diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 3e3beb29a31..49b43c413ab 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -117,7 +117,7 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, if (rotateVerticalGlyph) { // Vertical-supporting glyphs are laid out in 24x24 point boxes (1 square em) // In horizontal orientation, the y values for glyphs are below the midline. - // If the glyph's baseline is applicable, we take the value of the baseline offset. + // If the glyph's baseline is applicable, we take the y value of the glyph. // Otherwise, we use a "yOffset" of -17 to pull them up to the middle. // By rotating counter-clockwise around the point at the center of the left // edge of a 24x24 layout box centered below the midline, we align the center @@ -125,14 +125,7 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, // necessary, but we also pull the glyph to the left along the x axis. // The y coordinate includes baseline yOffset, therefore, needs to be accounted // for when glyph is rotated and translated. - if (shapedText.hasBaseline) { - assert(fontPositions->second.ascender && fontPositions->second.descender); - } - const float yShift = - (shapedText.hasBaseline - ? ((-(fontPositions->second.ascender.value()) + fontPositions->second.descender.value()) / 2.0 * - positionedGlyph.scale) - : Shaping::yOffset); + const float yShift = (shapedText.hasBaseline ? positionedGlyph.y : Shaping::yOffset); const Point center{-halfAdvance, halfAdvance - yShift}; const float verticalRotation = -M_PI_2; diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index d4a30a3446d..337dd613dd0 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -134,11 +134,12 @@ void justifyLine(std::vector& positionedGlyphs, const GlyphMap& glyphMap, std::size_t start, std::size_t end, - float justify) { - if (!justify) { + float justify, + float baselineOffset) { + if (!justify && !baselineOffset) { return; } - + PositionedGlyph& glyph = positionedGlyphs[end]; auto glyphs = glyphMap.find(glyph.font); if (glyphs == glyphMap.end()) { @@ -151,6 +152,7 @@ void justifyLine(std::vector& positionedGlyphs, for (std::size_t j = start; j <= end; j++) { positionedGlyphs[j].x -= lineIndent; + positionedGlyphs[j].y += baselineOffset; } } } @@ -358,6 +360,7 @@ void shapeLines(Shaping& shaping, continue; } + float biggestHeight{0}, baselineOffset{0}; std::size_t lineStartIndex = shaping.positionedGlyphs.size(); for (std::size_t i = 0; i < line.length(); i++) { const std::size_t sectionIndex = line.getSectionIndex(i); @@ -374,21 +377,29 @@ void shapeLines(Shaping& shaping, const Glyph& glyph = **it->second; - // In order to make different fonts aligned, they must share a general baseline that starts from the midline - // of each font face. Baseline offset is the vertical distance from font face's baseline to its top most - // position, which is the half size of the sum (ascender + descender). Since glyph's position is counted - // from the top left corner, the negative shift is needed. So different fonts share the same baseline but - // with different offset shift. If font's baseline is not applicable, fall back to use a default baseline - // offset, see shaping.yOffset. Since we're laying out at 24 points, we need also calculate how much it will - // move when we scale up or down. + double ascender{0}, descender{0}, glyphOffset{0}; + // In order to make different fonts aligned, they must share a general baseline that aligns with every + // font's real baseline. Glyph's position is counted from the top left corner, where is the ascender line + // starts. Since ascender is above the baseline, the glyphOffset is the negative shift. In order to make all + // the glyphs aligned with shaping box, for each line, we lock the heighest glyph (with scale) locating + // at the middle of the line, which will lead to a baseline shift. Then adjust the whole line with the + // baseline offset we calculated from the shift. if (hasBaseline) { assert(glyphs->second.ascender && glyphs->second.descender); + ascender = std::abs(glyphs->second.ascender.value()); + descender = std::abs(glyphs->second.descender.value()); + auto value = (ascender + descender) * section.scale; + if (biggestHeight < value) { + biggestHeight = value; + baselineOffset = (ascender - descender) / 2 * section.scale; + } + glyphOffset = -ascender * section.scale; + } else { + // If font's baseline is not applicable, fall back to use a default baseline + // offset, see shaping.yOffset. Since we're laying out at 24 points, we need also calculate how much it + // will move when we scale up or down. + glyphOffset = Shaping::yOffset + (lineMaxScale - section.scale) * util::ONE_EM; } - const float baselineOffset = - (hasBaseline - ? ((-(glyphs->second.ascender.value()) + glyphs->second.descender.value()) / 2.0 * section.scale) - : shaping.yOffset) + - (lineMaxScale - section.scale) * util::ONE_EM; if (writingMode == WritingModeType::Horizontal || // Don't verticalize glyphs that have no upright orientation if vertical placement is disabled. @@ -398,10 +409,11 @@ void shapeLines(Shaping& shaping, (allowVerticalPlacement && (util::i18n::isWhitespace(codePoint) || util::i18n::isCharInComplexShapingScript(codePoint)))) { shaping.positionedGlyphs.emplace_back( - codePoint, x, y + baselineOffset, false, section.fontStackHash, section.scale, sectionIndex); + codePoint, x, y + glyphOffset, false, section.fontStackHash, section.scale, sectionIndex); x += glyph.metrics.advance * section.scale + spacing; } else { - shaping.positionedGlyphs.emplace_back(codePoint, x, y + baselineOffset, true, section.fontStackHash, section.scale, sectionIndex); + shaping.positionedGlyphs.emplace_back( + codePoint, x, y + glyphOffset, true, section.fontStackHash, section.scale, sectionIndex); x += util::ONE_EM * section.scale + spacing; } } @@ -410,9 +422,13 @@ void shapeLines(Shaping& shaping, if (shaping.positionedGlyphs.size() != lineStartIndex) { float lineLength = x - spacing; // Don't count trailing spacing maxLineLength = util::max(lineLength, maxLineLength); - - justifyLine(shaping.positionedGlyphs, glyphMap, lineStartIndex, - shaping.positionedGlyphs.size() - 1, justify); + + justifyLine(shaping.positionedGlyphs, + glyphMap, + lineStartIndex, + shaping.positionedGlyphs.size() - 1, + justify, + baselineOffset); } x = 0;