Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vertical alignment in format expression #5043

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ac7cec8
add support for `top` alingment
stanislawpuda-tomtom Oct 7, 2024
c0b7b95
add support for "center" alignment
stanislawpuda-tomtom Oct 7, 2024
4b7e0ae
add comments
stanislawpuda-tomtom Oct 7, 2024
395a9db
render tests
zbigniewmatysek-tomtom Oct 15, 2024
9eecb22
handle vertical text
zbigniewmatysek-tomtom Oct 15, 2024
51ad9c2
cleanout
zbigniewmatysek-tomtom Oct 15, 2024
d1dd1ce
update top alignment
zbigniewmatysek-tomtom Oct 16, 2024
e4d36cd
cleanout
zbigniewmatysek-tomtom Oct 16, 2024
f381f8c
refactor shaping
zbigniewmatysek-tomtom Oct 18, 2024
04a46c4
Fix vertical alignment
zbigniewmatysek-tomtom Oct 21, 2024
f177852
fix bbox size
zbigniewmatysek-tomtom Oct 21, 2024
2f3cc78
adjust line spacing
zbigniewmatysek-tomtom Oct 22, 2024
e8f916d
vertical placement
zbigniewmatysek-tomtom Oct 22, 2024
7b174cf
cleanout
zbigniewmatysek-tomtom Oct 23, 2024
33f7d6f
handle text offset
zbigniewmatysek-tomtom Oct 23, 2024
70c4b94
minor fix
zbigniewmatysek-tomtom Oct 23, 2024
3fa48a9
const glyph height
zbigniewmatysek-tomtom Oct 29, 2024
a471167
align when no big image
stanislawpuda-tomtom Nov 3, 2024
dd30b1f
use section.scale when multiplying on image
stanislawpuda-tomtom Nov 4, 2024
e01a437
fix big image case
stanislawpuda-tomtom Nov 5, 2024
f14bd5d
fix vertical
stanislawpuda-tomtom Nov 5, 2024
5b04aed
simplify imageOffset calculation
stanislawpuda-tomtom Nov 8, 2024
5462948
code simplification
stanislawpuda-tomtom Nov 8, 2024
966c17d
improve readability
stanislawpuda-tomtom Nov 11, 2024
4863b92
cleaning - removing dead code
stanislawpuda-tomtom Nov 11, 2024
08ff664
fix only images case
stanislawpuda-tomtom Nov 11, 2024
e0030d9
cleaning + update render tests
stanislawpuda-tomtom Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 137 additions & 45 deletions src/symbol/shaping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import type {ImagePosition} from '../render/image_atlas';
import {IMAGE_PADDING} from '../render/image_atlas';
import type {Rect, GlyphPosition} from '../render/glyph_atlas';
import {Formatted, FormattedSection} from '@maplibre/maplibre-gl-style-spec';
import {Formatted, FormattedSection, VerticalAlign} from '@maplibre/maplibre-gl-style-spec';

Check failure on line 17 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Module '"@maplibre/maplibre-gl-style-spec"' has no exported member 'VerticalAlign'.

Check failure on line 17 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Module '"@maplibre/maplibre-gl-style-spec"' has no exported member 'VerticalAlign'.

