diff options
author | zmiao <zmiao.jamie@gmail.com> | 2019-09-24 18:56:48 +0300 |
---|---|---|
committer | zmiao <miao.zhao@mapbox.com> | 2019-10-06 19:48:08 +0300 |
commit | 97c6ed20ee00df22dd737498107d656ec3ef7a67 (patch) | |
tree | f8cf6e70115587e727171a1b2c457fc5c4be92fa | |
parent | 54c310f95dec0ed2d972a62a65ef283fce7683a1 (diff) | |
download | qtlocation-mapboxgl-97c6ed20ee00df22dd737498107d656ec3ef7a67.tar.gz |
[core] Change font's baseline value to the midline of the font fase.
-rw-r--r-- | src/mbgl/text/glyph.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/text/quads.cpp | 15 | ||||
-rw-r--r-- | src/mbgl/text/shaping.cpp | 44 |
3 files changed, 46 insertions, 14 deletions
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index 8977f4992a..c56247f205 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -94,6 +94,7 @@ class Shaping { explicit operator bool() const { return !positionedGlyphs.empty(); } // The y offset *should* be part of the font metadata. static constexpr int32_t yOffset = -17; + bool hasBaseline{false}; }; enum class WritingModeType : uint8_t { diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 281c5d99de..c703f331bc 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -80,7 +80,7 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, const GlyphPosition& glyph = positionsIt->second; const Rect<uint16_t>& rect = glyph.rect; - // The rects have an addditional buffer that is not included in their size; + // The rects have an additional buffer that is not included in their size; const float glyphPadding = 1.0f; const float rectBuffer = 3.0f + glyphPadding; @@ -115,8 +115,9 @@ 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 - // and we use a "yOffset" of -17 to pull them up to the middle. + // 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. + // 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 // of the glyphs with the horizontal midline, so the yOffset is no longer @@ -124,14 +125,16 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, // The y coordinate includes baseline yOffset, therefore, needs to be accounted // for when glyph is rotated and translated. - const Point<float> center{ -halfAdvance, halfAdvance - Shaping::yOffset }; + float yShift = + shapedText.hasBaseline ? (-glyph.metrics.ascender + glyph.metrics.descender) / 2 : Shaping::yOffset; + const Point<float> center{-halfAdvance, halfAdvance - yShift}; const float verticalRotation = -M_PI_2; // xHalfWidhtOffsetcorrection is a difference between full-width and half-width // advance, should be 0 for full-width glyphs and will pull up half-width glyphs. const float xHalfWidhtOffsetcorrection = util::ONE_EM / 2 - halfAdvance; - const Point<float> xOffsetCorrection{ 5.0f - Shaping::yOffset - xHalfWidhtOffsetcorrection, 0.0f }; - + const Point<float> xOffsetCorrection{5.0f - yShift - xHalfWidhtOffsetcorrection, 0.0f}; + tl = util::rotate(tl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset; tr = util::rotate(tr - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset; bl = util::rotate(bl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset; diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index d1f70e5173..efcf17873e 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -328,11 +328,34 @@ void shapeLines(Shaping& shaping, float x = 0; float y = 0; float maxLineLength = 0; + bool hasBaseline{false}; + + for (std::size_t i = 0; i < lines.size(); ++i) { + TaggedString& line = lines[i]; + line.trim(); + for (std::size_t j = 0; j < line.length(); ++j) { + const std::size_t sectionIndex = line.getSectionIndex(j); + const SectionOptions& section = line.sectionAt(sectionIndex); + char16_t codePoint = line.getCharCodeAt(i); + auto glyphs = glyphMap.find(section.fontStackHash); + if (glyphs == glyphMap.end()) { + continue; + } + auto it = glyphs->second.find(codePoint); + if (it == glyphs->second.end() || !it->second) { + continue; + } + const Glyph& glyph = **it->second; + hasBaseline = glyph.metrics.ascender != 0 && glyph.metrics.descender != 0; + if (!hasBaseline) break; + } + if (!hasBaseline) break; + } const float justify = textJustify == style::TextJustifyType::Right ? 1 : textJustify == style::TextJustifyType::Left ? 0 : 0.5; - + for (TaggedString& line : lines) { // Collapse whitespace so it doesn't throw off justification line.trim(); @@ -360,13 +383,17 @@ void shapeLines(Shaping& shaping, const Glyph& glyph = **it->second; - // Each glyph's baseline is starting from its acsender, which is the vertical distance - // from the horizontal baseline to the highest ‘character’ coordinate in a font face. - // Since we're laying out at 24 points, we need also calculate how much it will move - // when we scale up or down. - const bool hasBaseline = glyph.metrics.ascender != 0 && glyph.metrics.descender != 0; - const double baselineOffset = (hasBaseline ? (-glyph.metrics.ascender * section.scale) : shaping.yOffset) + - (lineMaxScale - section.scale) * util::ONE_EM; + // 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 shares 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. + const double baselineOffset = + (hasBaseline ? ((-glyph.metrics.ascender + glyph.metrics.descender) / 2 * 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. @@ -407,6 +434,7 @@ void shapeLines(Shaping& shaping, shaping.bottom = shaping.top + height; shaping.left += -anchorAlign.horizontalAlign * maxLineLength; shaping.right = shaping.left + maxLineLength; + shaping.hasBaseline = hasBaseline; } const Shaping getShaping(const TaggedString& formattedString, |