From ac7cec8746fcd46478a6db4ee48d01562a3fc4e2 Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 7 Oct 2024 11:13:58 +0200 Subject: [PATCH 01/27] add support for `top` alingment --- src/symbol/shaping.ts | 33 +++++++++++++------ .../symbol-shaping/shaping.test.ts | 4 +-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 6348fbc69f..2048902176 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -81,23 +81,28 @@ class SectionOptions { 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; } @@ -184,7 +189,7 @@ class TaggedString { 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)); const index = this.sections.length - 1; for (let i = 0; i < section.text.length; ++i) { this.sectionIndex.push(index); @@ -205,7 +210,7 @@ class TaggedString { } this.text += String.fromCharCode(nextImageSectionCharCode); - this.sections.push(SectionOptions.forImage(imageName)); + this.sections.push(SectionOptions.forImage(imageName, section.verticalAlign)); this.sectionIndex.push(this.sections.length - 1); } @@ -637,7 +642,7 @@ function shapeLines(shaping: Shaping, const section = line.getSection(i); const sectionIndex = line.getSectionIndex(i); const codePoint = line.getCharCode(i); - let baselineOffset = 0.0; + let verticalAlignOffset = 0.0; let metrics = null; let rect = null; let imageName = null; @@ -665,7 +670,11 @@ function shapeLines(shaping: Shaping, // 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; + if (section.verticalAlign === 'top') { + verticalAlignOffset = -(lineMaxScale - section.scale) * metrics.top + metrics.top; + } else { + verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; + } } else { const imagePosition = imagePositions[section.imageName]; if (!imagePosition) continue; @@ -686,8 +695,12 @@ function shapeLines(shaping: Shaping, // 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 (section.verticalAlign === 'top') { + verticalAlignOffset = 0; + } else { + const imageOffset = ONE_EM - size[1] * section.scale; + verticalAlignOffset = maxLineOffset + imageOffset; + } verticalAdvance = metrics.advance; // Difference between height of an image and one EM at max line scale. @@ -700,11 +713,11 @@ function shapeLines(shaping: Shaping, } if (!vertical) { - positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + baselineOffset, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); + positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + verticalAlignOffset, 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}); + positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + verticalAlignOffset, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); x += verticalAdvance * section.scale + spacing; } } diff --git a/test/integration/symbol-shaping/shaping.test.ts b/test/integration/symbol-shaping/shaping.test.ts index fca54cd0fd..6130cc009a 100644 --- a/test/integration/symbol-shaping/shaping.test.ts +++ b/test/integration/symbol-shaping/shaping.test.ts @@ -22,11 +22,11 @@ if (typeof process !== 'undefined' && process.env !== undefined) { } function sectionForImage(name: string) { - return new FormattedSection('', ResolvedImage.fromString(name), null, null, null); + return new FormattedSection('', ResolvedImage.fromString(name), null, null, null, null); } function sectionForText(name: string, scale?: number) { - return new FormattedSection(name, null, scale, null, null); + return new FormattedSection(name, null, scale, null, null, null); } describe('shaping', () => { From c0b7b95cb4dcac7814f87125e395770235c0627e Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 7 Oct 2024 13:10:19 +0200 Subject: [PATCH 02/27] add support for "center" alignment --- src/symbol/shaping.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 2048902176..735d57e8c4 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -671,7 +671,9 @@ function shapeLines(shaping: Shaping, // at 24 points, we can calculate how much it will move when // we scale up or down. if (section.verticalAlign === 'top') { - verticalAlignOffset = -(lineMaxScale - section.scale) * metrics.top + metrics.top; + verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM / 3) - (ONE_EM / 3); + } else if (section.verticalAlign === 'center') { + verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM * 2 / 3) - (ONE_EM / 6); } else { verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; } @@ -697,6 +699,9 @@ function shapeLines(shaping: Shaping, // Aligns bottom of an image to a baseline level. if (section.verticalAlign === 'top') { verticalAlignOffset = 0; + } else if (section.verticalAlign === 'center') { + const imageOffset = ONE_EM - size[1] * section.scale; + verticalAlignOffset = (maxLineOffset + imageOffset) / 2; } else { const imageOffset = ONE_EM - size[1] * section.scale; verticalAlignOffset = maxLineOffset + imageOffset; From 4b7e0aec0e86f55c3f5a16561a40022a9cfbe5da Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 7 Oct 2024 16:01:12 +0200 Subject: [PATCH 03/27] add comments --- src/symbol/shaping.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 735d57e8c4..79fa560715 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -667,14 +667,17 @@ function shapeLines(shaping: Shaping, metrics = glyph.metrics; } - // 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. if (section.verticalAlign === 'top') { + // We arbitrarily set the distance between the top of the glyph set + // and top of uppercase letters to be 1/3 em. verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM / 3) - (ONE_EM / 3); } else if (section.verticalAlign === 'center') { + // We calculate center as the middle between top and baseline alignment. verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM * 2 / 3) - (ONE_EM / 6); } else { + // 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. verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; } } else { @@ -695,14 +698,16 @@ function shapeLines(shaping: Shaping, 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. if (section.verticalAlign === 'top') { + // Aligns top of an image to top of a line. verticalAlignOffset = 0; } else if (section.verticalAlign === 'center') { + // We calculate center as the middle between top and baseline alignment. const imageOffset = ONE_EM - size[1] * section.scale; verticalAlignOffset = (maxLineOffset + imageOffset) / 2; } else { + // 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; verticalAlignOffset = maxLineOffset + imageOffset; } From 395a9db7adb974c9aac96833577c66a1c759a6a5 Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Tue, 15 Oct 2024 13:39:07 +0200 Subject: [PATCH 04/27] render tests --- .../assets/sprites/vertical-align.json | 9 + .../assets/sprites/vertical-align.png | Bin 0 -> 5940 bytes .../assets/sprites/vertical-align@2x.json | 9 + .../assets/sprites/vertical-align@2x.png | Bin 0 -> 5940 bytes .../expected.png | Bin 0 -> 22240 bytes .../formatted-vertical-align-line/style.json | 452 ++++++++++++++++++ .../formatted-vertical-align/expected.png | Bin 0 -> 24516 bytes .../formatted-vertical-align/style.json | 122 +++++ 8 files changed, 592 insertions(+) create mode 100644 test/integration/assets/sprites/vertical-align.json create mode 100644 test/integration/assets/sprites/vertical-align.png create mode 100644 test/integration/assets/sprites/vertical-align@2x.json create mode 100644 test/integration/assets/sprites/vertical-align@2x.png create mode 100644 test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/expected.png create mode 100644 test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/style.json create mode 100644 test/integration/render/tests/text-field/formatted/formatted-vertical-align/expected.png create mode 100644 test/integration/render/tests/text-field/formatted/formatted-vertical-align/style.json diff --git a/test/integration/assets/sprites/vertical-align.json b/test/integration/assets/sprites/vertical-align.json new file mode 100644 index 0000000000..bf0cfcedb4 --- /dev/null +++ b/test/integration/assets/sprites/vertical-align.json @@ -0,0 +1,9 @@ +{ + "image": { + "width": 100, + "height": 100, + "x": 0, + "y": 0, + "pixelRatio": 1 + } +} \ No newline at end of file diff --git a/test/integration/assets/sprites/vertical-align.png b/test/integration/assets/sprites/vertical-align.png new file mode 100644 index 0000000000000000000000000000000000000000..7ce74186787f59efd1e0bebdbe25c633495e0ae2 GIT binary patch literal 5940 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 literal 0 HcmV?d00001 diff --git a/test/integration/assets/sprites/vertical-align@2x.json b/test/integration/assets/sprites/vertical-align@2x.json new file mode 100644 index 0000000000..bdb68a7818 --- /dev/null +++ b/test/integration/assets/sprites/vertical-align@2x.json @@ -0,0 +1,9 @@ +{ + "image": { + "width": 20, + "height": 20, + "x": 40, + "y": 40, + "pixelRatio": 1 + } +} \ No newline at end of file diff --git a/test/integration/assets/sprites/vertical-align@2x.png b/test/integration/assets/sprites/vertical-align@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7ce74186787f59efd1e0bebdbe25c633495e0ae2 GIT binary patch literal 5940 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 literal 0 HcmV?d00001 diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/expected.png b/test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..09097d073c3c097f2bc6a8b3624f7344813c9151 GIT binary patch literal 22240 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 H-HZPKSDq~) literal 0 HcmV?d00001 diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/style.json b/test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/style.json new file mode 100644 index 0000000000..cfc2f6319f --- /dev/null +++ b/test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/style.json @@ -0,0 +1,452 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 512, + "width": 512 + } + }, + "center": [ 0, 0 ], + "zoom": 1, + "sources": { + "line-top": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -63, + 41 + ], + [ + -57, + 44 + ], + [ + -51, + 45.8 + ], + [ + -45, + 47 + ], + [ + -39, + 48.2 + ], + [ + -33, + 49.1 + ], + [ + -27, + 49.7 + ], + [ + -21, + 50 + ], + [ + -15, + 50.3 + ], + [ + -9, + 50.9 + ], + [ + -3, + 51.8 + ], + [ + 3, + 53 + ], + [ + 9, + 54.2 + ], + [ + 15, + 56 + ], + [ + 21, + 57 + ], + [ + 27, + 58 + ], + [ + 33, + 58 + ], + [ + 39, + 59 + ], + [ + 45, + 59 + ], + [ + 51, + 58 + ], + [ + 57, + 57 + ], + [ + 63, + 55 + ] + ] + }, + "properties": {} + } + ] + } + }, + "line-center": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -63, + -9 + ], + [ + -57, + -6 + ], + [ + -51, + -4.2 + ], + [ + -45, + -3 + ], + [ + -39, + -1.8 + ], + [ + -33, + -0.9 + ], + [ + -27, + -0.3 + ], + [ + -21, + 0 + ], + [ + -15, + 0.3 + ], + [ + -9, + 0.9 + ], + [ + -3, + 1.8 + ], + [ + 3, + 3 + ], + [ + 9, + 4.2 + ], + [ + 15, + 6 + ], + [ + 21, + 7 + ], + [ + 27, + 8 + ], + [ + 33, + 8 + ], + [ + 39, + 9 + ], + [ + 45, + 9 + ], + [ + 51, + 8 + ], + [ + 57, + 7 + ], + [ + 63, + 5 + ] + ] + }, + "properties": {} + } + ] + } + }, + "line-baseline": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -63, + -59 + ], + [ + -57, + -56 + ], + [ + -51, + -54.2 + ], + [ + -45, + -53 + ], + [ + -39, + -51.8 + ], + [ + -33, + -50.9 + ], + [ + -27, + -50.3 + ], + [ + -21, + -50 + ], + [ + -15, + -49.7 + ], + [ + -9, + -49.1 + ], + [ + -3, + -48.2 + ], + [ + 3, + -47 + ], + [ + 9, + -45.8 + ], + [ + 15, + -44 + ], + [ + 21, + -43 + ], + [ + 27, + -42 + ], + [ + 33, + -42 + ], + [ + 39, + -41 + ], + [ + 45, + -41 + ], + [ + 51, + -42 + ], + [ + 57, + -43 + ], + [ + 63, + -45 + ] + ] + }, + "properties": {} + } + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sprite": "local://sprites/emerald", + "layers": [ + { + "id": "line-top", + "type": "line", + "source": "line-top", + "layout": {}, + "paint": { + "line-color": "#000000", + "line-width": 2 + } + }, + { + "id": "line-center", + "type": "line", + "source": "line-center", + "layout": {}, + "paint": { + "line-color": "#000000", + "line-width": 2 + } + }, + { + "id": "line-baseline", + "type": "line", + "source": "line-baseline", + "layout": {}, + "paint": { + "line-color": "#000000", + "line-width": 2 + } + }, + { + "id": "line-label-top", + "type": "symbol", + "source": "line-top", + "layout": { + "text-field": [ + "format", + ["image", "government_icon"], + { "vertical-align": "top" }, + " ", + {}, + "Ag", + { "font-scale": 1.2, "vertical-align": "top" }, + " ", + {}, + "Top", + { "font-scale": 0.8, "vertical-align": "top" } + ], + "text-size": 48, + "symbol-placement": "line-center", + "symbol-spacing": 100, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "#000000" + } + }, + { + "id": "line-label-center", + "type": "symbol", + "source": "line-center", + "layout": { + "text-field": [ + "format", + ["image", "government_icon"], + { "vertical-align": "center" }, + " ", + {}, + "Ag", + { "font-scale": 1.2, "vertical-align": "center" }, + " ", + {}, + "Center", + { "font-scale": 0.8, "vertical-align": "center" } + ], + "text-size": 48, + "symbol-placement": "line-center", + "symbol-spacing": 100, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "#000000" + } + }, + { + "id": "line-label-baseline", + "type": "symbol", + "source": "line-baseline", + "layout": { + "text-field": [ + "format", + ["image", "government_icon"], + { "vertical-align": "baseline" }, + " ", + {}, + "Ag", + { "font-scale": 1.2, "vertical-align": "baseline" }, + " ", + {}, + "Baseline", + { "font-scale": 0.8, "vertical-align": "baseline" } + ], + "text-size": 48, + "symbol-placement": "line-center", + "symbol-spacing": 100, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "#000000" + } + } + ] +} \ No newline at end of file diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align/expected.png b/test/integration/render/tests/text-field/formatted/formatted-vertical-align/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..46bd448b4a855bf40a7792b48421c47ef6f3d79b GIT binary patch literal 24516 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 Uftnd2cK#o(JGnVF{SuP-pAOO4@&Et; literal 0 HcmV?d00001 diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align/style.json b/test/integration/render/tests/text-field/formatted/formatted-vertical-align/style.json new file mode 100644 index 0000000000..c7c54903b2 --- /dev/null +++ b/test/integration/render/tests/text-field/formatted/formatted-vertical-align/style.json @@ -0,0 +1,122 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 512, + "width": 512 + } + }, + "center": [ 0, 0 ], + "zoom": 0, + "sources": { + "point": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + }, + "properties": { + "label": "abc" + } + } + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sprite": "local://sprites/emerald", + "layers": [ + { + "id": "point-label-top", + "type": "symbol", + "source": "point", + "layout": { + "text-field": [ + "format", + ["image", "government_icon"], + { "vertical-align": "top" }, + " ", + {}, + "ÓÑX yg", + { "font-scale": 1.2, "vertical-align": "top" }, + " ", + {}, + "TOP", + { "font-scale": 0.8, "vertical-align": "top" } + ], + "text-size": 48, + "text-offset": [0, -2], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "#000000" + } + }, + { + "id": "point-label-center", + "type": "symbol", + "source": "point", + "layout": { + "text-field": [ + "format", + ["image", "government_icon"], + { "vertical-align": "center" }, + " ", + {}, + "ÓÑX yg", + { "font-scale": 1.2, "vertical-align": "center" }, + " ", + {}, + "CENTER", + { "font-scale": 0.8, "vertical-align": "center" } + ], + "text-size": 48, + "text-offset": [0, 0], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "#000000" + } + }, + { + "id": "point-label-baseline", + "type": "symbol", + "source": "point", + "layout": { + "text-field": [ + "format", + ["image", "government_icon"], + { "vertical-align": "baseline" }, + " ", + {}, + "ÓÑX yg", + { "font-scale": 1.2, "vertical-align": "baseline" }, + " ", + {}, + "BASELINE", + { "font-scale": 0.8, "vertical-align": "baseline" } + ], + "text-size": 48, + "text-offset": [0, 2], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "#000000" + } + } + ] +} \ No newline at end of file From 9eecb2296de41ff233553747f45f1f45fc830a50 Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Tue, 15 Oct 2024 16:06:12 +0200 Subject: [PATCH 05/27] handle vertical text --- src/symbol/shaping.ts | 54 ++++++++++-------- .../expected.png | Bin 0 -> 6889 bytes .../style.json | 45 +++++++++++++++ 3 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/expected.png create mode 100644 test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/style.json diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 79fa560715..4a17f9a526 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -667,18 +667,21 @@ function shapeLines(shaping: Shaping, metrics = glyph.metrics; } - if (section.verticalAlign === 'top') { - // We arbitrarily set the distance between the top of the glyph set - // and top of uppercase letters to be 1/3 em. - verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM / 3) - (ONE_EM / 3); - } else if (section.verticalAlign === 'center') { - // We calculate center as the middle between top and baseline alignment. - verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM * 2 / 3) - (ONE_EM / 6); - } else { - // 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. - verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; + // 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. + verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; + + // Do not offset vertical alignment for vertical text. + if (writingMode !== WritingMode.vertical) { + if (section.verticalAlign === 'top') { + // Arbitrarily set the distance between the top of the glyph set + // and top of uppercase letters to be 1/3 em. + verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM / 3) - (ONE_EM / 3); + } else if (section.verticalAlign === 'center') { + // Calculate center as the middle between top and baseline alignment. + verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM * 2 / 3) - (ONE_EM / 6); + } } } else { const imagePosition = imagePositions[section.imageName]; @@ -698,19 +701,22 @@ function shapeLines(shaping: Shaping, top: -GLYPH_PBF_BORDER, advance: vertical ? size[1] : size[0]}; - if (section.verticalAlign === 'top') { - // Aligns top of an image to top of a line. - verticalAlignOffset = 0; - } else if (section.verticalAlign === 'center') { - // We calculate center as the middle between top and baseline alignment. - const imageOffset = ONE_EM - size[1] * section.scale; - verticalAlignOffset = (maxLineOffset + imageOffset) / 2; - } else { - // 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; - verticalAlignOffset = maxLineOffset + imageOffset; + // 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; + verticalAlignOffset = maxLineOffset + imageOffset; + + // Do not offset vertical alignment for vertical text. + if (writingMode !== WritingMode.vertical) { + if (section.verticalAlign === 'top') { + // Aligns top of an image to top of a line. + verticalAlignOffset = 0; + } else if (section.verticalAlign === 'center') { + // We calculate center as the middle between top and baseline alignment. + verticalAlignOffset = (maxLineOffset + imageOffset) / 2; + } } + verticalAdvance = metrics.advance; // Difference between height of an image and one EM at max line scale. diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/expected.png b/test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..3355890fe0ffa6bd95de1833c1a06b178bd4f5c2 GIT binary patch literal 6889 zcmeHMi8s{W`yVryu`99{GBU)FC5n)JXvmO#OHo7iBoU*Kr7UBKu@qOc)&v90URd zU!f2LE%?~H+xrs&;VH&wTr|E*wel{|Jso~^@Y~wPbRUaeMXYUW#mvWuYZ#Md1#e7R zsDwUW9IiUnV}(CR<%4yR#4NhCBrBw`V%5{tOIy3Ae3aOn~ju{q*hRu}HZYWcIFM@!0lGfU*t|iTU62-*^I>i6@bA zqyRhCupsloisM|=uNstyo~PAtSv%D0tm{hd@p<>_KO3g%*vZ^48mc0!-?RiT zQ`76Tm9t`q@rr^(q^OTQQtmlokcH8`JcR(kRB;OB9?@*rB^))ij6_O=$M%LDoe;E3 z%B$n2a1lKvwQxeOpf7@itX%kG1Vy*ikh2&9Qi3iPiK$`(YZwQe%WUJ#QKi#~jd!LZ z@^lJFK~kx0CY<~T5)EYyqW^+bj)=fKA@g%l+uJ4Pxxi_I#H6CLMpE?9tQg;;0vJ6t zBnGz{4A!_}$NciUmgr?D4moQ<$kviUFhWFvINy9dVaKp8?oR(N)t(^1K`(-Bb0y6> z4F_G!r0)flv#6#bxPC!GezU~G^gVR2AN6ei^p|Nj^ ziW>w&1D8$>ru~g25B69R>{YEHeLR63Q^g^W`-Kq-Yrss<6js0op-K#?YJeuV0BRj4 zofrCP|5y)nxEaI7jYLETB@E?(pn>0_SLt2z~ zhvMKYC-T3aXHlluQDS!ke$)#@1V~0aKRc!&S74)y3EYj||CO;n{1DD!;>$MQl`+<) zRxU(JQ7jLb|HO@yi-%zH#;Uwp1~mIB0*{C8>9T8L#W8W4A^D{J*5>xT#r^_IJ#pXl zckrfh$~v4sqLGqOriK$UVymnu#*s`^Hu@&rMts)lw#ni>0&9_&Ji~g`82Nkt<&k(j1J}$MMJ)o8Em%s_xoh@ z*dKTL>bNj@7Dg3wK8*_XPlWrN61r!&EzY_jom`)vig>;h^fvQJ-X;E@95?t6_+uQz zPp2ujhimUYUiAxzD*UyUNfwO?ED^QYjjYwTsK2x`i?{IeLo~&p!hBxv4%|OV@kaL5 zAuxIUy}jWn(=XSDq!?j|wVN6H#Il2xA_X7Hu(4#q&C##wW~gFZIc{>ch;M4P$UlwW zVSkXW6zR}eVeoqzko8f}2xsJKw`lJ3Do;yC37|Nh$B19;$V zT8y`ZR`;tucDX=>i03iFMFHFA&`R4U<;-&$H;u-p_Qv-lj{9vFyKXZJOnl#D>@iU8 zoZ2zpM;H08@OA{Op{&@JS23r!j1+l~>=&vI_aJmmkyDu*ZP2mV+J9KC-S zZJk$uKPEXoqu#s2S*Wia#AZ{;%jad9%W=vw%~N@tFT$5@FEv3?n>U}0^*gt>lj_>x2m&^ ze61r&tE?fk>eDKGvu`?P;5^RJD0MyO zwS_~y)ug>|EW=Z@*R$6jt?;q3?K*i^UU6sliS>zRonnMOmqIcM(5pWeuyb){Te3_s zdrMCCmcYKQWJl$@yl|g}EV=S!k}V2wB!x~E2j0K#e>qxsbGTnm7@Mr*6Z`a2*BRe{ zC{s?fjHv~(z+`8aJw(viGG*bWGufxfqQcco&p?~kW%!;sho<4<>}n1n{1x3E+3@Em z$JVFy+b|miuXJ7F_vu8Fybg4HvNg)U<|>AWv7J+B`Cvy=Gp>W*XD z23?mixWWWr(U`oE@6P=@gihYcr|AtpmYamBB|7~5?VotVsR**dl!bGIP$CWYA(B`z zc{sU``tF+AmNEktEhI-1E_IwWL+ooY&5IO1)7ur5o(0~8E)M3bv|WO^g&{f?3Ei@O zQKzf>EB+3UPW@+K^ShVTmvUF80Si;V)9nx9=VOcq)BrZ{3LdiU(oW}xE#LH?AE>w- z=fExeiC^>2Ixb&t5BSTqe=zI*YHX*ctvJw@$mEQ75xX2`l9x3)>c{ctB^G_i3ysHW z3YTUqhWg5a9L#z6F5*VPMx8?XCc3JoKCCh~N==AJFv9M*ik9Z{Y-Ge5gUniBaWH4F z-^A7@?i((=B7wcNWYJ~tmC1Su?~J}2M_!~1)Neg0I+?o)JS%5Dp_CM}&RzJ%d-zm9 zw`<*1nfB5cgK@vLI#J?3HeuOU3gSEWTV%0pi6h0|Tt)_sW<(t36Hg9T_Z!8L@j17B zf0pSuAplFtu_>;kSL8lP_vX=>dw4O8y*F~4_N!x62@X_4fs3nS8}vjTHSofs(z`pA zdH5ek_4>=tmIbzW@4Z>!uZ}7&!1iY2&)Zt-1oC2-gw(oUZSMwB);L+JB@V9ui2hSOavTo{H(ny(Tkad zt8co972_;0^`4H7t7E)wwI0kErqimp(R(0mPLJ=c7yWWd49R%>{N=-AVwkqU(`Bit z^&eZkICF>ktD;=2mlnn;XX!oO>*7iJ4s`s#npE~X<^gidG;!(-F~-~a8Oozo2dhn%tT44|a@5W;DLqP2GOv*oz{mQVAG&6pY~+rW@% zKfj~opc>y}y`j^V0KqUVPF2Y$mWkKM3;1bsP_Nlx63OF)g~j&SnT?d6KlKGfD?vGv zEkHN@MsBqgaR=7f%Ra~!lNM3>lIeH#@~k8ELQP(7&brw%*70|iFO7*!k+W_0n^#w} zblTFu0@oZJ=g5gklcoE6V$;1730TvdPn4a6!sqUF( z;>yw4R&+7Ftd5`3NBc_2i%W*=-dO!h?sqAy7~#pz_aRA&%*!t-i=t(*FWR4Stcl(6 z0X%mFWg!A95z_J;^$#gEY2tHS6EY##0o&OrD<@wjo{QwW=b6+RP6vja%zHLbL{DK2 z+-OP)sk-WN*c$4oF5d}dP#~3dN2S$pja0=Yyuv3mH9bN-ZPzfoJwMXX;fkEq3d^qM zEdRh#e0`b11@`izf`#deitPI(;e=qe7VX^dsbwlK3#jeWBejo&vs$7Id%pI6m`gwL z9A&S5gOgX@jXc*syzQ|+B8w+Ud(ScEgwRAq^IaS0tZ7B8QYi;#TZP5;A|k}ilQLeM zGPk;Jc>wvPuAcw;#+r@O2Q8bKUW$So!v=#@2^FU5h*0jNvDmTD42rZ&PtV?R{r&vS zl@}RvLu*P8v;7&sdmPQW`^P@%ifC*5*2QII<@ffFeKH~x1@w{bnwbI_%3|cckAO3qOKZNyChDe zo#W zpYVotBMZd+mk)pDzj4>b6@n6(OGZXUzWhC-wqfrT^wV=5{_)d7EoMo!ndE}HC-0se zzs1j&nUfQ8h!r|`MDx^N&^yd64_Qk%lTJK&zMv0?K{iN`lo+#JUR93B9s%f!nIn^3 zqb#O(Wghqum}=+zRk!YvsH5{GINl!Keqwt+LT%XA)u|G653dO^y_bKZwHJ3cAE0SM z!dR?zve|RC-ri^15L|!=*`a4-WW0>@I^5Yct!HuJCDYd)pHTeJxThrNva$lgaPh!S zMWUbp2(q=l!ew!ej6dEXWNvh=9^&-}AkQh0QwmD{VcEoW$0@ars6v|V<~ygkwi){Pc%NteBoTj%zJ7uT%M1=2W}rn zL0am>Vn?k|?|tI+gqd0RpOZ|?@hzXM8COSIb^BhoO-`!Ew>vyXReQNQI?5A0g#c|L zEvDgS(s%qHgT34veiXXE&olJ{tQ0<-)vMvL1p%|PaHH*ru_oe|Yb`JFF3#7y3|I`= zOP-ZQK1q=`@>*KiRS0wiDxG}ZE3~^2+M*p*vNSh(oq8L>uZBav*KwlOOcd|vGKv#N zmlgyP_MZuwd@b{ll)EM*>FMO3N($MbDI6qZj{v&3izU!E8TcnBFX994j4PY`-0Csd zSoTT3h^q(JQEC}+ytCVl9Dx7YvDPn!CQi<7(-8m#0A}8j0=q}`XzwiBw<|fLU;M^>*tc{(zln{@sP3xw*OeD5m3=9!G=11Q=PRra25X z51Aj5h%PHeaom@)`ICOP?EP1DSrpOVQWIKiRygvMym;HqmVb9mS=B0R#}LGQzlP=W zf8xF^Bx(u;sW>?~ImN<0Gz;~Q*wgk@1?9GHvDd^qBro>>#!q}^2HgDI-3?IQGaC$R zw*TgfoCUZImG;_NE=-ieMr#?~7I72A_Pl5VdMf!_PgeoAbi9m=)Niypi7J@@G_7-pCCsebS9#i& z)a(Me6;Z`CB_$_U(6_DJaKGnhf0mZ+?DYVoQs0(F0L#I0j2n!(_9lVI;#C!-FVcD z^d?LGQf6~T3L|{g+{jA?Bm;3hF}g?Te2$*>55TZRzwCtwkZnL2cgS}%`;;QcP>&w5 z7-IACUtgO?)B3Dl&vCMtU0)Y$o0T?XA3Y~8Q^pIl7tltt;2TVwTTxjH?4@o+U44^< z>DxV!72ba{bb7Af2U;{hp;sNK*RHlMlw9k5T~S_A_2LmKV({}&^M}rq+^Qd2_fu8m zu_W@Pv~%kCt3g1x2E8|2rGetG2#Ruotoz`k9>?5#E{211s9#0(;4|y#m7$uaq>@<9 zb8^c1osD}?(_5-IS3nnq1l^EHk@}8~O<9#1H~!Q2cNbsyZYg#Nh>inIc)*?by1cTi z8{pq&ZDs*=y1cy7qZy#!cSei3A1(}2yi?qrSWwsd_{n3bv(jqVu6`R69=@*^v8r1N zf9R~I*D7??Z|@yQ*Xb8LgR_a3dkmLn!X*QOTEBTXX=&SJSFYVlYz|3Uc?j#x#;hZN znHp|%cczKu?cTTO`US75>q0FZ~w6vB!21e*lpGudfmc zl`-T+BcP|-oWJ$d2XHI9DmOPJtDmy}c;bW|tmqtn%!PE2=A0v&*M$CUGyVU@<{~LF zrZn6M(Ml&G|x__o>$i6aBJ03F_BXkXNo?uG2LD*<` z(tuUvWresj&}PykQK1DyeGaGjPH@|?--K>KRcNeeqoDHyrUv~?_)XY7!U+LdeX62A z(`w=x#vzhazZ%dsUbGY{DL8u&R+Y2(_#m|vtv=*%l0CAo#&_b}1hSZSkm?pS8mdh| zP)@iXK|x`vic-vb5R~BWmgWPG3G+-EE-I+qiMu>^X%%QR8is>-gUUe@5+k6FTRlt# zG7a(sH<(CJk7`Js3(Xd^u7Ph|XUTTk!L4;rjOxv}1`O4tE{0&g&%C?dE)9Y7!LakiE*Ni|}WnNV|i)$tjR)xJjkLRC|1o;T8-! z0dIIp5DA)A{nNWdMKqx8R6f&*LnI;5Fas({A&e<-g#B6rogH%$Gzt>Pv?n1IjVxdl z$~Cm2W~Sm^r*~&hqLl`Hzb5Cy_TT@W|K=0;skkRul#gvZe$@{T{=$M_H1#zK)$AVp EAJigPg#Z8m literal 0 HcmV?d00001 diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/style.json b/test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/style.json new file mode 100644 index 0000000000..af4e8491b7 --- /dev/null +++ b/test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/style.json @@ -0,0 +1,45 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 512, + "width": 512 + } + }, + "center": [ 0, 0 ], + "zoom": 0, + "sources": { + "point": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sprite": "local://sprites/emerald", + "layers": [ + { + "id": "vertical", + "type": "symbol", + "source": "point", + "layout": { + "text-writing-mode": ["vertical"], + "text-field": ["format", "H", { "vertical-align": "top" }, "H", { "vertical-align": "center" }, "H", ["image", "interstate_1"], { "vertical-align": "center" }, ["image", "government_icon"], { "vertical-align": "top" }, ["image", "government_icon"], { "vertical-align": "center" }, ["image", "government_icon"], "ッ",{"font-scale": 1.8}], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + } + ] +} \ No newline at end of file From 51ad9c261b477362fdcea0650a8f8bce9b2b8c95 Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Tue, 15 Oct 2024 16:14:58 +0200 Subject: [PATCH 06/27] cleanout --- .../assets/sprites/vertical-align.json | 9 --------- .../assets/sprites/vertical-align.png | Bin 5940 -> 0 bytes .../assets/sprites/vertical-align@2x.json | 9 --------- .../assets/sprites/vertical-align@2x.png | Bin 5940 -> 0 bytes .../formatted-vertical-align-line/expected.png | Bin .../formatted-vertical-align-line/style.json | 0 .../expected.png | Bin .../style.json | 0 .../formatted-vertical-align/expected.png | Bin .../formatted-vertical-align/style.json | 3 --- 10 files changed, 21 deletions(-) delete mode 100644 test/integration/assets/sprites/vertical-align.json delete mode 100644 test/integration/assets/sprites/vertical-align.png delete mode 100644 test/integration/assets/sprites/vertical-align@2x.json delete mode 100644 test/integration/assets/sprites/vertical-align@2x.png rename test/integration/render/tests/text-field/{formatted => }/formatted-vertical-align-line/expected.png (100%) rename test/integration/render/tests/text-field/{formatted => }/formatted-vertical-align-line/style.json (100%) rename test/integration/render/tests/text-field/{formatted => }/formatted-vertical-align-vertical-text/expected.png (100%) rename test/integration/render/tests/text-field/{formatted => }/formatted-vertical-align-vertical-text/style.json (100%) rename test/integration/render/tests/text-field/{formatted => }/formatted-vertical-align/expected.png (100%) rename test/integration/render/tests/text-field/{formatted => }/formatted-vertical-align/style.json (97%) diff --git a/test/integration/assets/sprites/vertical-align.json b/test/integration/assets/sprites/vertical-align.json deleted file mode 100644 index bf0cfcedb4..0000000000 --- a/test/integration/assets/sprites/vertical-align.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "image": { - "width": 100, - "height": 100, - "x": 0, - "y": 0, - "pixelRatio": 1 - } -} \ No newline at end of file diff --git a/test/integration/assets/sprites/vertical-align.png b/test/integration/assets/sprites/vertical-align.png deleted file mode 100644 index 7ce74186787f59efd1e0bebdbe25c633495e0ae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5940 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 diff --git a/test/integration/assets/sprites/vertical-align@2x.json b/test/integration/assets/sprites/vertical-align@2x.json deleted file mode 100644 index bdb68a7818..0000000000 --- a/test/integration/assets/sprites/vertical-align@2x.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "image": { - "width": 20, - "height": 20, - "x": 40, - "y": 40, - "pixelRatio": 1 - } -} \ No newline at end of file diff --git a/test/integration/assets/sprites/vertical-align@2x.png b/test/integration/assets/sprites/vertical-align@2x.png deleted file mode 100644 index 7ce74186787f59efd1e0bebdbe25c633495e0ae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5940 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 diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/expected.png b/test/integration/render/tests/text-field/formatted-vertical-align-line/expected.png similarity index 100% rename from test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/expected.png rename to test/integration/render/tests/text-field/formatted-vertical-align-line/expected.png diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/style.json b/test/integration/render/tests/text-field/formatted-vertical-align-line/style.json similarity index 100% rename from test/integration/render/tests/text-field/formatted/formatted-vertical-align-line/style.json rename to test/integration/render/tests/text-field/formatted-vertical-align-line/style.json diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/expected.png b/test/integration/render/tests/text-field/formatted-vertical-align-vertical-text/expected.png similarity index 100% rename from test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/expected.png rename to test/integration/render/tests/text-field/formatted-vertical-align-vertical-text/expected.png diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/style.json b/test/integration/render/tests/text-field/formatted-vertical-align-vertical-text/style.json similarity index 100% rename from test/integration/render/tests/text-field/formatted/formatted-vertical-align-vertical-text/style.json rename to test/integration/render/tests/text-field/formatted-vertical-align-vertical-text/style.json diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align/expected.png b/test/integration/render/tests/text-field/formatted-vertical-align/expected.png similarity index 100% rename from test/integration/render/tests/text-field/formatted/formatted-vertical-align/expected.png rename to test/integration/render/tests/text-field/formatted-vertical-align/expected.png diff --git a/test/integration/render/tests/text-field/formatted/formatted-vertical-align/style.json b/test/integration/render/tests/text-field/formatted-vertical-align/style.json similarity index 97% rename from test/integration/render/tests/text-field/formatted/formatted-vertical-align/style.json rename to test/integration/render/tests/text-field/formatted-vertical-align/style.json index c7c54903b2..f90b9358b9 100644 --- a/test/integration/render/tests/text-field/formatted/formatted-vertical-align/style.json +++ b/test/integration/render/tests/text-field/formatted-vertical-align/style.json @@ -19,9 +19,6 @@ "geometry": { "type": "Point", "coordinates": [0, 0] - }, - "properties": { - "label": "abc" } } ] From d1dd1ce0b95327cc5bac1162e45a59292db2ed2c Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Wed, 16 Oct 2024 14:40:49 +0200 Subject: [PATCH 07/27] update top alignment --- src/symbol/shaping.ts | 6 +- test/debug-pages/hillshade.html | 74 ++++++++++++++++++ test/debug-pages/index.html | 64 +++++++++++++++ .../expected.png | Bin 22240 -> 21991 bytes .../formatted-vertical-align/expected.png | Bin 24516 -> 22919 bytes .../formatted-vertical-align/style.json | 6 +- 6 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 test/debug-pages/hillshade.html create mode 100644 test/debug-pages/index.html diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 4a17f9a526..2669ca1b87 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -671,13 +671,11 @@ function shapeLines(shaping: Shaping, // at 24 points, we can calculate how much it will move when // we scale up or down. verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; - + // Do not offset vertical alignment for vertical text. if (writingMode !== WritingMode.vertical) { if (section.verticalAlign === 'top') { - // Arbitrarily set the distance between the top of the glyph set - // and top of uppercase letters to be 1/3 em. - verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM / 3) - (ONE_EM / 3); + verticalAlignOffset = 0; } else if (section.verticalAlign === 'center') { // Calculate center as the middle between top and baseline alignment. verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM * 2 / 3) - (ONE_EM / 6); diff --git a/test/debug-pages/hillshade.html b/test/debug-pages/hillshade.html new file mode 100644 index 0000000000..9dff3ccd23 --- /dev/null +++ b/test/debug-pages/hillshade.html @@ -0,0 +1,74 @@ + + + + MapLibre GL JS debug page for terrian + + + + + + + +
+ + + + + diff --git a/test/debug-pages/index.html b/test/debug-pages/index.html new file mode 100644 index 0000000000..54f49f95b8 --- /dev/null +++ b/test/debug-pages/index.html @@ -0,0 +1,64 @@ + + + + Debug Pages + + +

Debug Pages

+ 2762.html
+ 3895.html
+ 7438.html
+ 7517.html
+ animate.html
+ bounds.html
+ cache_api.html
+ canvas.html
+ chinese.html
+ circles.html
+ cluster.html
+ color_spaces.html
+ csp-static.html
+ csp.html
+ custom3d.html
+ debug.html
+ default-image.html
+ events.html
+ extrusion-query.html
+ featurestate.html
+ geojson-updates.html
+ heatmap.html
+ highlightpoints.html
+ hillshade.html
+ iframe-blob.html
+ iframe.html
+ image.html
+ is-safari.html
+ line-gradient.html
+ markers.html
+ mobile_scroll.html
+ multiple.html
+ no_wrap.html
+ popup.html
+ query_features.html
+ raster-streets.html
+ route.html
+ rtl.html
+ satellite.html
+ setstyle.html
+ shield-rotation.html
+ stretchable.html
+ switch-pattern.html
+ symbols.html
+ terrain-hillshade.html
+ terrain-osm.html
+ terrain-satellite.html
+ textsize.html
+ threejs.html
+ tinysdf.html
+ transform-style.html
+ update_image.html
+ variable-anchor-with-icon-text-fit.html
+ video.html
+ wms.html
+ + diff --git a/test/integration/render/tests/text-field/formatted-vertical-align-line/expected.png b/test/integration/render/tests/text-field/formatted-vertical-align-line/expected.png index 09097d073c3c097f2bc6a8b3624f7344813c9151..9b00fff2309189ecea8febde58a1bbbc53d6b939 100644 GIT binary patch literal 21991 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 Dr9R!D literal 22240 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 H-HZPKSDq~) diff --git a/test/integration/render/tests/text-field/formatted-vertical-align/expected.png b/test/integration/render/tests/text-field/formatted-vertical-align/expected.png index 46bd448b4a855bf40a7792b48421c47ef6f3d79b..6041666a95f37ba0f8b1ab9bd6c4ef5b6a1f6f3b 100644 GIT binary patch literal 22919 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 O#8o?2+omi2DgOo+(ar_{ literal 24516 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 Uftnd2cK#o(JGnVF{SuP-pAOO4@&Et; diff --git a/test/integration/render/tests/text-field/formatted-vertical-align/style.json b/test/integration/render/tests/text-field/formatted-vertical-align/style.json index f90b9358b9..75439c8b6a 100644 --- a/test/integration/render/tests/text-field/formatted-vertical-align/style.json +++ b/test/integration/render/tests/text-field/formatted-vertical-align/style.json @@ -39,7 +39,7 @@ { "vertical-align": "top" }, " ", {}, - "ÓÑX yg", + "ÓÑt yg", { "font-scale": 1.2, "vertical-align": "top" }, " ", {}, @@ -68,7 +68,7 @@ { "vertical-align": "center" }, " ", {}, - "ÓÑX yg", + "ÓÑt yg", { "font-scale": 1.2, "vertical-align": "center" }, " ", {}, @@ -97,7 +97,7 @@ { "vertical-align": "baseline" }, " ", {}, - "ÓÑX yg", + "ÓÑt yg", { "font-scale": 1.2, "vertical-align": "baseline" }, " ", {}, From e4d36cdad2014c31f6194526a4b75bcf8f0cbd00 Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Wed, 16 Oct 2024 14:57:10 +0200 Subject: [PATCH 08/27] cleanout --- test/debug-pages/hillshade.html | 74 --------------------------------- test/debug-pages/index.html | 64 ---------------------------- 2 files changed, 138 deletions(-) delete mode 100644 test/debug-pages/hillshade.html delete mode 100644 test/debug-pages/index.html diff --git a/test/debug-pages/hillshade.html b/test/debug-pages/hillshade.html deleted file mode 100644 index 9dff3ccd23..0000000000 --- a/test/debug-pages/hillshade.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - MapLibre GL JS debug page for terrian - - - - - - - -
- - - - - diff --git a/test/debug-pages/index.html b/test/debug-pages/index.html deleted file mode 100644 index 54f49f95b8..0000000000 --- a/test/debug-pages/index.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - Debug Pages - - -

Debug Pages

- 2762.html
- 3895.html
- 7438.html
- 7517.html
- animate.html
- bounds.html
- cache_api.html
- canvas.html
- chinese.html
- circles.html
- cluster.html
- color_spaces.html
- csp-static.html
- csp.html
- custom3d.html
- debug.html
- default-image.html
- events.html
- extrusion-query.html
- featurestate.html
- geojson-updates.html
- heatmap.html
- highlightpoints.html
- hillshade.html
- iframe-blob.html
- iframe.html
- image.html
- is-safari.html
- line-gradient.html
- markers.html
- mobile_scroll.html
- multiple.html
- no_wrap.html
- popup.html
- query_features.html
- raster-streets.html
- route.html
- rtl.html
- satellite.html
- setstyle.html
- shield-rotation.html
- stretchable.html
- switch-pattern.html
- symbols.html
- terrain-hillshade.html
- terrain-osm.html
- terrain-satellite.html
- textsize.html
- threejs.html
- tinysdf.html
- transform-style.html
- update_image.html
- variable-anchor-with-icon-text-fit.html
- video.html
- wms.html
- - From f381f8cf17081ee057a07d1f7b25ed87b57a32ef Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Fri, 18 Oct 2024 15:07:31 +0200 Subject: [PATCH 09/27] refactor shaping --- src/symbol/shaping.ts | 189 ++++++++++++++++++++++++++++-------------- 1 file changed, 127 insertions(+), 62 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 2669ca1b87..b33be6c7f2 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -14,7 +14,7 @@ import {TextFit} from '../style/style_image'; 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'; enum WritingMode { none = 0, @@ -590,6 +590,78 @@ function getAnchorAlignment(anchor: SymbolAnchor) { return {horizontalAlign, verticalAlign}; } +function calculateTallestLineItems( + glyphMap: { + [_: string]: { + [_: number]: StyleGlyph; + }; + }, glyphPositions: { + [_: string]: { + [_: number]: GlyphPosition; + }; + }, + imagePositions: {[_: string]: ImagePosition}, + line: TaggedString +) { + let maxGlyphHeight = 0; + let maxImageHeight = 0; + + for (let i = 0; i < line.length(); i++) { + const section = line.getSection(i); + + if (section.imageName) { + const imagePosition = imagePositions[section.imageName]; + if (!imagePosition) continue; + maxImageHeight = Math.max(maxImageHeight, imagePosition.displaySize[1]); + } else { + const codePoint = line.getCharCode(i); + const positions = glyphPositions[section.fontStack]; + const glyphPosition = positions && positions[codePoint]; + const rectAndMetrics = extractRectAndMetrics(glyphPosition, glyphMap, section, codePoint); + if (rectAndMetrics === null) continue; + const {metrics} = rectAndMetrics; + maxGlyphHeight = Math.max(maxGlyphHeight, metrics.height * section.scale); + } + } + + return {maxGlyphHeight, maxImageHeight}; +} + +function calculateVerticalOffset(verticalAlign: VerticalAlign, lineHeight: number, itemHeight: number) { + if (verticalAlign === 'top') { + return 0; + } else if (verticalAlign === 'center') { + return (lineHeight - itemHeight) * 0.5; + } else { + return lineHeight - itemHeight; + } +} + +function extractRectAndMetrics( + glyphPosition: GlyphPosition, + glyphMap: { + [_: string]: { + [_: number]: StyleGlyph; + }; + }, + section: SectionOptions, codePoint: number +) { + let rect = null; + let metrics = 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]: { @@ -609,13 +681,14 @@ function shapeLines(shaping: Shaping, writingMode: WritingMode.horizontal | WritingMode.vertical, spacing: number, allowVerticalPlacement: boolean, + // TODO: find out what this is used for layoutTextSizeThisZoom: number) { let x = 0; - let y = SHAPING_DEFAULT_OFFSET; + let y = 0; + let bboxBottom = 0; let maxLineLength = 0; - let maxLineHeight = 0; const justify = textJustify === 'right' ? 1 : @@ -626,14 +699,20 @@ function shapeLines(shaping: Shaping, 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; + + const {maxGlyphHeight, maxImageHeight} = calculateTallestLineItems( + glyphMap, + glyphPositions, + imagePositions, + line + ); + const tallestLineItem = Math.max(maxGlyphHeight, maxImageHeight); if (!line.length()) { - y += lineHeight; // Still need a line feed after empty line + y += tallestLineItem; // Still need a line feed after empty line ++lineIndex; continue; } @@ -657,30 +736,19 @@ function shapeLines(shaping: Shaping, if (!section.imageName) { const positions = glyphPositions[section.fontStack]; const glyphPosition = positions && positions[codePoint]; - if (glyphPosition && glyphPosition.rect) { - rect = glyphPosition.rect; - metrics = glyphPosition.metrics; - } else { - const glyphs = glyphMap[section.fontStack]; - const glyph = glyphs && glyphs[codePoint]; - if (!glyph) continue; - metrics = glyph.metrics; - } - - // 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. - verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; - - // Do not offset vertical alignment for vertical text. - if (writingMode !== WritingMode.vertical) { - if (section.verticalAlign === 'top') { - verticalAlignOffset = 0; - } else if (section.verticalAlign === 'center') { - // Calculate center as the middle between top and baseline alignment. - verticalAlignOffset = (lineMaxScale - section.scale) * (ONE_EM * 2 / 3) - (ONE_EM / 6); - } - } + + const rectAndMetrics = extractRectAndMetrics(glyphPosition, glyphMap, section, codePoint); + + if (rectAndMetrics === null) continue; + + rect = rectAndMetrics.rect; + metrics = rectAndMetrics.metrics; + + verticalAlignOffset = calculateVerticalOffset( + vertical ? 'center' : section.verticalAlign, + tallestLineItem, + section.scale * ONE_EM + ); } else { const imagePosition = imagePositions[section.imageName]; if (!imagePosition) continue; @@ -691,7 +759,7 @@ function shapeLines(shaping: Shaping, // 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; + // section.scale = section.scale * ONE_EM / layoutTextSizeThisZoom; metrics = {width: size[0], height: size[1], @@ -701,29 +769,14 @@ function shapeLines(shaping: Shaping, // 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; - verticalAlignOffset = maxLineOffset + imageOffset; - - // Do not offset vertical alignment for vertical text. - if (writingMode !== WritingMode.vertical) { - if (section.verticalAlign === 'top') { - // Aligns top of an image to top of a line. - verticalAlignOffset = 0; - } else if (section.verticalAlign === 'center') { - // We calculate center as the middle between top and baseline alignment. - verticalAlignOffset = (maxLineOffset + imageOffset) / 2; - } - } - - 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; - } + verticalAlignOffset = calculateVerticalOffset( + vertical ? 'center' : section.verticalAlign, + tallestLineItem, + imagePosition.displaySize[1] + ); + + verticalAdvance = metrics.advance; } if (!vertical) { @@ -740,24 +793,36 @@ function shapeLines(shaping: Shaping, 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, 0); } x = 0; - const currentLineHeight = lineHeight * lineMaxScale + lineOffset; - positionedLine.lineOffset = Math.max(lineOffset, maxLineOffset); - y += currentLineHeight; - maxLineHeight = Math.max(currentLineHeight, maxLineHeight); + + const isImageTheTallestInLine = tallestLineItem >= maxGlyphHeight; + + if (lineIndex === lines.length - 1) { + bboxBottom = y + Math.max(lineHeight * lineMaxScale, tallestLineItem); + } + + // TODO: review this logic, compare with the current behavior + if (isImageTheTallestInLine) { + const textLineHeight = lineHeight / ONE_EM; + y += tallestLineItem + textLineHeight * maxGlyphHeight; + } else { + y += lineHeight * lineMaxScale; + } + y += lineHeight * lineMaxScale; + ++lineIndex; } // Calculate the bounding box and justify / align text block. - const height = y - SHAPING_DEFAULT_OFFSET; + // const height = y; 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, height, lines.length); - shaping.top += -verticalAlign * height; - shaping.bottom = shaping.top + height; + shaping.top = 0; + shaping.bottom = shaping.top + bboxBottom; shaping.left += -horizontalAlign * maxLineLength; shaping.right = shaping.left + maxLineLength; } From 04a46c492b36083d474115a3882486dd6d4cacca Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Mon, 21 Oct 2024 11:20:33 +0200 Subject: [PATCH 10/27] Fix vertical alignment --- src/symbol/shaping.ts | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index b33be6c7f2..27b953d78f 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -686,7 +686,10 @@ function shapeLines(shaping: Shaping, let x = 0; let y = 0; - let bboxBottom = 0; + /** + * Height of the block of text (a sum of all line heights). + */ + let blockHeight = 0; let maxLineLength = 0; @@ -767,9 +770,6 @@ function shapeLines(shaping: Shaping, 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. - verticalAlignOffset = calculateVerticalOffset( vertical ? 'center' : section.verticalAlign, tallestLineItem, @@ -798,12 +798,11 @@ function shapeLines(shaping: Shaping, x = 0; - const isImageTheTallestInLine = tallestLineItem >= maxGlyphHeight; - if (lineIndex === lines.length - 1) { - bboxBottom = y + Math.max(lineHeight * lineMaxScale, tallestLineItem); + blockHeight = y + Math.max(lineHeight * lineMaxScale, tallestLineItem); } + const isImageTheTallestInLine = tallestLineItem >= maxGlyphHeight; // TODO: review this logic, compare with the current behavior if (isImageTheTallestInLine) { const textLineHeight = lineHeight / ONE_EM; @@ -811,18 +810,19 @@ function shapeLines(shaping: Shaping, } else { y += lineHeight * lineMaxScale; } - y += lineHeight * lineMaxScale; ++lineIndex; } - // Calculate the bounding box and justify / align text block. - // const height = y; + // verticalAlign top = 0, center = 0.5, bottom = 1 const {horizontalAlign, verticalAlign} = getAnchorAlignment(textAnchor); - // align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, maxLineHeight, lineHeight, height, lines.length); - shaping.top = 0; - shaping.bottom = shaping.top + bboxBottom; + // Align text block + align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, blockHeight); + + // Calculate the bounding box + shaping.top = -verticalAlign * blockHeight; + shaping.bottom = shaping.top + blockHeight; shaping.left += -horizontalAlign * maxLineLength; shaping.right = shaping.left + maxLineLength; } @@ -846,23 +846,17 @@ function justifyLine(positionedGlyphs: Array, } } +/** + * Aligns the lines based on horizontal and vertical alignment. + */ function align(positionedLines: Array, justify: number, horizontalAlign: number, verticalAlign: number, maxLineLength: number, - maxLineHeight: number, - lineHeight: number, - blockHeight: number, - lineCount: number) { + blockHeight: number) { const shiftX = (justify - horizontalAlign) * maxLineLength; - let shiftY = 0; - - if (maxLineHeight !== lineHeight) { - shiftY = -blockHeight * verticalAlign - SHAPING_DEFAULT_OFFSET; - } else { - shiftY = (-verticalAlign * lineCount + 0.5) * lineHeight; - } + const shiftY = -verticalAlign * blockHeight; for (const line of positionedLines) { for (const positionedGlyph of line.positionedGlyphs) { From f1778523389917803ff88d29d3c84f6f2857d59d Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Mon, 21 Oct 2024 15:53:57 +0200 Subject: [PATCH 11/27] fix bbox size --- src/symbol/shaping.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 27b953d78f..ecaf9c8fec 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -601,7 +601,8 @@ function calculateTallestLineItems( }; }, imagePositions: {[_: string]: ImagePosition}, - line: TaggedString + line: TaggedString, + layoutTextSizeThisZoom: number ) { let maxGlyphHeight = 0; let maxImageHeight = 0; @@ -612,7 +613,7 @@ function calculateTallestLineItems( if (section.imageName) { const imagePosition = imagePositions[section.imageName]; if (!imagePosition) continue; - maxImageHeight = Math.max(maxImageHeight, imagePosition.displaySize[1]); + maxImageHeight = Math.max(maxImageHeight, imagePosition.displaySize[1] * ONE_EM / layoutTextSizeThisZoom); } else { const codePoint = line.getCharCode(i); const positions = glyphPositions[section.fontStack]; @@ -624,7 +625,7 @@ function calculateTallestLineItems( } } - return {maxGlyphHeight, maxImageHeight}; + return {maxGlyphHeight, maxImageHeight}; } function calculateVerticalOffset(verticalAlign: VerticalAlign, lineHeight: number, itemHeight: number) { @@ -710,7 +711,8 @@ function shapeLines(shaping: Shaping, glyphMap, glyphPositions, imagePositions, - line + line, + layoutTextSizeThisZoom ); const tallestLineItem = Math.max(maxGlyphHeight, maxImageHeight); @@ -725,7 +727,7 @@ function shapeLines(shaping: Shaping, const sectionIndex = line.getSectionIndex(i); const codePoint = line.getCharCode(i); let verticalAlignOffset = 0.0; - let metrics = null; + let metrics: GlyphMetrics | null = null; let rect = null; let imageName = null; let verticalAdvance = ONE_EM; @@ -762,7 +764,7 @@ function shapeLines(shaping: Shaping, // 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; + section.scale = 1 * ONE_EM / layoutTextSizeThisZoom; metrics = {width: size[0], height: size[1], @@ -773,7 +775,7 @@ function shapeLines(shaping: Shaping, verticalAlignOffset = calculateVerticalOffset( vertical ? 'center' : section.verticalAlign, tallestLineItem, - imagePosition.displaySize[1] + imagePosition.displaySize[1] * section.scale ); verticalAdvance = metrics.advance; @@ -799,7 +801,10 @@ function shapeLines(shaping: Shaping, x = 0; if (lineIndex === lines.length - 1) { - blockHeight = y + Math.max(lineHeight * lineMaxScale, tallestLineItem); + // When items are aligned to the baseline, part of the glyph will be below the image + // We need to add this part to the block height + const belowBaselineOffset = lineMaxScale * (ONE_EM + SHAPING_DEFAULT_OFFSET); + blockHeight = y + Math.max(lineHeight * lineMaxScale, tallestLineItem + belowBaselineOffset); } const isImageTheTallestInLine = tallestLineItem >= maxGlyphHeight; From 2f3cc78602f50d65f3f6bfa3ce5ad89c711867aa Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Tue, 22 Oct 2024 09:45:13 +0200 Subject: [PATCH 12/27] adjust line spacing --- src/symbol/shaping.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index ecaf9c8fec..d514284a40 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -15,6 +15,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, VerticalAlign} from '@maplibre/maplibre-gl-style-spec'; +import {text} from 'd3'; enum WritingMode { none = 0, @@ -682,7 +683,6 @@ function shapeLines(shaping: Shaping, writingMode: WritingMode.horizontal | WritingMode.vertical, spacing: number, allowVerticalPlacement: boolean, - // TODO: find out what this is used for layoutTextSizeThisZoom: number) { let x = 0; @@ -800,21 +800,17 @@ function shapeLines(shaping: Shaping, x = 0; + // When items are aligned to the baseline, part of the glyph will be below the image + // We need to add this part to the block height + const belowBaselineOffset = lineMaxScale * (ONE_EM + SHAPING_DEFAULT_OFFSET); + const currentLineHeight = Math.max(lineHeight * lineMaxScale, tallestLineItem + belowBaselineOffset); if (lineIndex === lines.length - 1) { - // When items are aligned to the baseline, part of the glyph will be below the image - // We need to add this part to the block height - const belowBaselineOffset = lineMaxScale * (ONE_EM + SHAPING_DEFAULT_OFFSET); - blockHeight = y + Math.max(lineHeight * lineMaxScale, tallestLineItem + belowBaselineOffset); + blockHeight = y + currentLineHeight; } - const isImageTheTallestInLine = tallestLineItem >= maxGlyphHeight; - // TODO: review this logic, compare with the current behavior - if (isImageTheTallestInLine) { - const textLineHeight = lineHeight / ONE_EM; - y += tallestLineItem + textLineHeight * maxGlyphHeight; - } else { - y += lineHeight * lineMaxScale; - } + // If image is taller than the text, the block height should be adjusted + const imageOffset = tallestLineItem - maxGlyphHeight; + y += lineHeight * lineMaxScale + imageOffset; ++lineIndex; } From e8f916dcb33c9cb3b9335b08ceab5aeb064802a2 Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Tue, 22 Oct 2024 14:43:52 +0200 Subject: [PATCH 13/27] vertical placement --- src/symbol/shaping.ts | 50 +++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index d514284a40..44efc80db4 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -15,7 +15,6 @@ 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, VerticalAlign} from '@maplibre/maplibre-gl-style-spec'; -import {text} from 'd3'; enum WritingMode { none = 0, @@ -591,7 +590,7 @@ function getAnchorAlignment(anchor: SymbolAnchor) { return {horizontalAlign, verticalAlign}; } -function calculateTallestLineItems( +function calculateLineBlockMetrics( glyphMap: { [_: string]: { [_: number]: StyleGlyph; @@ -607,7 +606,6 @@ function calculateTallestLineItems( ) { let maxGlyphHeight = 0; let maxImageHeight = 0; - for (let i = 0; i < line.length(); i++) { const section = line.getSection(i); @@ -626,7 +624,7 @@ function calculateTallestLineItems( } } - return {maxGlyphHeight, maxImageHeight}; + return {maxGlyphHeight, maxImageHeight}; } function calculateVerticalOffset(verticalAlign: VerticalAlign, lineHeight: number, itemHeight: number) { @@ -703,21 +701,22 @@ function shapeLines(shaping: Shaping, 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; - const {maxGlyphHeight, maxImageHeight} = calculateTallestLineItems( + const {maxGlyphHeight, maxImageHeight} = calculateLineBlockMetrics( glyphMap, glyphPositions, imagePositions, line, layoutTextSizeThisZoom ); - const tallestLineItem = Math.max(maxGlyphHeight, maxImageHeight); + const maxLineHeight = Math.max(maxGlyphHeight, maxImageHeight); if (!line.length()) { - y += tallestLineItem; // Still need a line feed after empty line + y += maxLineHeight; // Still need a line feed after empty line ++lineIndex; continue; } @@ -749,11 +748,17 @@ function shapeLines(shaping: Shaping, rect = rectAndMetrics.rect; metrics = rectAndMetrics.metrics; - verticalAlignOffset = calculateVerticalOffset( - vertical ? 'center' : section.verticalAlign, - tallestLineItem, - section.scale * ONE_EM - ); + if (vertical) { + // If text is layed out verically, the verticalAlignOffset affetcs horizontal alignment. + // We set this offset to a const value. + verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM - SHAPING_DEFAULT_OFFSET; + } else { + verticalAlignOffset = calculateVerticalOffset( + section.verticalAlign, + maxLineHeight, + section.scale * ONE_EM + ); + } } else { const imagePosition = imagePositions[section.imageName]; if (!imagePosition) continue; @@ -772,11 +777,18 @@ function shapeLines(shaping: Shaping, top: -GLYPH_PBF_BORDER, advance: vertical ? size[1] : size[0]}; - verticalAlignOffset = calculateVerticalOffset( - vertical ? 'center' : section.verticalAlign, - tallestLineItem, - imagePosition.displaySize[1] * section.scale - ); + if (vertical) { + // If text is layed out verically, the verticalAlignOffset affetcs horizontal alignment. + // We set this offset to a const value. + const imageOffset = ONE_EM - size[1] * section.scale; + verticalAlignOffset = maxLineOffset + imageOffset - SHAPING_DEFAULT_OFFSET; + } else { + verticalAlignOffset = calculateVerticalOffset( + section.verticalAlign, + maxLineHeight, + imagePosition.displaySize[1] * section.scale + ); + } verticalAdvance = metrics.advance; } @@ -803,13 +815,13 @@ function shapeLines(shaping: Shaping, // When items are aligned to the baseline, part of the glyph will be below the image // We need to add this part to the block height const belowBaselineOffset = lineMaxScale * (ONE_EM + SHAPING_DEFAULT_OFFSET); - const currentLineHeight = Math.max(lineHeight * lineMaxScale, tallestLineItem + belowBaselineOffset); + const currentLineHeight = Math.max(lineHeight * lineMaxScale, maxLineHeight + belowBaselineOffset); if (lineIndex === lines.length - 1) { blockHeight = y + currentLineHeight; } // If image is taller than the text, the block height should be adjusted - const imageOffset = tallestLineItem - maxGlyphHeight; + const imageOffset = maxLineHeight - maxGlyphHeight; y += lineHeight * lineMaxScale + imageOffset; ++lineIndex; From 7b174cf8c09cddb19608fe6ae63e06651658e48a Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Wed, 23 Oct 2024 09:46:48 +0200 Subject: [PATCH 14/27] cleanout --- src/symbol/shaping.ts | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 44efc80db4..c7910e62d1 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -602,7 +602,7 @@ function calculateLineBlockMetrics( }, imagePositions: {[_: string]: ImagePosition}, line: TaggedString, - layoutTextSizeThisZoom: number + layoutTextSizeFactor: number ) { let maxGlyphHeight = 0; let maxImageHeight = 0; @@ -612,15 +612,20 @@ function calculateLineBlockMetrics( if (section.imageName) { const imagePosition = imagePositions[section.imageName]; if (!imagePosition) continue; - maxImageHeight = Math.max(maxImageHeight, imagePosition.displaySize[1] * ONE_EM / layoutTextSizeThisZoom); + maxImageHeight = Math.max( + maxImageHeight, + imagePosition.displaySize[1] * layoutTextSizeFactor + ); } else { const codePoint = line.getCharCode(i); const positions = glyphPositions[section.fontStack]; const glyphPosition = positions && positions[codePoint]; - const rectAndMetrics = extractRectAndMetrics(glyphPosition, glyphMap, section, codePoint); + const rectAndMetrics = getRectAndMetrics(glyphPosition, glyphMap, section, codePoint); if (rectAndMetrics === null) continue; - const {metrics} = rectAndMetrics; - maxGlyphHeight = Math.max(maxGlyphHeight, metrics.height * section.scale); + maxGlyphHeight = Math.max( + maxGlyphHeight, + rectAndMetrics.metrics.height * section.scale + ); } } @@ -637,7 +642,7 @@ function calculateVerticalOffset(verticalAlign: VerticalAlign, lineHeight: numbe } } -function extractRectAndMetrics( +function getRectAndMetrics( glyphPosition: GlyphPosition, glyphMap: { [_: string]: { @@ -695,6 +700,7 @@ function shapeLines(shaping: Shaping, const justify = textJustify === 'right' ? 1 : textJustify === 'left' ? 0 : 0.5; + const layoutTextSizeFactor = ONE_EM / layoutTextSizeThisZoom; let lineIndex = 0; for (const line of lines) { @@ -711,7 +717,7 @@ function shapeLines(shaping: Shaping, glyphPositions, imagePositions, line, - layoutTextSizeThisZoom + layoutTextSizeFactor ); const maxLineHeight = Math.max(maxGlyphHeight, maxImageHeight); @@ -741,7 +747,7 @@ function shapeLines(shaping: Shaping, const positions = glyphPositions[section.fontStack]; const glyphPosition = positions && positions[codePoint]; - const rectAndMetrics = extractRectAndMetrics(glyphPosition, glyphMap, section, codePoint); + const rectAndMetrics = getRectAndMetrics(glyphPosition, glyphMap, section, codePoint); if (rectAndMetrics === null) continue; @@ -768,8 +774,8 @@ function shapeLines(shaping: Shaping, 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 = 1 * ONE_EM / layoutTextSizeThisZoom; + // when FormattedSection is an image section.A + section.scale = 1 * layoutTextSizeFactor; metrics = {width: size[0], height: size[1], @@ -820,7 +826,7 @@ function shapeLines(shaping: Shaping, blockHeight = y + currentLineHeight; } - // If image is taller than the text, the block height should be adjusted + // Image can be higher than the text, so we need to account for that const imageOffset = maxLineHeight - maxGlyphHeight; y += lineHeight * lineMaxScale + imageOffset; From 33f7d6f8fa9c2673fda5956acafdc278335231ba Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Wed, 23 Oct 2024 11:56:03 +0200 Subject: [PATCH 15/27] handle text offset --- src/symbol/shaping.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index c7910e62d1..ef3f1108dc 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -632,7 +632,11 @@ function calculateLineBlockMetrics( return {maxGlyphHeight, maxImageHeight}; } -function calculateVerticalOffset(verticalAlign: VerticalAlign, lineHeight: number, itemHeight: number) { +function calculateVerticalOffset( + verticalAlign: VerticalAlign, + lineHeight: number, + itemHeight: number +) { if (verticalAlign === 'top') { return 0; } else if (verticalAlign === 'center') { @@ -651,8 +655,8 @@ function getRectAndMetrics( }, section: SectionOptions, codePoint: number ) { - let rect = null; - let metrics = null; + let rect: Rect = null; + let metrics: GlyphMetrics = null; if (glyphPosition && glyphPosition.rect) { rect = glyphPosition.rect; @@ -792,7 +796,7 @@ function shapeLines(shaping: Shaping, verticalAlignOffset = calculateVerticalOffset( section.verticalAlign, maxLineHeight, - imagePosition.displaySize[1] * section.scale + imagePosition.displaySize[1] * section.scale, ); } @@ -840,7 +844,8 @@ function shapeLines(shaping: Shaping, align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, blockHeight); // Calculate the bounding box - shaping.top = -verticalAlign * blockHeight; + // shaping.top & shaping.left already include text offset (text-radial-offset or text-offset) + shaping.top += -verticalAlign * blockHeight + spacing; shaping.bottom = shaping.top + blockHeight; shaping.left += -horizontalAlign * maxLineLength; shaping.right = shaping.left + maxLineLength; From 70c4b94f35432cc612d0c1fe89cc7ee335cf573f Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Wed, 23 Oct 2024 14:45:53 +0200 Subject: [PATCH 16/27] minor fix --- src/symbol/shaping.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index ef3f1108dc..0b82113471 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -845,7 +845,7 @@ function shapeLines(shaping: Shaping, // Calculate the bounding box // shaping.top & shaping.left already include text offset (text-radial-offset or text-offset) - shaping.top += -verticalAlign * blockHeight + spacing; + shaping.top += -verticalAlign * blockHeight; shaping.bottom = shaping.top + blockHeight; shaping.left += -horizontalAlign * maxLineLength; shaping.right = shaping.left + maxLineLength; From 3fa48a95b45bd0ab98afbc30f32861f0f1be3742 Mon Sep 17 00:00:00 2001 From: Zbigniew Matysek Date: Tue, 29 Oct 2024 09:08:40 +0100 Subject: [PATCH 17/27] const glyph height --- src/symbol/shaping.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 0b82113471..8001129416 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -624,7 +624,7 @@ function calculateLineBlockMetrics( if (rectAndMetrics === null) continue; maxGlyphHeight = Math.max( maxGlyphHeight, - rectAndMetrics.metrics.height * section.scale + ONE_EM * section.scale ); } } @@ -796,7 +796,7 @@ function shapeLines(shaping: Shaping, verticalAlignOffset = calculateVerticalOffset( section.verticalAlign, maxLineHeight, - imagePosition.displaySize[1] * section.scale, + imagePosition.displaySize[1] * section.scale ); } From a4711675f26ef79d2d1b633c23fd6d35c2b90588 Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Sun, 3 Nov 2024 11:59:47 +0100 Subject: [PATCH 18/27] align when no big image --- src/symbol/shaping.ts | 64 ++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 8001129416..2061d38b2b 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -694,12 +694,9 @@ function shapeLines(shaping: Shaping, let x = 0; let y = 0; - /** - * Height of the block of text (a sum of all line heights). - */ - let blockHeight = 0; let maxLineLength = 0; + let maxLineHeight = 0; const justify = textJustify === 'right' ? 1 : @@ -716,6 +713,12 @@ function shapeLines(shaping: Shaping, shaping.positionedLines[lineIndex] = positionedLine; const positionedGlyphs = positionedLine.positionedGlyphs; + if (!line.length()) { + y += lineHeight; // Still need a line feed after empty line + ++lineIndex; + continue; + } + const {maxGlyphHeight, maxImageHeight} = calculateLineBlockMetrics( glyphMap, glyphPositions, @@ -723,13 +726,7 @@ function shapeLines(shaping: Shaping, line, layoutTextSizeFactor ); - const maxLineHeight = Math.max(maxGlyphHeight, maxImageHeight); - - if (!line.length()) { - y += maxLineHeight; // Still need a line feed after empty line - ++lineIndex; - continue; - } + const lineContentHeight = Math.max(maxGlyphHeight, maxImageHeight); for (let i = 0; i < line.length(); i++) { const section = line.getSection(i); @@ -765,7 +762,7 @@ function shapeLines(shaping: Shaping, } else { verticalAlignOffset = calculateVerticalOffset( section.verticalAlign, - maxLineHeight, + lineContentHeight, section.scale * ONE_EM ); } @@ -795,7 +792,7 @@ function shapeLines(shaping: Shaping, } else { verticalAlignOffset = calculateVerticalOffset( section.verticalAlign, - maxLineHeight, + lineContentHeight, imagePosition.displaySize[1] * section.scale ); } @@ -804,11 +801,11 @@ function shapeLines(shaping: Shaping, } if (!vertical) { - positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + verticalAlignOffset, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); + positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + verticalAlignOffset + SHAPING_DEFAULT_OFFSET, 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 + verticalAlignOffset, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); + positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + verticalAlignOffset + SHAPING_DEFAULT_OFFSET, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); x += verticalAdvance * section.scale + spacing; } } @@ -822,31 +819,21 @@ function shapeLines(shaping: Shaping, x = 0; - // When items are aligned to the baseline, part of the glyph will be below the image - // We need to add this part to the block height - const belowBaselineOffset = lineMaxScale * (ONE_EM + SHAPING_DEFAULT_OFFSET); - const currentLineHeight = Math.max(lineHeight * lineMaxScale, maxLineHeight + belowBaselineOffset); - if (lineIndex === lines.length - 1) { - blockHeight = y + currentLineHeight; - } - - // Image can be higher than the text, so we need to account for that - const imageOffset = maxLineHeight - maxGlyphHeight; - y += lineHeight * lineMaxScale + imageOffset; + const currentLineHeight = Math.max(lineHeight * lineMaxScale, maxImageHeight); + y += currentLineHeight; + maxLineHeight = Math.max(currentLineHeight, maxLineHeight); ++lineIndex; } - // verticalAlign top = 0, center = 0.5, bottom = 1 + // Calculate the bounding box and justify / align text block. const {horizontalAlign, verticalAlign} = getAnchorAlignment(textAnchor); - - // Align text block - align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, blockHeight); + align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, maxLineHeight, lineHeight, y, lines.length); // Calculate the bounding box // shaping.top & shaping.left already include text offset (text-radial-offset or text-offset) - shaping.top += -verticalAlign * blockHeight; - shaping.bottom = shaping.top + blockHeight; + shaping.top += -verticalAlign * y; + shaping.bottom = shaping.top + y; shaping.left += -horizontalAlign * maxLineLength; shaping.right = shaping.left + maxLineLength; } @@ -878,9 +865,18 @@ function align(positionedLines: Array, horizontalAlign: number, verticalAlign: number, maxLineLength: number, - blockHeight: number) { + maxLineHeight: number, + lineHeight: number, + blockHeight: number, + lineCount: number) { const shiftX = (justify - horizontalAlign) * maxLineLength; - const shiftY = -verticalAlign * blockHeight; + let shiftY = 0; + + if (maxLineHeight !== lineHeight) { + shiftY = -blockHeight * verticalAlign - SHAPING_DEFAULT_OFFSET; + } else { + shiftY = -verticalAlign * lineCount * lineHeight + 0.5 * lineHeight; + } for (const line of positionedLines) { for (const positionedGlyph of line.positionedGlyphs) { From dd30b1f9e2e822d80e498e631c9f917b604ba9ae Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 4 Nov 2024 08:16:09 +0100 Subject: [PATCH 19/27] use section.scale when multiplying on image --- src/symbol/shaping.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 2061d38b2b..97ef350186 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -776,7 +776,7 @@ function shapeLines(shaping: Shaping, // 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.A - section.scale = 1 * layoutTextSizeFactor; + section.scale = section.scale * layoutTextSizeFactor; metrics = {width: size[0], height: size[1], From e01a437f7b58c69026538c078f6909e9327798da Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Tue, 5 Nov 2024 09:48:13 +0100 Subject: [PATCH 20/27] fix big image case --- src/symbol/shaping.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 97ef350186..8af8294806 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -712,6 +712,7 @@ function shapeLines(shaping: Shaping, const positionedLine = {positionedGlyphs: [], lineOffset: 0}; shaping.positionedLines[lineIndex] = positionedLine; const positionedGlyphs = positionedLine.positionedGlyphs; + let imageOffset = 0.0; if (!line.length()) { y += lineHeight; // Still need a line feed after empty line @@ -798,6 +799,14 @@ function shapeLines(shaping: Shaping, } 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 > imageOffset) { + imageOffset = offset; + } } if (!vertical) { @@ -819,7 +828,7 @@ function shapeLines(shaping: Shaping, x = 0; - const currentLineHeight = Math.max(lineHeight * lineMaxScale, maxImageHeight); + const currentLineHeight = lineHeight * lineMaxScale + imageOffset; y += currentLineHeight; maxLineHeight = Math.max(currentLineHeight, maxLineHeight); From f14bd5df4390354b5c7f0c8ccd968865ff634132 Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Tue, 5 Nov 2024 15:45:52 +0100 Subject: [PATCH 21/27] fix vertical --- src/symbol/shaping.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 8af8294806..c165a992e2 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -759,7 +759,7 @@ function shapeLines(shaping: Shaping, if (vertical) { // If text is layed out verically, the verticalAlignOffset affetcs horizontal alignment. // We set this offset to a const value. - verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM - SHAPING_DEFAULT_OFFSET; + verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; } else { verticalAlignOffset = calculateVerticalOffset( section.verticalAlign, @@ -789,7 +789,7 @@ function shapeLines(shaping: Shaping, // If text is layed out verically, the verticalAlignOffset affetcs horizontal alignment. // We set this offset to a const value. const imageOffset = ONE_EM - size[1] * section.scale; - verticalAlignOffset = maxLineOffset + imageOffset - SHAPING_DEFAULT_OFFSET; + verticalAlignOffset = maxLineOffset + imageOffset; } else { verticalAlignOffset = calculateVerticalOffset( section.verticalAlign, @@ -823,13 +823,12 @@ function shapeLines(shaping: Shaping, if (positionedGlyphs.length !== 0) { const lineLength = x - spacing; maxLineLength = Math.max(lineLength, maxLineLength); - justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify, 0); + justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify, writingMode === WritingMode.vertical ? imageOffset : 0); } x = 0; - const currentLineHeight = lineHeight * lineMaxScale + imageOffset; - + positionedLine.lineOffset = Math.max(imageOffset, maxLineOffset); y += currentLineHeight; maxLineHeight = Math.max(currentLineHeight, maxLineHeight); ++lineIndex; From 5b04aed1b2415a6b4f60eee5afbfe4c482c558e7 Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Fri, 8 Nov 2024 12:11:11 +0100 Subject: [PATCH 22/27] simplify imageOffset calculation --- src/symbol/shaping.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index c165a992e2..f1c70ebdb3 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -802,8 +802,7 @@ function shapeLines(shaping: Shaping, // 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; + const offset = (vertical ? size[0] : size[1]) * section.scale - ONE_EM * lineMaxScale; if (offset > 0 && offset > imageOffset) { imageOffset = offset; } From 546294859d34f501a4b93bf59f2c32d80a28f855 Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Fri, 8 Nov 2024 16:14:02 +0100 Subject: [PATCH 23/27] code simplification --- src/symbol/shaping.ts | 67 ++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index f1c70ebdb3..f0fa39b3a1 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -590,7 +590,7 @@ function getAnchorAlignment(anchor: SymbolAnchor) { return {horizontalAlign, verticalAlign}; } -function calculateLineBlockMetrics( +function calculateLineContentSize( glyphMap: { [_: string]: { [_: number]: StyleGlyph; @@ -604,8 +604,10 @@ function calculateLineBlockMetrics( line: TaggedString, layoutTextSizeFactor: number ) { - let maxGlyphHeight = 0; + let maxGlyphSize = 0; let maxImageHeight = 0; + let maxImageWidth = 0; + for (let i = 0; i < line.length(); i++) { const section = line.getSection(i); @@ -616,33 +618,38 @@ function calculateLineBlockMetrics( maxImageHeight, imagePosition.displaySize[1] * layoutTextSizeFactor ); + maxImageWidth = Math.max( + maxImageWidth, + imagePosition.displaySize[0] * layoutTextSizeFactor + ); } else { const codePoint = line.getCharCode(i); const positions = glyphPositions[section.fontStack]; const glyphPosition = positions && positions[codePoint]; const rectAndMetrics = getRectAndMetrics(glyphPosition, glyphMap, section, codePoint); if (rectAndMetrics === null) continue; - maxGlyphHeight = Math.max( - maxGlyphHeight, + maxGlyphSize = Math.max( + maxGlyphSize, ONE_EM * section.scale ); } } - return {maxGlyphHeight, maxImageHeight}; + const lineContentHeight = Math.max(maxGlyphSize, maxImageHeight); + const lineContentWidth = Math.max(maxGlyphSize, maxImageWidth); + + return {lineContentWidth, lineContentHeight}; } -function calculateVerticalOffset( - verticalAlign: VerticalAlign, - lineHeight: number, - itemHeight: number +function getVerticalAlignFactor( + verticalAlign: VerticalAlign ) { if (verticalAlign === 'top') { return 0; } else if (verticalAlign === 'center') { - return (lineHeight - itemHeight) * 0.5; + return 0.5; } else { - return lineHeight - itemHeight; + return 1; } } @@ -708,7 +715,6 @@ function shapeLines(shaping: Shaping, 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; @@ -720,20 +726,19 @@ function shapeLines(shaping: Shaping, continue; } - const {maxGlyphHeight, maxImageHeight} = calculateLineBlockMetrics( + const {lineContentWidth, lineContentHeight} = calculateLineContentSize( glyphMap, glyphPositions, imagePositions, line, layoutTextSizeFactor ); - const lineContentHeight = Math.max(maxGlyphHeight, maxImageHeight); for (let i = 0; i < line.length(); i++) { const section = line.getSection(i); const sectionIndex = line.getSectionIndex(i); const codePoint = line.getCharCode(i); - let verticalAlignOffset = 0.0; + let baselineOffset = 0.0; let metrics: GlyphMetrics | null = null; let rect = null; let imageName = null; @@ -757,15 +762,10 @@ function shapeLines(shaping: Shaping, metrics = rectAndMetrics.metrics; if (vertical) { - // If text is layed out verically, the verticalAlignOffset affetcs horizontal alignment. - // We set this offset to a const value. - verticalAlignOffset = (lineMaxScale - section.scale) * ONE_EM; + baselineOffset = lineContentWidth - section.scale * ONE_EM; } else { - verticalAlignOffset = calculateVerticalOffset( - section.verticalAlign, - lineContentHeight, - section.scale * ONE_EM - ); + const verticalAlignFactor = getVerticalAlignFactor(section.verticalAlign); + baselineOffset = (lineContentHeight - section.scale * ONE_EM) * verticalAlignFactor; } } else { const imagePosition = imagePositions[section.imageName]; @@ -786,16 +786,10 @@ function shapeLines(shaping: Shaping, advance: vertical ? size[1] : size[0]}; if (vertical) { - // If text is layed out verically, the verticalAlignOffset affetcs horizontal alignment. - // We set this offset to a const value. - const imageOffset = ONE_EM - size[1] * section.scale; - verticalAlignOffset = maxLineOffset + imageOffset; + baselineOffset = lineContentWidth - size[1] * section.scale; } else { - verticalAlignOffset = calculateVerticalOffset( - section.verticalAlign, - lineContentHeight, - imagePosition.displaySize[1] * section.scale - ); + const verticalAlignFactor = getVerticalAlignFactor(section.verticalAlign); + baselineOffset = (lineContentHeight - size[1] * section.scale) * verticalAlignFactor; } verticalAdvance = metrics.advance; @@ -809,11 +803,11 @@ function shapeLines(shaping: Shaping, } if (!vertical) { - positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + verticalAlignOffset + SHAPING_DEFAULT_OFFSET, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); + positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + baselineOffset + SHAPING_DEFAULT_OFFSET, 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 + verticalAlignOffset + SHAPING_DEFAULT_OFFSET, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); + positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + baselineOffset + SHAPING_DEFAULT_OFFSET, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); x += verticalAdvance * section.scale + spacing; } } @@ -822,12 +816,13 @@ function shapeLines(shaping: Shaping, if (positionedGlyphs.length !== 0) { const lineLength = x - spacing; maxLineLength = Math.max(lineLength, maxLineLength); - justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify, writingMode === WritingMode.vertical ? imageOffset : 0); + justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify, 0); } x = 0; - const currentLineHeight = lineHeight * lineMaxScale + imageOffset; + 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; From 966c17d5e23b757babf6a9e130c304dfb9f849cb Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 11 Nov 2024 11:42:23 +0100 Subject: [PATCH 24/27] improve readability --- src/symbol/shaping.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index f0fa39b3a1..0de3e1de3c 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -803,11 +803,33 @@ function shapeLines(shaping: Shaping, } if (!vertical) { - positionedGlyphs.push({glyph: codePoint, imageName, x, y: y + baselineOffset + SHAPING_DEFAULT_OFFSET, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); + positionedGlyphs.push({ + glyph: codePoint, + imageName, + x, + y: y + baselineOffset + SHAPING_DEFAULT_OFFSET, + 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 + SHAPING_DEFAULT_OFFSET, vertical, scale: section.scale, fontStack: section.fontStack, sectionIndex, metrics, rect}); + positionedGlyphs.push({ + glyph: codePoint, + imageName, + x, + y: y + baselineOffset + SHAPING_DEFAULT_OFFSET, + vertical, + scale: section.scale, + fontStack: section.fontStack, + sectionIndex, + metrics, + rect + }); x += verticalAdvance * section.scale + spacing; } } From 4863b9211d27020b25b145023752a69946e99cef Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 11 Nov 2024 14:17:23 +0100 Subject: [PATCH 25/27] cleaning - removing dead code --- src/symbol/shaping.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 0de3e1de3c..3f6b8bd2bd 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -838,7 +838,7 @@ function shapeLines(shaping: Shaping, if (positionedGlyphs.length !== 0) { const lineLength = x - spacing; maxLineLength = Math.max(lineLength, maxLineLength); - justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify, 0); + justifyLine(positionedGlyphs, 0, positionedGlyphs.length - 1, justify); } x = 0; @@ -866,9 +866,8 @@ function shapeLines(shaping: Shaping, function justifyLine(positionedGlyphs: Array, 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]; @@ -877,7 +876,6 @@ function justifyLine(positionedGlyphs: Array, for (let j = start; j <= end; j++) { positionedGlyphs[j].x -= lineIndent; - positionedGlyphs[j].y += lineOffset; } } From 08ff66410e2ba1421ddf0453ab97a2afa9f1970b Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 11 Nov 2024 17:37:50 +0100 Subject: [PATCH 26/27] fix only images case --- src/symbol/shaping.ts | 70 ++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 3f6b8bd2bd..8a9d4b9ede 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -187,6 +187,22 @@ class TaggedString { 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, section.verticalAlign)); @@ -591,52 +607,15 @@ function getAnchorAlignment(anchor: SymbolAnchor) { } function calculateLineContentSize( - glyphMap: { - [_: string]: { - [_: number]: StyleGlyph; - }; - }, glyphPositions: { - [_: string]: { - [_: number]: GlyphPosition; - }; - }, imagePositions: {[_: string]: ImagePosition}, line: TaggedString, layoutTextSizeFactor: number ) { - let maxGlyphSize = 0; - let maxImageHeight = 0; - let maxImageWidth = 0; - - for (let i = 0; i < line.length(); i++) { - const section = line.getSection(i); - - if (section.imageName) { - const imagePosition = imagePositions[section.imageName]; - if (!imagePosition) continue; - maxImageHeight = Math.max( - maxImageHeight, - imagePosition.displaySize[1] * layoutTextSizeFactor - ); - maxImageWidth = Math.max( - maxImageWidth, - imagePosition.displaySize[0] * layoutTextSizeFactor - ); - } else { - const codePoint = line.getCharCode(i); - const positions = glyphPositions[section.fontStack]; - const glyphPosition = positions && positions[codePoint]; - const rectAndMetrics = getRectAndMetrics(glyphPosition, glyphMap, section, codePoint); - if (rectAndMetrics === null) continue; - maxGlyphSize = Math.max( - maxGlyphSize, - ONE_EM * section.scale - ); - } - } + const maxGlyphSize = line.getMaxScale() * ONE_EM; + const {maxImageWidth, maxImageHeight} = line.getMaxImageSize(imagePositions); - const lineContentHeight = Math.max(maxGlyphSize, maxImageHeight); - const lineContentWidth = Math.max(maxGlyphSize, maxImageWidth); + const lineContentHeight = Math.max(maxGlyphSize, maxImageHeight * layoutTextSizeFactor); + const lineContentWidth = Math.max(maxGlyphSize, maxImageWidth * layoutTextSizeFactor); return {lineContentWidth, lineContentHeight}; } @@ -726,13 +705,8 @@ function shapeLines(shaping: Shaping, continue; } - const {lineContentWidth, lineContentHeight} = calculateLineContentSize( - glyphMap, - glyphPositions, - imagePositions, - line, - layoutTextSizeFactor - ); + const {lineContentWidth, lineContentHeight} = + calculateLineContentSize(imagePositions, line, layoutTextSizeFactor); for (let i = 0; i < line.length(); i++) { const section = line.getSection(i); From e0030d9a44d7d90c803793f33203a066ccb001ba Mon Sep 17 00:00:00 2001 From: Stanislaw Puda Date: Mon, 11 Nov 2024 21:56:14 +0100 Subject: [PATCH 27/27] cleaning + update render tests --- src/symbol/shaping.ts | 38 +++++++----------- .../expected.png | Bin 21991 -> 22956 bytes .../formatted-vertical-align/expected.png | Bin 22919 -> 24116 bytes 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 8a9d4b9ede..2d6b17e2d0 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -712,6 +712,7 @@ function shapeLines(shaping: Shaping, const section = line.getSection(i); const sectionIndex = line.getSectionIndex(i); const codePoint = line.getCharCode(i); + let baselineOffset = 0.0; let metrics: GlyphMetrics | null = null; let rect = null; @@ -776,34 +777,23 @@ function shapeLines(shaping: Shaping, } } + 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 + SHAPING_DEFAULT_OFFSET, - 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 + SHAPING_DEFAULT_OFFSET, - vertical, - scale: section.scale, - fontStack: section.fontStack, - sectionIndex, - metrics, - rect - }); x += verticalAdvance * section.scale + spacing; } } diff --git a/test/integration/render/tests/text-field/formatted-vertical-align-line/expected.png b/test/integration/render/tests/text-field/formatted-vertical-align-line/expected.png index 9b00fff2309189ecea8febde58a1bbbc53d6b939..c71e6155a377e31eb10179a7fdb9bcaa505d8c08 100644 GIT binary patch literal 22956 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 Dr9R!D diff --git a/test/integration/render/tests/text-field/formatted-vertical-align/expected.png b/test/integration/render/tests/text-field/formatted-vertical-align/expected.png index 6041666a95f37ba0f8b1ab9bd6c4ef5b6a1f6f3b..30bcbbcb1a482c9d78651eda835bf952b824ac76 100644 GIT binary patch literal 24116 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 Ld3(~_BeMS+2`FO) literal 22919 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 O#8o?2+omi2DgOo+(ar_{