enum WritingMode {
none = 0,
Expand Down Expand Up @@ -81,23 +81,28 @@
fontStack: string;
// Image options
imageName: string | null;
// Common options
verticalAlign: 'baseline' | 'top' | 'center';

constructor() {
this.scale = 1.0;
this.fontStack = '';
this.imageName = null;
this.verticalAlign = 'baseline';
}

static forText(scale: number | null, fontStack: string) {
static forText(scale: number | null, fontStack: string, verticalAlign: 'baseline' | 'top' | 'center' | null) {
const textOptions = new SectionOptions();
textOptions.scale = scale || 1;
textOptions.fontStack = fontStack;
textOptions.verticalAlign = verticalAlign || 'baseline';
return textOptions;
}

static forImage(imageName: string) {
static forImage(imageName: string, verticalAlign: 'baseline' | 'top' | 'center' | null) {
const imageOptions = new SectionOptions();
imageOptions.imageName = imageName;
imageOptions.verticalAlign = verticalAlign || 'baseline';
return imageOptions;
}

Expand Down Expand Up @@ -182,9 +187,25 @@
return this.sectionIndex.reduce((max, index) => Math.max(max, this.sections[index].scale), 0);
}

getMaxImageSize(imagePositions: {[_: string]: ImagePosition}) {
let maxImageWidth = 0;
let maxImageHeight = 0;
for (let i = 0; i < this.length(); i++) {
const section = this.getSection(i);
if (section.imageName) {
const imagePosition = imagePositions[section.imageName];
if (!imagePosition) continue;
const size = imagePosition.displaySize;
maxImageWidth = Math.max(maxImageWidth, size[0]);
maxImageHeight = Math.max(maxImageHeight, size[1]);
}
}
return {maxImageWidth, maxImageHeight};
}

addTextSection(section: FormattedSection, defaultFontStack: string) {
this.text += section.text;
this.sections.push(SectionOptions.forText(section.scale, section.fontStack || defaultFontStack));
this.sections.push(SectionOptions.forText(section.scale, section.fontStack || defaultFontStack, section.verticalAlign));

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Build tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Integration tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Unit tests and Coverage

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Build tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Integration tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Unit tests and Coverage

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 208 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.
const index = this.sections.length - 1;
for (let i = 0; i < section.text.length; ++i) {
this.sectionIndex.push(index);
Expand All @@ -205,7 +226,7 @@
}

this.text += String.fromCharCode(nextImageSectionCharCode);
this.sections.push(SectionOptions.forImage(imageName));
this.sections.push(SectionOptions.forImage(imageName, section.verticalAlign));

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Build tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Integration tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Unit tests and Coverage

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Build tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Integration tests (ubuntu-latest)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Unit tests and Coverage

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (ubuntu-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Code Hygiene

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 1)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 2)

Property 'verticalAlign' does not exist on type 'FormattedSection'.

Check failure on line 229 in src/symbol/shaping.ts

View workflow job for this annotation

GitHub Actions / Render tests (windows-latest, 0)

Property 'verticalAlign' does not exist on type 'FormattedSection'.
this.sectionIndex.push(this.sections.length - 1);
}

Expand Down Expand Up @@ -585,6 +606,57 @@
return {horizontalAlign, verticalAlign};
}

function calculateLineContentSize(
imagePositions: {[_: string]: ImagePosition},
line: TaggedString,
layoutTextSizeFactor: number
) {
const maxGlyphSize = line.getMaxScale() * ONE_EM;
const {maxImageWidth, maxImageHeight} = line.getMaxImageSize(imagePositions);

const lineContentHeight = Math.max(maxGlyphSize, maxImageHeight * layoutTextSizeFactor);
const lineContentWidth = Math.max(maxGlyphSize, maxImageWidth * layoutTextSizeFactor);

return {lineContentWidth, lineContentHeight};
}

function getVerticalAlignFactor(
verticalAlign: VerticalAlign
) {
if (verticalAlign === 'top') {
return 0;
} else if (verticalAlign === 'center') {
return 0.5;
} else {
return 1;
}
}

function getRectAndMetrics(
glyphPosition: GlyphPosition,
glyphMap: {
[_: string]: {
[_: number]: StyleGlyph;
};
},
section: SectionOptions, codePoint: number
) {
let rect: Rect = null;
let metrics: GlyphMetrics = null;

if (glyphPosition && glyphPosition.rect) {
rect = glyphPosition.rect;
metrics = glyphPosition.metrics;
} else {
const glyphs = glyphMap[section.fontStack];
const glyph = glyphs && glyphs[codePoint];
if (!glyph) return null;
metrics = glyph.metrics;
}

return {rect, metrics};
}

