Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

Commit 8a5a1e1

Browse files
committed
[core] Make text's baseline locating on the general virtual baseline.
1 parent 43d132b commit 8a5a1e1

File tree

2 files changed

+38
-29
lines changed

2 files changed

+38
-29
lines changed

src/mbgl/text/quads.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,22 +117,15 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText,
117117
if (rotateVerticalGlyph) {
118118
// Vertical-supporting glyphs are laid out in 24x24 point boxes (1 square em)
119119
// In horizontal orientation, the y values for glyphs are below the midline.
120-
// If the glyph's baseline is applicable, we take the value of the baseline offset.
120+
// If the glyph's baseline is applicable, we take the y value of the glyph.
121121
// Otherwise, we use a "yOffset" of -17 to pull them up to the middle.
122122
// By rotating counter-clockwise around the point at the center of the left
123123
// edge of a 24x24 layout box centered below the midline, we align the center
124124
// of the glyphs with the horizontal midline, so the yOffset is no longer
125125
// necessary, but we also pull the glyph to the left along the x axis.
126126
// The y coordinate includes baseline yOffset, therefore, needs to be accounted
127127
// for when glyph is rotated and translated.
128-
if (shapedText.hasBaseline) {
129-
assert(fontPositions->second.ascender && fontPositions->second.descender);
130-
}
131-
const float yShift =
132-
(shapedText.hasBaseline
133-
? ((-(fontPositions->second.ascender.value()) + fontPositions->second.descender.value()) / 2.0 *
134-
positionedGlyph.scale)
135-
: Shaping::yOffset);
128+
const float yShift = (shapedText.hasBaseline ? positionedGlyph.y : Shaping::yOffset);
136129
const Point<float> center{-halfAdvance, halfAdvance - yShift};
137130
const float verticalRotation = -M_PI_2;
138131

src/mbgl/text/shaping.cpp

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,12 @@ void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs,
134134
const GlyphMap& glyphMap,
135135
std::size_t start,
136136
std::size_t end,
137-
float justify) {
138-
if (!justify) {
137+
float justify,
138+
float baselineOffset) {
139+
if (!justify && !baselineOffset) {
139140
return;
140141
}
141-
142+
142143
PositionedGlyph& glyph = positionedGlyphs[end];
143144
auto glyphs = glyphMap.find(glyph.font);
144145
if (glyphs == glyphMap.end()) {
@@ -151,6 +152,7 @@ void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs,
151152

152153
for (std::size_t j = start; j <= end; j++) {
153154
positionedGlyphs[j].x -= lineIndent;
155+
positionedGlyphs[j].y += baselineOffset;
154156
}
155157
}
156158
}
@@ -358,6 +360,7 @@ void shapeLines(Shaping& shaping,
358360
continue;
359361
}
360362

363+
float biggestHeight{0}, baselineOffset{0};
361364
std::size_t lineStartIndex = shaping.positionedGlyphs.size();
362365
for (std::size_t i = 0; i < line.length(); i++) {
363366
const std::size_t sectionIndex = line.getSectionIndex(i);
@@ -374,21 +377,29 @@ void shapeLines(Shaping& shaping,
374377

375378
const Glyph& glyph = **it->second;
376379

377-
// In order to make different fonts aligned, they must share a general baseline that starts from the midline
378-
// of each font face. Baseline offset is the vertical distance from font face's baseline to its top most
379-
// position, which is the half size of the sum (ascender + descender). Since glyph's position is counted
380-
// from the top left corner, the negative shift is needed. So different fonts share the same baseline but
381-
// with different offset shift. If font's baseline is not applicable, fall back to use a default baseline
382-
// offset, see shaping.yOffset. Since we're laying out at 24 points, we need also calculate how much it will
383-
// move when we scale up or down.
380+
double ascender{0}, descender{0}, glyphOffset{0};
381+
// In order to make different fonts aligned, they must share a general baseline that aligns with every
382+
// font's real baseline. Glyph's position is counted from the top left corner, where is the ascender line
383+
// starts. Since ascender is above the baseline, the glyphOffset is the negative shift. In order to make all
384+
// the glyphs aligned with shaping box, for each line, we lock the heighest glyph (with scale) locating
385+
// at the middle of the line, which will lead to a baseline shift. Then adjust the whole line with the
386+
// baseline offset we calculated from the shift.
384387
if (hasBaseline) {
385388
assert(glyphs->second.ascender && glyphs->second.descender);
389+
ascender = std::abs(glyphs->second.ascender.value());
390+
descender = std::abs(glyphs->second.descender.value());
391+
auto value = (ascender + descender) * section.scale;
392+
if (biggestHeight < value) {
393+
biggestHeight = value;
394+
baselineOffset = (ascender - descender) / 2 * section.scale;
395+
}
396+
glyphOffset = -ascender * section.scale;
397+
} else {
398+
// If font's baseline is not applicable, fall back to use a default baseline
399+
// offset, see shaping.yOffset. Since we're laying out at 24 points, we need also calculate how much it
400+
// will move when we scale up or down.
401+
glyphOffset = Shaping::yOffset + (lineMaxScale - section.scale) * util::ONE_EM;
386402
}
387-
const float baselineOffset =
388-
(hasBaseline
389-
? ((-(glyphs->second.ascender.value()) + glyphs->second.descender.value()) / 2.0 * section.scale)
390-
: shaping.yOffset) +
391-
(lineMaxScale - section.scale) * util::ONE_EM;
392403

393404
if (writingMode == WritingModeType::Horizontal ||
394405
// Don't verticalize glyphs that have no upright orientation if vertical placement is disabled.
@@ -398,10 +409,11 @@ void shapeLines(Shaping& shaping,
398409
(allowVerticalPlacement &&
399410
(util::i18n::isWhitespace(codePoint) || util::i18n::isCharInComplexShapingScript(codePoint)))) {
400411
shaping.positionedGlyphs.emplace_back(
401-
codePoint, x, y + baselineOffset, false, section.fontStackHash, section.scale, sectionIndex);
412+
codePoint, x, y + glyphOffset, false, section.fontStackHash, section.scale, sectionIndex);
402413
x += glyph.metrics.advance * section.scale + spacing;
403414
} else {
404-
shaping.positionedGlyphs.emplace_back(codePoint, x, y + baselineOffset, true, section.fontStackHash, section.scale, sectionIndex);
415+
shaping.positionedGlyphs.emplace_back(
416+
codePoint, x, y + glyphOffset, true, section.fontStackHash, section.scale, sectionIndex);
405417
x += util::ONE_EM * section.scale + spacing;
406418
}
407419
}
@@ -410,9 +422,13 @@ void shapeLines(Shaping& shaping,
410422
if (shaping.positionedGlyphs.size() != lineStartIndex) {
411423
float lineLength = x - spacing; // Don't count trailing spacing
412424
maxLineLength = util::max(lineLength, maxLineLength);
413-
414-
justifyLine(shaping.positionedGlyphs, glyphMap, lineStartIndex,
415-
shaping.positionedGlyphs.size() - 1, justify);
425+
426+
justifyLine(shaping.positionedGlyphs,
427+
glyphMap,
428+
lineStartIndex,
429+
shaping.positionedGlyphs.size() - 1,
430+
justify,
431+
baselineOffset);
416432
}
417433

418434
x = 0;

0 commit comments

Comments
 (0)