diff options
Diffstat (limited to 'src/mbgl/layout')
-rw-r--r-- | src/mbgl/layout/symbol_feature.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_instance.cpp | 17 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_instance.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_layout.cpp | 57 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_layout.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_projection.cpp | 6 |
6 files changed, 74 insertions, 16 deletions
diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp index ed9c0783d0..03d8e5018d 100644 --- a/src/mbgl/layout/symbol_feature.hpp +++ b/src/mbgl/layout/symbol_feature.hpp @@ -32,6 +32,7 @@ public: optional<std::string> icon; float sortKey = 0.0f; std::size_t index; + bool allowsVerticalWritingMode = false; }; } // namespace mbgl diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index 133cdec698..8e8286bbd7 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -25,7 +25,8 @@ SymbolInstanceSharedData::SymbolInstanceSharedData(GeometryCoordinates line_, const float layoutTextSize, const style::SymbolPlacementType textPlacement, const std::array<float, 2>& textOffset, - const GlyphPositions& positions) : line(std::move(line_)) { + const GlyphPositions& positions, + bool allowVerticalPlacement) : line(std::move(line_)) { // Create the quads used for rendering the icon and glyphs. if (shapedIcon) { iconQuad = getIconQuad(*shapedIcon, layout, layoutTextSize, shapedTextOrientations.horizontal); @@ -34,11 +35,11 @@ SymbolInstanceSharedData::SymbolInstanceSharedData(GeometryCoordinates line_, bool singleLineInitialized = false; const auto initHorizontalGlyphQuads = [&] (SymbolQuads& quads, const Shaping& shaping) { if (!shapedTextOrientations.singleLine) { - quads = getGlyphQuads(shaping, textOffset, layout, textPlacement, positions); + quads = getGlyphQuads(shaping, textOffset, layout, textPlacement, positions, allowVerticalPlacement); return; } if (!singleLineInitialized) { - rightJustifiedGlyphQuads = getGlyphQuads(shaping, textOffset, layout, textPlacement, positions); + rightJustifiedGlyphQuads = getGlyphQuads(shaping, textOffset, layout, textPlacement, positions, allowVerticalPlacement); singleLineInitialized = true; } }; @@ -56,7 +57,7 @@ SymbolInstanceSharedData::SymbolInstanceSharedData(GeometryCoordinates line_, } if (shapedTextOrientations.vertical) { - verticalGlyphQuads = getGlyphQuads(shapedTextOrientations.vertical, textOffset, layout, textPlacement, positions); + verticalGlyphQuads = getGlyphQuads(shapedTextOrientations.vertical, textOffset, layout, textPlacement, positions, allowVerticalPlacement); } } @@ -81,7 +82,8 @@ SymbolInstance::SymbolInstance(Anchor& anchor_, std::u16string key_, const float overscaling, const float rotate, - float radialTextOffset_) : + float radialTextOffset_, + bool allowVerticalPlacement) : sharedData(std::move(sharedData_)), anchor(anchor_), // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap @@ -101,6 +103,11 @@ SymbolInstance::SymbolInstance(Anchor& anchor_, radialTextOffset(radialTextOffset_), singleLine(shapedTextOrientations.singleLine) { + if (allowVerticalPlacement && shapedTextOrientations.vertical) { + const float verticalPointLabelAngle = 90.0f; + verticalTextCollisionFeature = CollisionFeature(line(), anchor, shapedTextOrientations.vertical, textBoxScale_, textPadding, textPlacement, indexedFeature, overscaling, rotate + verticalPointLabelAngle); + } + rightJustifiedGlyphQuadsSize = sharedData->rightJustifiedGlyphQuads.size(); centerJustifiedGlyphQuadsSize = sharedData->centerJustifiedGlyphQuads.size(); leftJustifiedGlyphQuadsSize = sharedData->leftJustifiedGlyphQuads.size(); diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 48bb2f0cbc..693d8917c7 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -29,7 +29,8 @@ struct SymbolInstanceSharedData { const float layoutTextSize, const style::SymbolPlacementType textPlacement, const std::array<float, 2>& textOffset, - const GlyphPositions& positions); + const GlyphPositions& positions, + bool allowVerticalPlacement); bool empty() const; GeometryCoordinates line; // Note: When singleLine == true, only `rightJustifiedGlyphQuads` is populated. @@ -59,7 +60,8 @@ public: std::u16string key, const float overscaling, const float rotate, - float radialTextOffset); + float radialTextOffset, + bool allowVerticalPlacement); optional<size_t> getDefaultHorizontalPlacedTextIndex() const; const GeometryCoordinates& line() const; @@ -85,6 +87,7 @@ public: CollisionFeature textCollisionFeature; CollisionFeature iconCollisionFeature; + optional<CollisionFeature> verticalTextCollisionFeature = nullopt; WritingModeType writingModes; std::size_t layoutFeatureIndex; // Index into the set of features included at layout time std::size_t dataFeatureIndex; // Index into the underlying tile data feature set diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index d269ca4144..be6444bb16 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -109,6 +109,19 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, const bool zOrderByViewportY = symbolZOrder == SymbolZOrderType::ViewportY || (symbolZOrder == SymbolZOrderType::Auto && !sortFeaturesByKey); sortFeaturesByY = zOrderByViewportY && (layout->get<TextAllowOverlap>() || layout->get<IconAllowOverlap>() || layout->get<TextIgnorePlacement>() || layout->get<IconIgnorePlacement>()); + if (layout->get<SymbolPlacement>() == SymbolPlacementType::Point) { + auto modes = layout->get<TextWritingMode>(); + // Remove duplicates and preserve order. + std::set<style::TextWritingModeType> seen; + auto end = std::remove_if(modes.begin(), + modes.end(), + [&seen, this](const auto& placementMode) { + allowVerticalPlacement = allowVerticalPlacement || placementMode == style::TextWritingModeType::Vertical; + return !seen.insert(placementMode).second; + }); + modes.erase(end, modes.end()); + placementModes = std::move(modes); + } for (const auto& layer : layers) { layerPaintProperties.emplace(layer->baseImpl->id, layer); @@ -148,7 +161,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, const bool canVerticalizeText = layout->get<TextRotationAlignment>() == AlignmentType::Map && layout->get<SymbolPlacement>() != SymbolPlacementType::Point - && util::i18n::allowsVerticalWritingMode(ft.formattedText->rawText()); + && ft.formattedText->allowsVerticalWritingMode(); // Loop through all characters of this text and collect unique codepoints. for (std::size_t j = 0; j < ft.formattedText->length(); j++) { @@ -156,7 +169,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, GlyphIDs& dependencies = glyphDependencies[sectionFontStack ? *sectionFontStack : baseFontStack]; char16_t codePoint = ft.formattedText->getCharCodeAt(j); dependencies.insert(codePoint); - if (canVerticalizeText) { + if (canVerticalizeText || (allowVerticalPlacement && ft.formattedText->allowsVerticalWritingMode())) { if (char16_t verticalChr = util::i18n::verticalizePunctuation(codePoint)) { dependencies.insert(verticalChr); } @@ -321,7 +334,18 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions } } TextJustifyType textJustify = textAlongLine ? TextJustifyType::Center : layout->evaluate<TextJustify>(zoom, feature); - // If this layer uses text-variable-anchor, generate shapings for all justification possibilities. + + const auto addVerticalShapingForPointLabelIfNeeded = [&] { + if (allowVerticalPlacement && feature.formattedText->allowsVerticalWritingMode()) { + feature.formattedText->verticalizePunctuation(); + // Vertical POI label placement is meant to be used for scripts that support vertical + // writing mode, thus, default style::TextJustifyType::Left justification is used. If Latin + // scripts would need to be supported, this should take into account other justifications. + shapedTextOrientations.vertical = applyShaping(*feature.formattedText, WritingModeType::Vertical, textAnchor, style::TextJustifyType::Left); + } + }; + + // If this layer uses text-variable-anchor, generate shapings for all justification possibilities. if (!textAlongLine && !variableTextAnchor.empty()) { std::vector<TextJustifyType> justifications; if (textJustify != TextJustifyType::Auto) { @@ -347,16 +371,25 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions } } } + + // Vertical point label shaping if allowVerticalPlacement is enabled. + addVerticalShapingForPointLabelIfNeeded(); } else { if (textJustify == TextJustifyType::Auto) { textJustify = getAnchorJustification(textAnchor); } + + // Horizontal point or line label. Shaping shaping = applyShaping(*feature.formattedText, WritingModeType::Horizontal, textAnchor, textJustify); if (shaping) { shapedTextOrientations.horizontal = std::move(shaping); } - if (util::i18n::allowsVerticalWritingMode(feature.formattedText->rawText()) && textAlongLine) { + // Vertical point label shaping if allowVerticalPlacement is enabled. + addVerticalShapingForPointLabelIfNeeded(); + + // Verticalized line label. + if (textAlongLine && feature.formattedText->allowsVerticalWritingMode()) { feature.formattedText->verticalizePunctuation(); shapedTextOrientations.vertical = applyShaping(*feature.formattedText, WritingModeType::Vertical, textAnchor, textJustify); } @@ -423,7 +456,8 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const float textPadding = layout->get<TextPadding>() * tilePixelRatio; const float iconPadding = layout->get<IconPadding>() * tilePixelRatio; const float textMaxAngle = layout->get<TextMaxAngle>() * util::DEG2RAD; - const float rotation = layout->evaluate<IconRotate>(zoom, feature); + const float iconRotation = layout->evaluate<IconRotate>(zoom, feature); + const float textRotation = layout->evaluate<TextRotate>(zoom, feature); const float radialTextOffset = layout->evaluate<TextRadialOffset>(zoom, feature) * util::ONE_EM; const SymbolPlacementType textPlacement = layout->get<TextRotationAlignment>() != AlignmentType::Map ? SymbolPlacementType::Point @@ -448,14 +482,14 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, iconBoxScale, iconPadding, iconOffset, indexedFeature, layoutFeatureIndex, feature.index, feature.formattedText ? feature.formattedText->rawText() : std::u16string(), - overscaling, rotation, radialTextOffset); + overscaling, iconRotation, textRotation, radialTextOffset, allowVerticalPlacement); } }; const auto createSymbolInstanceSharedData = [&] (GeometryCoordinates line) { return std::make_shared<SymbolInstanceSharedData>(std::move(line), shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize, - textPlacement, textOffset, glyphPositions); + textPlacement, textOffset, glyphPositions, allowVerticalPlacement); }; const auto& type = feature.getType(); @@ -568,7 +602,10 @@ std::vector<float> CalculateTileDistances(const GeometryCoordinates& line, const } void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>& renderData, const bool firstLoad, const bool showCollisionBoxes) { - auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio); + auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, + sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio, + allowVerticalPlacement, + std::move(placementModes)); for (SymbolInstance &symbolInstance : bucket->symbolInstances) { const bool hasText = symbolInstance.hasText; @@ -660,6 +697,7 @@ std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket, symbolInstance.textOffset, writingMode, symbolInstance.line(), CalculateTileDistances(symbolInstance.line(), symbolInstance.anchor)); placedIndex = bucket.text.placedSymbols.size() - 1; PlacedSymbol& placedSymbol = bucket.text.placedSymbols.back(); + placedSymbol.angle = (allowVerticalPlacement && writingMode == WritingModeType::Vertical) ? M_PI_2 : 0; bool firstSymbol = true; for (const auto& symbolQuad : glyphQuads) { @@ -795,6 +833,9 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) { } }; populateCollisionBox(symbolInstance.textCollisionFeature); + if (symbolInstance.verticalTextCollisionFeature) { + populateCollisionBox(*symbolInstance.verticalTextCollisionFeature); + } populateCollisionBox(symbolInstance.iconCollisionFeature); } } diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 581c3ccb04..70a3482644 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -96,6 +96,8 @@ private: bool sdfIcons = false; bool iconsNeedLinear = false; bool sortFeaturesByY = false; + bool allowVerticalPlacement = false; + std::vector<style::TextWritingModeType> placementModes; style::TextSize::UnevaluatedType textSize; style::IconSize::UnevaluatedType iconSize; diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp index aeea10ffa4..745c1c1d77 100644 --- a/src/mbgl/layout/symbol_projection.cpp +++ b/src/mbgl/layout/symbol_projection.cpp @@ -319,7 +319,11 @@ namespace mbgl { const float glyphOffsetX = symbol.glyphOffsets[glyphIndex]; // Since first and last glyph fit on the line, we're sure that the rest of the glyphs can be placed auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, projectedAnchorPoint, symbol.anchorPoint, symbol.segment, symbol.line, symbol.tileDistances, labelPlaneMatrix, false); - placedGlyphs.push_back(*placedGlyph); + if (placedGlyph) { + placedGlyphs.push_back(*placedGlyph); + } else { + placedGlyphs.emplace_back(Point<float>{-INFINITY, -INFINITY}, 0.0f, nullopt); + } } placedGlyphs.push_back(firstAndLastGlyph->second); } else if (symbol.glyphOffsets.size() == 1) { |