summaryrefslogtreecommitdiff
path: root/src/mbgl/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/layout')
-rw-r--r--src/mbgl/layout/symbol_feature.hpp1
-rw-r--r--src/mbgl/layout/symbol_instance.cpp17
-rw-r--r--src/mbgl/layout/symbol_instance.hpp7
-rw-r--r--src/mbgl/layout/symbol_layout.cpp57
-rw-r--r--src/mbgl/layout/symbol_layout.hpp2
-rw-r--r--src/mbgl/layout/symbol_projection.cpp6
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) {