function shapeLines(shaping: Shaping,
glyphMap: {
[_: string]: {
Expand All @@ -607,38 +679,42 @@
layoutTextSizeThisZoom: number) {

let x = 0;
let y = SHAPING_DEFAULT_OFFSET;
let y = 0;

let maxLineLength = 0;
let maxLineHeight = 0;

const justify =
textJustify === 'right' ? 1 :
textJustify === 'left' ? 0 : 0.5;
const layoutTextSizeFactor = ONE_EM / layoutTextSizeThisZoom;

let lineIndex = 0;
for (const line of lines) {
line.trim();

const lineMaxScale = line.getMaxScale();
const maxLineOffset = (lineMaxScale - 1) * ONE_EM;
const positionedLine = {positionedGlyphs: [], lineOffset: 0};
shaping.positionedLines[lineIndex] = positionedLine;
const positionedGlyphs = positionedLine.positionedGlyphs;
let lineOffset = 0.0;
let imageOffset = 0.0;

if (!line.length()) {
y += lineHeight; // Still need a line feed after empty line
++lineIndex;
continue;
}

const {lineContentWidth, lineContentHeight} =
calculateLineContentSize(imagePositions, line, layoutTextSizeFactor);

for (let i = 0; i < line.length(); i++) {
const section = line.getSection(i);
const sectionIndex = line.getSectionIndex(i);
const codePoint = line.getCharCode(i);

let baselineOffset = 0.0;
let metrics = null;
let metrics: GlyphMetrics | null = null;
let rect = null;
let imageName = null;
let verticalAdvance = ONE_EM;
Expand All @@ -652,20 +728,20 @@
if (!section.imageName) {
const positions = glyphPositions[section.fontStack];
const glyphPosition = positions && positions[codePoint];
if (glyphPosition && glyphPosition.rect) {
rect = glyphPosition.rect;
metrics = glyphPosition.metrics;

const rectAndMetrics = getRectAndMetrics(glyphPosition, glyphMap, section, codePoint);

if (rectAndMetrics === null) continue;

rect = rectAndMetrics.rect;
metrics = rectAndMetrics.metrics;

if (vertical) {
baselineOffset = lineContentWidth - section.scale * ONE_EM;
} else {
const glyphs = glyphMap[section.fontStack];
const glyph = glyphs && glyphs[codePoint];
if (!glyph) continue;
metrics = glyph.metrics;
const verticalAlignFactor = getVerticalAlignFactor(section.verticalAlign);
baselineOffset = (lineContentHeight - section.scale * ONE_EM) * verticalAlignFactor;
}

// We don't know the baseline, but since we're laying out
// at 24 points, we can calculate how much it will move when
// we scale up or down.
baselineOffset = (lineMaxScale - section.scale) * ONE_EM;
} else {
const imagePosition = imagePositions[section.imageName];
if (!imagePosition) continue;
Expand All @@ -675,36 +751,49 @@
const size = imagePosition.displaySize;
// If needed, allow to set scale factor for an image using
// alias "image-scale" that could be alias for "font-scale"
// when FormattedSection is an image section.
section.scale = section.scale * ONE_EM / layoutTextSizeThisZoom;
// when FormattedSection is an image section.A
section.scale = section.scale * layoutTextSizeFactor;

metrics = {width: size[0],
height: size[1],
left: IMAGE_PADDING,
top: -GLYPH_PBF_BORDER,
advance: vertical ? size[1] : size[0]};

// Difference between one EM and an image size.
// Aligns bottom of an image to a baseline level.
const imageOffset = ONE_EM - size[1] * section.scale;
baselineOffset = maxLineOffset + imageOffset;
if (vertical) {
baselineOffset = lineContentWidth - size[1] * section.scale;
} else {
const verticalAlignFactor = getVerticalAlignFactor(section.verticalAlign);
baselineOffset = (lineContentHeight - size[1] * section.scale) * verticalAlignFactor;
}

verticalAdvance = metrics.advance;

// Difference between height of an image and one EM at max line scale.
// Pushes current line down if an image size is over 1 EM at max line scale.
const offset = vertical ? size[0] * section.scale - ONE_EM * lineMaxScale :
size[1] * section.scale - ONE_EM * lineMaxScale;
if (offset > 0 && offset > lineOffset) {
lineOffset = offset;
const offset = (vertical ? size[0] : size[1]) * section.scale - ONE_EM * lineMaxScale;
if (offset > 0 && offset > imageOffset) {
imageOffset = offset;
}
}

positionedGlyphs.push({
glyph: codePoint,
imageName,
x,
y: y + baselineOffset + SHAPING_DEFAULT_OFFSET,
vertical,
scale: section.scale,
fontStack: section.fontStack,
sectionIndex,
metrics,
rect
});

if (!vertical) {
positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + baselineOffset, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect});
x += metrics.advance * section.scale + spacing;
} else {
shaping.verticalizable = true;
positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + baselineOffset, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect});
x += verticalAdvance * section.scale + spacing;
}
}
Expand All @@ -713,24 +802,26 @@
if (positionedGlyphs.length !== 0) {
const lineLength = x - spacing;
maxLineLength = Math.max(lineLength, maxLineLength);
justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify, lineOffset);
justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify);
}

