@@ -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