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

Commit

Permalink
[core] Change font's baseline value to the midline of the font fase.
Browse files Browse the repository at this point in the history
  • Loading branch information
zmiao committed Sep 24, 2019
1 parent 21e65d7 commit 0808ad6
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/mbgl/text/glyph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
15 changes: 9 additions & 6 deletions src/mbgl/text/quads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -115,23 +115,26 @@ 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
// 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.

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;
Expand Down
44 changes: 36 additions & 8 deletions src/mbgl/text/shaping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 0808ad6

Please sign in to comment.