x = 0;
const currentLineHeight = lineHeight * lineMaxScale + lineOffset;
positionedLine.lineOffset = Math.max(lineOffset, maxLineOffset);
const maxLineOffset = (lineMaxScale - 1) * ONE_EM;
positionedLine.lineOffset = Math.max(imageOffset, maxLineOffset);
const currentLineHeight = lineHeight * lineMaxScale + imageOffset;
y += currentLineHeight;
maxLineHeight = Math.max(currentLineHeight, maxLineHeight);
++lineIndex;
}

// Calculate the bounding box and justify / align text block.
const height = y - SHAPING_DEFAULT_OFFSET;
const {horizontalAlign, verticalAlign} = getAnchorAlignment(textAnchor);
align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, maxLineHeight, lineHeight, height, lines.length);
align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, maxLineHeight, lineHeight, y, lines.length);

shaping.top += -verticalAlign * height;
shaping.bottom = shaping.top + height;
// Calculate the bounding box
// shaping.top & shaping.left already include text offset (text-radial-offset or text-offset)
shaping.top += -verticalAlign * y;
shaping.bottom = shaping.top + y;
shaping.left += -horizontalAlign * maxLineLength;
shaping.right = shaping.left + maxLineLength;
}
Expand All @@ -739,9 +830,8 @@
function justifyLine(positionedGlyphs: Array<PositionedGlyph>,
start: number,
end: number,
justify: 1 | 0 | 0.5,
lineOffset: number) {
if (!justify && !lineOffset)
justify: 1 | 0 | 0.5) {
if (!justify)
return;

const lastPositionedGlyph = positionedGlyphs[end];
Expand All @@ -750,10 +840,12 @@

for (let j = start; j <= end; j++) {
positionedGlyphs[j].x -= lineIndent;
positionedGlyphs[j].y += lineOffset;
}
}

/**
* Aligns the lines based on horizontal and vertical alignment.
*/
function align(positionedLines: Array<PositionedLine>,
justify: number,
horizontalAlign: number,
Expand All @@ -769,7 +861,7 @@
if (maxLineHeight !== lineHeight) {
shiftY = -blockHeight * verticalAlign - SHAPING_DEFAULT_OFFSET;
} else {
shiftY = (-verticalAlign * lineCount + 0.5) * lineHeight;
shiftY = -verticalAlign * lineCount * lineHeight + 0.5 * lineHeight;
}

for (const line of positionedLines) {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading