summaryrefslogtreecommitdiff
path: root/src/mbgl/text/quads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/text/quads.cpp')
-rw-r--r--src/mbgl/text/quads.cpp182
1 files changed, 98 insertions, 84 deletions
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index a94bfee336..ee17510c35 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -20,7 +20,7 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
// If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual
// pixels. The quad needs to be padded to account for this, otherwise they'll look slightly clipped
// on one edge in some cases.
- constexpr const float border = 1.0f;
+ const float border = ImagePosition::padding;
// Expand the box to respect the 1 pixel border in the atlas image. We're using `image.paddedRect - border`
// instead of image.displaySize because we only pad with one pixel for retina images as well, and the
@@ -77,96 +77,110 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText,
const std::array<float, 2> textOffset,
const SymbolLayoutProperties::Evaluated& layout,
const style::SymbolPlacementType placement,
- const GlyphPositions& positions,
+ const ImageMap& imageMap,
bool allowVerticalPlacement) {
const float textRotate = layout.get<TextRotate>() * util::DEG2RAD;
const bool alongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && placement != SymbolPlacementType::Point;
SymbolQuads quads;
- for (const PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs) {
- auto fontPositions = positions.find(positionedGlyph.font);
- if (fontPositions == positions.end())
- continue;
-
- auto positionsIt = fontPositions->second.find(positionedGlyph.glyph);
- if (positionsIt == fontPositions->second.end())
- continue;
-
- 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;
- const float glyphPadding = 1.0f;
- const float rectBuffer = 3.0f + glyphPadding;
-
- const float halfAdvance = glyph.metrics.advance * positionedGlyph.scale / 2.0;
-
- const Point<float> glyphOffset = alongLine ?
- Point<float>{ positionedGlyph.x + halfAdvance, positionedGlyph.y } :
- Point<float>{ 0.0f, 0.0f };
-
- Point<float> builtInOffset = alongLine ?
- Point<float>{ 0.0f, 0.0f } :
- Point<float>{ positionedGlyph.x + halfAdvance + textOffset[0], positionedGlyph.y + textOffset[1] };
-
- Point<float> verticalizedLabelOffset = { 0.0f, 0.0f };
- const bool rotateVerticalGlyph = (alongLine || allowVerticalPlacement) && positionedGlyph.vertical;
- if (rotateVerticalGlyph) {
- // Vertical POI labels, that are rotated 90deg CW and whose glyphs must preserve upright orientation
- // need to be rotated 90deg CCW. After quad is rotated, it is translated to the original built-in offset.
- verticalizedLabelOffset = builtInOffset;
- builtInOffset = { 0.0f, 0.0f };
+ for (const auto& line : shapedText.positionedLines) {
+ for (const auto& positionedGlyph : line.positionedGlyphs) {
+ if (!positionedGlyph.rect.hasArea()) continue;
+
+ // The rects have an addditional buffer that is not included in their size;
+ const float glyphPadding = 1.0f;
+ float rectBuffer = 3.0f + glyphPadding;
+ float pixelRatio = 1.0f;
+ float lineOffset = 0.0f;
+ const bool rotateVerticalGlyph = (alongLine || allowVerticalPlacement) && positionedGlyph.vertical;
+ const float halfAdvance = positionedGlyph.metrics.advance * positionedGlyph.scale / 2.0;
+ const Rect<uint16_t>& rect = positionedGlyph.rect;
+
+ // Align images and scaled glyphs in the middle of a vertical line.
+ if (allowVerticalPlacement && shapedText.verticalizable) {
+ const float scaledGlyphOffset = (positionedGlyph.scale - 1) * util::ONE_EM;
+ const float imageOffset = (util::ONE_EM - positionedGlyph.metrics.width * positionedGlyph.scale) / 2.0f;
+ lineOffset = line.lineOffset / 2.0f - (positionedGlyph.imageID ? -imageOffset : scaledGlyphOffset);
+ }
+
+ if (positionedGlyph.imageID) {
+ auto image = imageMap.find(*positionedGlyph.imageID);
+ if (image == imageMap.end()) {
+ continue;
+ }
+ pixelRatio = image->second->pixelRatio;
+ rectBuffer = ImagePosition::padding / pixelRatio;
+ }
+
+ const Point<float> glyphOffset =
+ alongLine ? Point<float>{positionedGlyph.x + halfAdvance, positionedGlyph.y} : Point<float>{0.0f, 0.0f};
+
+ Point<float> builtInOffset = alongLine ? Point<float>{0.0f, 0.0f}
+ : Point<float>{positionedGlyph.x + halfAdvance + textOffset[0],
+ positionedGlyph.y + textOffset[1] - lineOffset};
+
+ Point<float> verticalizedLabelOffset = {0.0f, 0.0f};
+ if (rotateVerticalGlyph) {
+ // Vertical POI labels, that are rotated 90deg CW and whose glyphs must preserve upright orientation
+ // need to be rotated 90deg CCW. After quad is rotated, it is translated to the original built-in
+ // offset.
+ verticalizedLabelOffset = builtInOffset;
+ builtInOffset = {0.0f, 0.0f};
+ }
+
+ const float x1 =
+ (positionedGlyph.metrics.left - rectBuffer) * positionedGlyph.scale - halfAdvance + builtInOffset.x;
+ const float y1 = (-positionedGlyph.metrics.top - rectBuffer) * positionedGlyph.scale + builtInOffset.y;
+ const float x2 = x1 + rect.w * positionedGlyph.scale / pixelRatio;
+ const float y2 = y1 + rect.h * positionedGlyph.scale / pixelRatio;
+
+ Point<float> tl{x1, y1};
+ Point<float> tr{x2, y1};
+ Point<float> bl{x1, y2};
+ Point<float> br{x2, y2};
+
+ 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.
+ // 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};
+ 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 float yImageOffsetCorrection = positionedGlyph.imageID ? xHalfWidhtOffsetcorrection : 0.0f;
+ const Point<float> xOffsetCorrection{5.0f - Shaping::yOffset - xHalfWidhtOffsetcorrection,
+ -yImageOffsetCorrection};
+
+ 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;
+ br = util::rotate(br - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
+ }
+
+ if (textRotate) {
+ // Compute the transformation matrix.
+ float angle_sin = std::sin(textRotate);
+ float angle_cos = std::cos(textRotate);
+ std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
+
+ tl = util::matrixMultiply(matrix, tl);
+ tr = util::matrixMultiply(matrix, tr);
+ bl = util::matrixMultiply(matrix, bl);
+ br = util::matrixMultiply(matrix, br);
+ }
+
+ quads.emplace_back(tl, tr, bl, br, rect, shapedText.writingMode, glyphOffset, positionedGlyph.sectionIndex);
}
-
- const float x1 = (glyph.metrics.left - rectBuffer) * positionedGlyph.scale - halfAdvance + builtInOffset.x;
- const float y1 = (-glyph.metrics.top - rectBuffer) * positionedGlyph.scale + builtInOffset.y;
- const float x2 = x1 + rect.w * positionedGlyph.scale;
- const float y2 = y1 + rect.h * positionedGlyph.scale;
-
- Point<float> tl{x1, y1};
- Point<float> tr{x2, y1};
- Point<float> bl{x1, y2};
- Point<float> br{x2, y2};
-
- 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.
- // 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 };
- 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 };
-
- 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;
- br = util::rotate(br - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
- }
-
- if (textRotate) {
- // Compute the transformation matrix.
- float angle_sin = std::sin(textRotate);
- float angle_cos = std::cos(textRotate);
- std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
-
- tl = util::matrixMultiply(matrix, tl);
- tr = util::matrixMultiply(matrix, tr);
- bl = util::matrixMultiply(matrix, bl);
- br = util::matrixMultiply(matrix, br);
- }
-
- quads.emplace_back(tl, tr, bl, br, rect, shapedText.writingMode, glyphOffset, positionedGlyph.sectionIndex);
}
return quads;