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.hpp16
-rw-r--r--src/mbgl/layout/symbol_instance.cpp46
-rw-r--r--src/mbgl/layout/symbol_instance.hpp9
-rw-r--r--src/mbgl/layout/symbol_layout.cpp353
-rw-r--r--src/mbgl/layout/symbol_layout.hpp35
5 files changed, 292 insertions, 167 deletions
diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp
index 5dd61d9156..f4dc1680bc 100644
--- a/src/mbgl/layout/symbol_feature.hpp
+++ b/src/mbgl/layout/symbol_feature.hpp
@@ -3,13 +3,25 @@
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/optional.hpp>
+#include <array>
#include <string>
namespace mbgl {
-class SymbolFeature {
+class SymbolFeature : public GeometryTileFeature {
public:
- FeatureType type;
+ SymbolFeature(std::unique_ptr<GeometryTileFeature> feature_) :
+ feature(std::move(feature_)),
+ geometry(feature->getGeometries()) // we need a mutable copy of the geometry for mergeLines()
+ {}
+
+ FeatureType getType() const override { return feature->getType(); }
+ optional<Value> getValue(const std::string& key) const override { return feature->getValue(key); };
+ std::unordered_map<std::string,Value> getProperties() const override { return feature->getProperties(); };
+ optional<FeatureIdentifier> getID() const override { return feature->getID(); };
+ GeometryCollection getGeometries() const override { return geometry; };
+
+ std::unique_ptr<GeometryTileFeature> feature;
GeometryCollection geometry;
optional<std::u16string> text;
optional<std::string> icon;
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index fafcc7c15d..d81783b2f6 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -6,29 +6,45 @@ namespace mbgl {
using namespace style;
SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
- const Shaping& shapedText, const PositionedIcon& shapedIcon,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations, const PositionedIcon& shapedIcon,
const SymbolLayoutProperties::Evaluated& layout, const bool addToBuffers, const uint32_t index_,
const float textBoxScale, const float textPadding, const SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, const SymbolPlacementType iconPlacement,
- const GlyphPositions& face, const IndexedSubfeature& indexedFeature) :
+ const GlyphPositions& face, const IndexedSubfeature& indexedFeature, const std::size_t featureIndex_) :
point(anchor.point),
index(index_),
- hasText(shapedText),
+ hasText(shapedTextOrientations.first || shapedTextOrientations.second),
hasIcon(shapedIcon),
- // Create the quads used for rendering the glyphs.
- glyphQuads(addToBuffers && shapedText ?
- getGlyphQuads(anchor, shapedText, textBoxScale, line, layout, textPlacement, face) :
- SymbolQuads()),
+ // Create the collision features that will be used to check whether this symbol instance can be placed
+ textCollisionFeature(line, anchor, shapedTextOrientations.second ?: shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature),
+ iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature),
+ featureIndex(featureIndex_) {
- // Create the quad used for rendering the icon.
- iconQuads(addToBuffers && shapedIcon ?
- getIconQuads(anchor, shapedIcon, line, layout, iconPlacement, shapedText) :
- SymbolQuads()),
+ // Create the quads used for rendering the icon and glyphs.
+ if (addToBuffers) {
+ if (shapedIcon) {
+ iconQuad = getIconQuad(anchor, shapedIcon, line, layout, iconPlacement, shapedTextOrientations.first);
+ }
+ if (shapedTextOrientations.first) {
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, face);
+ glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
+ }
+ if (shapedTextOrientations.second) {
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, face);
+ glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
+ }
+ }
- // Create the collision features that will be used to check whether this symbol instance can be placed
- textCollisionFeature(line, anchor, shapedText, textBoxScale, textPadding, textPlacement, indexedFeature),
- iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature)
- {}
+ if (shapedTextOrientations.first && shapedTextOrientations.second) {
+ writingModes = WritingModeType::Horizontal | WritingModeType::Vertical;
+ } else if (shapedTextOrientations.first) {
+ writingModes = WritingModeType::Horizontal;
+ } else if (shapedTextOrientations.second) {
+ writingModes = WritingModeType::Vertical;
+ } else {
+ writingModes = WritingModeType::None;
+ }
+}
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 508c11a394..532a4d30d8 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/text/quads.hpp>
+#include <mbgl/text/glyph.hpp>
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
@@ -12,20 +13,22 @@ class IndexedSubfeature;
class SymbolInstance {
public:
explicit SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
- const Shaping& shapedText, const PositionedIcon& shapedIcon,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations, const PositionedIcon& shapedIcon,
const style::SymbolLayoutProperties::Evaluated&, const bool inside, const uint32_t index,
const float textBoxScale, const float textPadding, style::SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, style::SymbolPlacementType iconPlacement,
- const GlyphPositions& face, const IndexedSubfeature& indexedfeature);
+ const GlyphPositions& face, const IndexedSubfeature& indexedfeature, const std::size_t featureIndex);
Point<float> point;
uint32_t index;
bool hasText;
bool hasIcon;
SymbolQuads glyphQuads;
- SymbolQuads iconQuads;
+ optional<SymbolQuad> iconQuad;
CollisionFeature textCollisionFeature;
CollisionFeature iconCollisionFeature;
+ WritingModeType writingModes;
+ std::size_t featureIndex;
};
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index eaa0332995..3a2c082ad8 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -3,7 +3,9 @@
#include <mbgl/layout/clip_lines.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/style/layer.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/get_anchors.hpp>
@@ -15,6 +17,7 @@
#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
+#include <mbgl/util/i18n.hpp>
#include <mbgl/math/clamp.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/math/log2.hpp>
@@ -27,48 +30,82 @@ namespace mbgl {
using namespace style;
-SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
- std::string sourceLayerName_,
- uint32_t overscaling_,
- float zoom_,
- const MapMode mode_,
- const GeometryTileLayer& layer,
- const style::Filter& filter,
- style::SymbolLayoutProperties::Evaluated layout_,
- float textMaxSize_,
+SymbolLayout::SymbolLayout(const BucketParameters& parameters,
+ const std::vector<const Layer*>& layers,
+ const GeometryTileLayer& sourceLayer,
SpriteAtlas& spriteAtlas_)
- : layerIDs(std::move(layerIDs_)),
- sourceLayerName(std::move(sourceLayerName_)),
- overscaling(overscaling_),
- zoom(zoom_),
- mode(mode_),
- layout(std::move(layout_)),
- textMaxSize(textMaxSize_),
+ : sourceLayerName(sourceLayer.getName()),
+ bucketName(layers.at(0)->getID()),
+ overscaling(parameters.tileID.overscaleFactor()),
+ zoom(parameters.tileID.overscaledZ),
+ mode(parameters.mode),
spriteAtlas(spriteAtlas_),
- tileSize(util::tileSize * overscaling_),
+ tileSize(util::tileSize * overscaling),
tilePixelRatio(float(util::EXTENT) / tileSize) {
- const bool hasText = !layout.get<TextField>().empty() && !layout.get<TextFont>().empty();
+ const SymbolLayer::Impl& leader = *layers.at(0)->as<SymbolLayer>()->impl;
+
+ layout = leader.layout.evaluate(PropertyEvaluationParameters(zoom));
+
+ if (layout.get<IconRotationAlignment>() == AlignmentType::Auto) {
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ layout.get<IconRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout.get<IconRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ if (layout.get<TextRotationAlignment>() == AlignmentType::Auto) {
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ layout.get<TextRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout.get<TextRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
+ if (layout.get<TextPitchAlignment>() == AlignmentType::Auto) {
+ layout.get<TextPitchAlignment>() = layout.get<TextRotationAlignment>();
+ }
+
+ textMaxSize = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(18));
+
+ layout.get<IconSize>() = leader.layout.evaluate<IconSize>(PropertyEvaluationParameters(zoom + 1));
+ layout.get<TextSize>() = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(zoom + 1));
+
+ const bool hasTextField = layout.get<TextField>().match(
+ [&] (const std::string& s) { return !s.empty(); },
+ [&] (const auto&) { return true; }
+ );
+
+ const bool hasText = !layout.get<TextFont>().empty() && hasTextField;
+
const bool hasIcon = !layout.get<IconImage>().empty();
if (!hasText && !hasIcon) {
return;
}
- auto layerName = layer.getName();
+ for (const auto& layer : layers) {
+ layerPaintProperties.emplace(layer->getID(), std::make_pair(
+ layer->as<SymbolLayer>()->impl->iconPaintProperties(),
+ layer->as<SymbolLayer>()->impl->textPaintProperties()
+ ));
+ }
// Determine and load glyph ranges
- const size_t featureCount = layer.featureCount();
+ const size_t featureCount = sourceLayer.featureCount();
for (size_t i = 0; i < featureCount; ++i) {
- auto feature = layer.getFeature(i);
- if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
+ auto feature = sourceLayer.getFeature(i);
+ if (!leader.filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
continue;
+
+ SymbolFeature ft(std::move(feature));
- SymbolFeature ft;
ft.index = i;
- auto getValue = [&feature](const std::string& key) -> std::string {
- auto value = feature->getValue(key);
+ auto getValue = [&ft](const std::string& key) -> std::string {
+ auto value = ft.getValue(key);
if (!value)
return std::string();
if (value->is<std::string>())
@@ -83,13 +120,18 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
return util::toString(value->get<double>());
return "null";
};
-
+
if (hasText) {
- std::string u8string = util::replaceTokens(layout.get<TextField>(), getValue);
+ std::string u8string = layout.evaluate<TextField>(zoom, ft);
+ if (layout.get<TextField>().isConstant()) {
+ u8string = util::replaceTokens(u8string, getValue);
+ }
+
+ auto textTransform = layout.evaluate<TextTransform>(zoom, ft);
- if (layout.get<TextTransform>() == TextTransformType::Uppercase) {
+ if (textTransform == TextTransformType::Uppercase) {
u8string = platform::uppercase(u8string);
- } else if (layout.get<TextTransform>() == TextTransformType::Lowercase) {
+ } else if (textTransform == TextTransformType::Lowercase) {
u8string = platform::lowercase(u8string);
}
@@ -98,6 +140,9 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
// Loop through all characters of this text and collect unique codepoints.
for (char16_t chr : *ft.text) {
ranges.insert(getGlyphRange(chr));
+ if (char16_t verticalChr = util::i18n::verticalizePunctuation(chr)) {
+ ranges.insert(getGlyphRange(verticalChr));
+ }
}
}
@@ -106,8 +151,6 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
}
if (ft.text || ft.icon) {
- ft.type = feature->getType();
- ft.geometry = feature->getGeometries();
features.push_back(std::move(ft));
}
}
@@ -122,7 +165,12 @@ bool SymbolLayout::hasSymbolInstances() const {
}
bool SymbolLayout::canPrepare(GlyphAtlas& glyphAtlas) {
- if (!layout.get<TextField>().empty() && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) {
+ const bool hasTextField = layout.get<TextField>().match(
+ [&] (const std::string& s) { return !s.empty(); },
+ [&] (const auto&) { return true; }
+ );
+
+ if (hasTextField && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) {
return false;
}
@@ -178,61 +226,83 @@ void SymbolLayout::prepare(uintptr_t tileUID,
auto glyphSet = glyphAtlas.getGlyphSet(layout.get<TextFont>());
- for (const auto& feature : features) {
+ const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map &&
+ layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
+
+ for (auto it = features.begin(); it != features.end(); ++it) {
+ auto& feature = *it;
if (feature.geometry.empty()) continue;
- Shaping shapedText;
+ std::pair<Shaping, Shaping> shapedTextOrientations;
PositionedIcon shapedIcon;
GlyphPositions face;
// if feature has text, shape the text
if (feature.text) {
- shapedText = glyphSet->getShaping(
- /* string */ *feature.text,
- /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
- layout.get<TextMaxWidth>() * 24 : 0,
- /* lineHeight: ems */ layout.get<TextLineHeight>() * 24,
- /* horizontalAlign */ horizontalAlign,
- /* verticalAlign */ verticalAlign,
- /* justify */ justify,
- /* spacing: ems */ layout.get<TextLetterSpacing>() * 24,
- /* translate */ Point<float>(layout.get<TextOffset>()[0], layout.get<TextOffset>()[1]),
- /* bidirectional algorithm object */ bidi);
-
- // Add the glyphs we need for this label to the glyph atlas.
- if (shapedText) {
- glyphAtlas.addGlyphs(tileUID, *feature.text, layout.get<TextFont>(), **glyphSet, face);
+ auto getShaping = [&] (const std::u16string& text, WritingModeType writingMode) {
+ const float oneEm = 24.0f;
+ const Shaping result = glyphSet->getShaping(
+ /* string */ text,
+ /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
+ layout.get<TextMaxWidth>() * oneEm : 0,
+ /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm,
+ /* horizontalAlign */ horizontalAlign,
+ /* verticalAlign */ verticalAlign,
+ /* justify */ justify,
+ /* spacing: ems */ layout.get<TextLetterSpacing>() * oneEm,
+ /* translate */ Point<float>(layout.get<TextOffset>()[0], layout.get<TextOffset>()[1]),
+ /* verticalHeight */ oneEm,
+ /* writingMode */ writingMode,
+ /* bidirectional algorithm object */ bidi);
+
+ // Add the glyphs we need for this label to the glyph atlas.
+ if (result) {
+ glyphAtlas.addGlyphs(tileUID, text, layout.get<TextFont>(), glyphSet, face);
+ }
+
+ return result;
+ };
+
+ shapedTextOrientations.first = getShaping(*feature.text, WritingModeType::Horizontal);
+
+ if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) {
+ shapedTextOrientations.second = getShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical);
}
}
// if feature has icon, get sprite atlas position
if (feature.icon) {
- auto image = spriteAtlas.getImage(*feature.icon, SpritePatternMode::Single);
+ auto image = spriteAtlas.getIcon(*feature.icon);
if (image) {
- shapedIcon = shapeIcon(*image, layout);
+ shapedIcon = shapeIcon(*image,
+ layout.evaluate<IconOffset>(zoom, feature),
+ layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
assert((*image).spriteImage);
if ((*image).spriteImage->sdf) {
sdfIcons = true;
}
if ((*image).relativePixelRatio != 1.0f) {
iconsNeedLinear = true;
- } else if (layout.get<IconRotate>() != 0) {
+ } else if (layout.get<IconRotate>().constantOr(1) != 0) {
iconsNeedLinear = true;
}
}
}
// if either shapedText or icon position is present, add the feature
- if (shapedText || shapedIcon) {
- addFeature(feature, shapedText, shapedIcon, face);
+ if (shapedTextOrientations.first || shapedIcon) {
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, face);
}
+
+ feature.geometry.clear();
}
- features.clear();
+ compareText.clear();
}
-void SymbolLayout::addFeature(const SymbolFeature& feature,
- const Shaping& shapedText,
+void SymbolLayout::addFeature(const std::size_t index,
+ const SymbolFeature& feature,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face) {
const float minScale = 0.5f;
@@ -254,7 +324,7 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
? SymbolPlacementType::Point
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
- IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, layerIDs.at(0), symbolInstances.size()};
+ IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()};
auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
// https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
@@ -277,11 +347,13 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
const bool addToBuffers = mode == MapMode::Still || withinPlus0;
- symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(),
+ symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
- face, indexedFeature);
+ face, indexedFeature, index);
};
+
+ const auto& type = feature.getType();
if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT);
@@ -289,8 +361,8 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
Anchors anchors = getAnchors(line,
symbolSpacing,
textMaxAngle,
- shapedText.left,
- shapedText.right,
+ (shapedTextOrientations.second ?: shapedTextOrientations.first).left,
+ (shapedTextOrientations.second ?: shapedTextOrientations.first).right,
shapedIcon.left,
shapedIcon.right,
glyphSize,
@@ -298,12 +370,12 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
overscaling);
for (auto& anchor : anchors) {
- if (!shapedText || !anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
+ if (!feature.text || !anchorIsTooClose(*feature.text, textRepeatDistance, anchor)) {
addSymbolInstance(line, anchor);
}
}
}
- } else if (feature.type == FeatureType::Polygon) {
+ } else if (type == FeatureType::Polygon) {
for (const auto& polygon : classifyRings(feature.geometry)) {
Polygon<double> poly;
for (const auto& ring : polygon) {
@@ -319,12 +391,12 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
Anchor anchor(poi.x, poi.y, 0, minScale);
addSymbolInstance(polygon[0], anchor);
}
- } else if (feature.type == FeatureType::LineString) {
+ } else if (type == FeatureType::LineString) {
for (const auto& line : feature.geometry) {
Anchor anchor(line[0].x, line[0].y, 0, minScale);
addSymbolInstance(line, anchor);
}
- } else if (feature.type == FeatureType::Point) {
+ } else if (type == FeatureType::Point) {
for (const auto& points : feature.geometry) {
for (const auto& point : points) {
Anchor anchor(point.x, point.y, 0, minScale);
@@ -350,7 +422,7 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe
}
std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) {
- auto bucket = std::make_unique<SymbolBucket>(mode, layout, sdfIcons, iconsNeedLinear);
+ auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, zoom, sdfIcons, iconsNeedLinear);
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
@@ -365,6 +437,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
const bool mayOverlap = layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() ||
layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>();
+ const bool keepUpright = layout.get<TextKeepUpright>();
+
// Sort symbols by their y position on the canvas so that they lower symbols
// are drawn on top of higher symbols.
// Don't sort symbols that won't overlap because it isn't necessary and
@@ -416,22 +490,32 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
// Insert final placement into collision tree and add glyphs/icons to buffers
if (hasText) {
+ const float placementZoom = util::max(util::log2(glyphScale) + zoom, 0.0f);
collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.get<TextIgnorePlacement>());
if (glyphScale < collisionTile.maxScale) {
- addSymbols(
- bucket->text, symbolInstance.glyphQuads, glyphScale,
- layout.get<TextKeepUpright>(), textPlacement, collisionTile.config.angle);
+ for (const auto& symbol : symbolInstance.glyphQuads) {
+ addSymbol(
+ bucket->text, symbol, placementZoom,
+ keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes);
+ }
}
}
if (hasIcon) {
+ const float placementZoom = util::max(util::log2(iconScale) + zoom, 0.0f);
collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get<IconIgnorePlacement>());
- if (iconScale < collisionTile.maxScale) {
- addSymbols(
- bucket->icon, symbolInstance.iconQuads, iconScale,
- layout.get<IconKeepUpright>(), iconPlacement, collisionTile.config.angle);
+ if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) {
+ addSymbol(
+ bucket->icon, *symbolInstance.iconQuad, placementZoom,
+ keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes);
}
}
+
+ const auto& feature = features.at(symbolInstance.featureIndex);
+ for (auto& pair : bucket->paintPropertyBinders) {
+ pair.second.first.populateVertexVectors(feature, bucket->icon.vertices.vertexSize());
+ pair.second.second.populateVertexVectors(feature, bucket->text.vertices.vertexSize());
+ }
}
if (collisionTile.config.debug) {
@@ -442,67 +526,76 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
}
template <typename Buffer>
-void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float scale, const bool keepUpright, const style::SymbolPlacementType placement, const float placementAngle) {
+void SymbolLayout::addSymbol(Buffer& buffer,
+ const SymbolQuad& symbol,
+ const float placementZoom,
+ const bool keepUpright,
+ const style::SymbolPlacementType placement,
+ const float placementAngle,
+ const WritingModeType writingModes) {
constexpr const uint16_t vertexLength = 4;
- const float placementZoom = util::max(util::log2(scale) + zoom, 0.0f);
-
- for (const auto& symbol : symbols) {
- const auto &tl = symbol.tl;
- const auto &tr = symbol.tr;
- const auto &bl = symbol.bl;
- const auto &br = symbol.br;
- const auto &tex = symbol.tex;
-
- float minZoom = util::max(zoom + util::log2(symbol.minScale), placementZoom);
- float maxZoom = util::min(zoom + util::log2(symbol.maxScale), util::MAX_ZOOM_F);
- const auto &anchorPoint = symbol.anchorPoint;
-
- // drop upside down versions of glyphs
- const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2);
- if (keepUpright && placement == style::SymbolPlacementType::Line &&
- (a <= M_PI / 2 || a > M_PI * 3 / 2)) {
- continue;
- }
- if (maxZoom <= minZoom)
- continue;
+ const auto &tl = symbol.tl;
+ const auto &tr = symbol.tr;
+ const auto &bl = symbol.bl;
+ const auto &br = symbol.br;
+ const auto &tex = symbol.tex;
+
+ float minZoom = util::max(zoom + util::log2(symbol.minScale), placementZoom);
+ float maxZoom = util::min(zoom + util::log2(symbol.maxScale), util::MAX_ZOOM_F);
+ const auto &anchorPoint = symbol.anchorPoint;
+
+ // drop incorrectly oriented glyphs
+ const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2);
+ if (writingModes & WritingModeType::Vertical) {
+ if (placement == style::SymbolPlacementType::Line && symbol.writingMode == WritingModeType::Vertical) {
+ if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 5 / 4) || a > (M_PI * 7 / 4)))
+ return;
+ } else if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 3 / 4) || a > (M_PI * 5 / 4)))
+ return;
+ } else if (keepUpright && placement == style::SymbolPlacementType::Line &&
+ (a <= M_PI / 2 || a > M_PI * 3 / 2)) {
+ return;
+ }
- // Lower min zoom so that while fading out the label
- // it can be shown outside of collision-free zoom levels
- if (minZoom == placementZoom) {
- minZoom = 0;
- }
+ if (maxZoom <= minZoom)
+ return;
- if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
- buffer.segments.emplace_back(buffer.vertices.vertexSize(), buffer.triangles.indexSize());
- }
+ // Lower min zoom so that while fading out the label
+ // it can be shown outside of collision-free zoom levels
+ if (minZoom == placementZoom) {
+ minZoom = 0;
+ }
- // We're generating triangle fans, so we always start with the first
- // coordinate in this polygon.
- auto& segment = buffer.segments.back();
- assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
- uint16_t index = segment.vertexLength;
-
- // Encode angle of glyph
- uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256);
-
- // coordinates (2 triangles)
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tl, tex.x, tex.y,
- minZoom, maxZoom, placementZoom, glyphAngle));
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y,
- minZoom, maxZoom, placementZoom, glyphAngle));
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h,
- minZoom, maxZoom, placementZoom, glyphAngle));
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h,
- minZoom, maxZoom, placementZoom, glyphAngle));
-
- // add the two triangles, referencing the four coordinates we just inserted.
- buffer.triangles.emplace_back(index + 0, index + 1, index + 2);
- buffer.triangles.emplace_back(index + 1, index + 2, index + 3);
-
- segment.vertexLength += vertexLength;
- segment.indexLength += 6;
+ if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
+ buffer.segments.emplace_back(buffer.vertices.vertexSize(), buffer.triangles.indexSize());
}
+
+ // We're generating triangle fans, so we always start with the first
+ // coordinate in this polygon.
+ auto& segment = buffer.segments.back();
+ assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t index = segment.vertexLength;
+
+ // Encode angle of glyph
+ uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256);
+
+ // coordinates (2 triangles)
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tl, tex.x, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+
+ // add the two triangles, referencing the four coordinates we just inserted.
+ buffer.triangles.emplace_back(index + 0, index + 1, index + 2);
+ buffer.triangles.emplace_back(index + 1, index + 2, index + 3);
+
+ segment.vertexLength += vertexLength;
+ segment.indexLength += 6;
}
void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& bucket) {
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index c89b791ccc..491d0078da 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -5,6 +5,7 @@
#include <mbgl/layout/symbol_feature.hpp>
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/text/bidi.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <memory>
#include <map>
@@ -20,6 +21,7 @@ class GlyphAtlas;
class SymbolBucket;
namespace style {
+class BucketParameters;
class Filter;
class Layer;
} // namespace style
@@ -28,15 +30,9 @@ struct Anchor;
class SymbolLayout {
public:
- SymbolLayout(std::vector<std::string> layerIDs_,
- std::string sourceLayerName_,
- uint32_t overscaling,
- float zoom,
- const MapMode,
+ SymbolLayout(const style::BucketParameters&,
+ const std::vector<const style::Layer*>&,
const GeometryTileLayer&,
- const style::Filter&,
- style::SymbolLayoutProperties::Evaluated,
- float textMaxSize,
SpriteAtlas&);
bool canPrepare(GlyphAtlas&);
@@ -56,12 +52,13 @@ public:
State state = Pending;
- const std::vector<std::string> layerIDs;
- const std::string sourceLayerName;
+ std::unordered_map<std::string,
+ std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>> layerPaintProperties;
private:
- void addFeature(const SymbolFeature&,
- const Shaping& shapedText,
+ void addFeature(const size_t,
+ const SymbolFeature&,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face);
@@ -72,14 +69,18 @@ private:
// Adds placed items to the buffer.
template <typename Buffer>
- void addSymbols(Buffer&, const SymbolQuads&, float scale,
- const bool keepUpright, const style::SymbolPlacementType, const float placementAngle);
+ void addSymbol(Buffer&, const SymbolQuad&, float scale,
+ const bool keepUpright, const style::SymbolPlacementType, const float placementAngle,
+ WritingModeType writingModes);
+ const std::string sourceLayerName;
+ const std::string bucketName;
const float overscaling;
const float zoom;
const MapMode mode;
- const style::SymbolLayoutProperties::Evaluated layout;
- const float textMaxSize;
+
+ style::SymbolLayoutProperties::Evaluated layout;
+ float textMaxSize;
SpriteAtlas& spriteAtlas;
@@ -92,7 +93,7 @@ private:
GlyphRangeSet ranges;
std::vector<SymbolInstance> symbolInstances;
std::vector<SymbolFeature> features;
-
+
BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread
};