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

Commit 70942a2

Browse files
committed
[core] Change font's baseline value to the midline of the font fase.
1 parent 1cdd0bd commit 70942a2

File tree

3 files changed

+46
-14
lines changed

3 files changed

+46
-14
lines changed

src/mbgl/text/glyph.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class Shaping {
9494
explicit operator bool() const { return !positionedGlyphs.empty(); }
9595
// The y offset *should* be part of the font metadata.
9696
static constexpr int32_t yOffset = -17;
97+
bool hasBaseline{false};
9798
};
9899

99100
enum class WritingModeType : uint8_t {

src/mbgl/text/quads.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText,
8080
const GlyphPosition& glyph = positionsIt->second;
8181
const Rect<uint16_t>& rect = glyph.rect;
8282

83-
// The rects have an addditional buffer that is not included in their size;
83+
// The rects have an additional buffer that is not included in their size;
8484
const float glyphPadding = 1.0f;
8585
const float rectBuffer = 3.0f + glyphPadding;
8686

@@ -115,23 +115,26 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText,
115115

116116
if (rotateVerticalGlyph) {
117117
// Vertical-supporting glyphs are laid out in 24x24 point boxes (1 square em)
118-
// In horizontal orientation, the y values for glyphs are below the midline
119-
// and we use a "yOffset" of -17 to pull them up to the middle.
118+
// In horizontal orientation, the y values for glyphs are below the midline.
119+
// If the glyph's baseline is applicable, we take the value of the baseline offset.
120+
// Otherwise, we use a "yOffset" of -17 to pull them up to the middle.
120121
// By rotating counter-clockwise around the point at the center of the left
121122
// edge of a 24x24 layout box centered below the midline, we align the center
122123
// of the glyphs with the horizontal midline, so the yOffset is no longer
123124
// necessary, but we also pull the glyph to the left along the x axis.
124125
// The y coordinate includes baseline yOffset, therefore, needs to be accounted
125126
// for when glyph is rotated and translated.
126127

127-
const Point<float> center{ -halfAdvance, halfAdvance - Shaping::yOffset };
128+
float yShift =
129+
shapedText.hasBaseline ? (-glyph.metrics.ascender + glyph.metrics.descender) / 2 : Shaping::yOffset;
130+
const Point<float> center{-halfAdvance, halfAdvance - yShift};
128131
const float verticalRotation = -M_PI_2;
129132

130133
// xHalfWidhtOffsetcorrection is a difference between full-width and half-width
131134
// advance, should be 0 for full-width glyphs and will pull up half-width glyphs.
132135
const float xHalfWidhtOffsetcorrection = util::ONE_EM / 2 - halfAdvance;
133-
const Point<float> xOffsetCorrection{ 5.0f - Shaping::yOffset - xHalfWidhtOffsetcorrection, 0.0f };
134-
136+
const Point<float> xOffsetCorrection{5.0f - yShift - xHalfWidhtOffsetcorrection, 0.0f};
137+
135138
tl = util::rotate(tl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
136139
tr = util::rotate(tr - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
137140
bl = util::rotate(bl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;

src/mbgl/text/shaping.cpp

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

412440
const Shaping getShaping(const TaggedString& formattedString,

0 commit comments

Comments
 (0)