@@ -328,11 +328,34 @@ void shapeLines(Shaping& shaping,
328328 float x = 0 ;
329329 float y = 0 ;
330330 float maxLineLength = 0 ;
331+ bool hasBaseline{false };
332+
333+ for (std::size_t i = 0 ; i < lines.size (); ++i) {
334+ TaggedString& line = lines[i];
335+ line.trim ();
336+ for (std::size_t j = 0 ; j < line.length (); ++j) {
337+ const std::size_t sectionIndex = line.getSectionIndex (j);
338+ const SectionOptions& section = line.sectionAt (sectionIndex);
339+ char16_t codePoint = line.getCharCodeAt (i);
340+ auto glyphs = glyphMap.find (section.fontStackHash );
341+ if (glyphs == glyphMap.end ()) {
342+ continue ;
343+ }
344+ auto it = glyphs->second .find (codePoint);
345+ if (it == glyphs->second .end () || !it->second ) {
346+ continue ;
347+ }
348+ const Glyph& glyph = **it->second ;
349+ hasBaseline = glyph.metrics .ascender != 0 && glyph.metrics .descender != 0 ;
350+ if (!hasBaseline) break ;
351+ }
352+ if (!hasBaseline) break ;
353+ }
331354
332355 const float justify = textJustify == style::TextJustifyType::Right ? 1 :
333356 textJustify == style::TextJustifyType::Left ? 0 :
334357 0.5 ;
335-
358+
336359 for (TaggedString& line : lines) {
337360 // Collapse whitespace so it doesn't throw off justification
338361 line.trim ();
@@ -360,13 +383,17 @@ void shapeLines(Shaping& shaping,
360383
361384 const Glyph& glyph = **it->second ;
362385
363- // Each glyph's baseline is starting from its acsender, which is the vertical distance
364- // from the horizontal baseline to the highest ‘character’ coordinate in a font face.
365- // Since we're laying out at 24 points, we need also calculate how much it will move
366- // when we scale up or down.
367- const bool hasBaseline = glyph.metrics .ascender != 0 && glyph.metrics .descender != 0 ;
368- const double baselineOffset = (hasBaseline ? (-glyph.metrics .ascender * section.scale ) : shaping.yOffset ) +
369- (lineMaxScale - section.scale ) * util::ONE_EM;
386+ // In order to make different fonts aligned, they must share a general baseline that starts from the midline
387+ // of each font face. Baseline offset is the vertical distance from font face's baseline to its top most
388+ // position, which is the half size of the sum (ascender + descender). Since glyph's position is counted
389+ // from the top left corner, the negative shift is needed. So different fonts shares the same baseline but
390+ // with different offset shift. If font's baseline is not applicable, fall back to use a default baseline
391+ // offset, see shaping.yOffset. Since we're laying out at 24 points, we need also calculate how much it will
392+ // move when we scale up or down.
393+ const double baselineOffset =
394+ (hasBaseline ? ((-glyph.metrics .ascender + glyph.metrics .descender ) / 2 * section.scale )
395+ : shaping.yOffset ) +
396+ (lineMaxScale - section.scale ) * util::ONE_EM;
370397
371398 if (writingMode == WritingModeType::Horizontal ||
372399 // Don't verticalize glyphs that have no upright orientation if vertical placement is disabled.
@@ -407,6 +434,7 @@ void shapeLines(Shaping& shaping,
407434 shaping.bottom = shaping.top + height;
408435 shaping.left += -anchorAlign.horizontalAlign * maxLineLength;
409436 shaping.right = shaping.left + maxLineLength;
437+ shaping.hasBaseline = hasBaseline;
410438}
411439
412440const Shaping getShaping (const TaggedString& formattedString,
0 commit comments