diff options
author | Alexander Shalamov <alexander.shalamov@mapbox.com> | 2019-03-11 10:26:19 +0200 |
---|---|---|
committer | Alexander Shalamov <alexander.shalamov@mapbox.com> | 2019-03-13 17:14:53 +0200 |
commit | 8be135231d9efe41a3b12037518d02b36104e8cf (patch) | |
tree | efecd5380232f899aed2cd5824dc16f057f0469a /src/mbgl/layout | |
parent | 8a51362bccbd6487dd1ed8518443b16ba6114fd8 (diff) | |
download | qtlocation-mapboxgl-8be135231d9efe41a3b12037518d02b36104e8cf.tar.gz |
[core] Add possibility of overriding paint properties inside format expression #14062
* [core] Add format override expression and formatted section to evaluation context
* [core] Add textColor to TaggedString's formatted section
* [core] Add FormatSectionOverrides and introduce overridable properties
* [core] Populate symbol layer paint properties for text sections
* [core] Add benchmark for style that uses text-color override
* [core] Add unit test for FormatOverrideExpression
* [core] Add unit test for FormatSectionOverrides
Diffstat (limited to 'src/mbgl/layout')
-rw-r--r-- | src/mbgl/layout/symbol_layout.cpp | 138 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_layout.hpp | 32 |
2 files changed, 99 insertions, 71 deletions
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 4041b16a65..c40a705d7f 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -1,25 +1,16 @@ -#include <mbgl/layout/layout.hpp> #include <mbgl/layout/symbol_layout.hpp> #include <mbgl/layout/merge_lines.hpp> #include <mbgl/layout/clip_lines.hpp> -#include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/renderer/bucket_parameters.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/renderer/image_atlas.hpp> -#include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/text/get_anchors.hpp> #include <mbgl/text/shaping.hpp> -#include <mbgl/util/constants.hpp> #include <mbgl/util/utf.hpp> -#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> #include <mbgl/util/platform.hpp> -#include <mbgl/util/logging.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mapbox/polylabel.hpp> @@ -31,11 +22,27 @@ using namespace style; template <class Property> static bool has(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) { return layout.get<Property>().match( - [&] (const typename Property::Type& t) { return !t.empty(); }, - [&] (const auto&) { return true; } + [] (const typename Property::Type& t) { return !t.empty(); }, + [] (const auto&) { return true; } ); } +namespace { +expression::Value sectionOptionsToValue(const SectionOptions& options) { + std::unordered_map<std::string, expression::Value> result; + // TODO: Data driven properties that can be overridden on per section basis. + // TextOpacity + // TextHaloColor + // TextHaloWidth + // TextHaloBlur + if (options.textColor) { + result.emplace(expression::kFormattedSectionTextColor, *options.textColor); + } + return result; +} +} // namespace + + SymbolLayout::SymbolLayout(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers, std::unique_ptr<GeometryTileLayer> sourceLayer_, @@ -108,7 +115,6 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, auto formatted = layout.evaluate<TextField>(zoom, ft); auto textTransform = layout.evaluate<TextTransform>(zoom, ft); FontStack baseFontStack = layout.evaluate<TextFont>(zoom, ft); - FontStackHash baseFontStackHash = FontStackHasher()(baseFontStack); ft.formattedText = TaggedString(); for (std::size_t j = 0; j < formatted.sections.size(); j++) { @@ -122,8 +128,8 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, ft.formattedText->addSection(applyArabicShaping(util::convertUTF8ToUTF16(u8string)), section.fontScale ? *section.fontScale : 1.0, - section.fontStack ? FontStackHasher()(*section.fontStack) : baseFontStackHash); - + section.fontStack ? *section.fontStack : baseFontStack, + section.textColor); } @@ -273,6 +279,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, : layout.get<SymbolPlacement>(); const float textRepeatDistance = symbolSpacing / 2; + const auto evaluatedLayoutProperties = layout.evaluate(zoom, feature); IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size()); auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) { @@ -285,7 +292,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, // (1) render symbols that overlap into this tile // (2) approximate collision detection effects from neighboring symbols symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, - layout.evaluate(zoom, feature), layoutTextSize, + evaluatedLayoutProperties, layoutTextSize, textBoxScale, textPadding, textPlacement, textOffset, iconBoxScale, iconPadding, iconOffset, glyphPositions, indexedFeature, layoutFeatureIndex, feature.index, @@ -418,43 +425,14 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn // Insert final placement into collision tree and add glyphs/icons to buffers - if (hasText) { - const Range<float> sizeData = bucket->textSizeBinder->getVertexSizeData(feature); - bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, symbolInstance.writingModes, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); - symbolInstance.placedTextIndex = bucket->text.placedSymbols.size() - 1; - PlacedSymbol& horizontalSymbol = bucket->text.placedSymbols.back(); - - bool firstHorizontal = true; - for (const auto& symbol : symbolInstance.horizontalGlyphQuads) { - size_t index = addSymbol( - bucket->text, sizeData, symbol, - symbolInstance.anchor, horizontalSymbol); - if (firstHorizontal) { - horizontalSymbol.vertexStartIndex = index; - firstHorizontal = false; - } - } + if (hasText && feature.formattedText) { + std::size_t index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedTextIndex, symbolInstance.horizontalGlyphQuads); if (symbolInstance.writingModes & WritingModeType::Vertical) { - bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, WritingModeType::Vertical, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); - symbolInstance.placedVerticalTextIndex = bucket->text.placedSymbols.size() - 1; - - PlacedSymbol& verticalSymbol = bucket->text.placedSymbols.back(); - bool firstVertical = true; - - for (const auto& symbol : symbolInstance.verticalGlyphQuads) { - size_t index = addSymbol( - bucket->text, sizeData, symbol, - symbolInstance.anchor, verticalSymbol); - - if (firstVertical) { - verticalSymbol.vertexStartIndex = index; - firstVertical = false; - } - } + index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads, index); } + + updatePaintPropertiesForSection(*bucket, feature, index); } if (hasIcon) { @@ -466,12 +444,11 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn PlacedSymbol& iconSymbol = bucket->icon.placedSymbols.back(); iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, *symbolInstance.iconQuad, symbolInstance.anchor, iconSymbol); - } - } - for (auto& pair : bucket->paintProperties) { - pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {}); - pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.elements(), {}, {}); + for (auto& pair : bucket->paintProperties) { + pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {}); + } + } } } @@ -489,12 +466,53 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn } -template <typename Buffer> -size_t SymbolLayout::addSymbol(Buffer& buffer, - const Range<float> sizeData, - const SymbolQuad& symbol, - const Anchor& labelAnchor, - PlacedSymbol& placedSymbol) { +void SymbolLayout::updatePaintPropertiesForSection(SymbolBucket& bucket, + const SymbolFeature& feature, + std::size_t sectionIndex) { + const auto& formattedSection = sectionOptionsToValue((*feature.formattedText).sectionAt(sectionIndex)); + for (auto& pair : bucket.paintProperties) { + pair.second.textBinders.populateVertexVectors(feature, bucket.text.vertices.elements(), {}, {}, formattedSection); + } +} + +std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket, + SymbolInstance& symbolInstance, + const SymbolFeature& feature, + WritingModeType writingMode, + optional<size_t>& placedIndex, + const SymbolQuads& glyphQuads, + optional<std::size_t> lastAddedSection) { + const Range<float> sizeData = bucket.textSizeBinder->getVertexSizeData(feature); + const bool hasFormatSectionOverrides = bucket.hasFormatSectionOverrides(); + + bucket.text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, + symbolInstance.textOffset, writingMode, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); + placedIndex = bucket.text.placedSymbols.size() - 1; + PlacedSymbol& placedSymbol = bucket.text.placedSymbols.back(); + + bool firstSymbol = true; + for (const auto& symbolQuad : glyphQuads) { + if (hasFormatSectionOverrides) { + if (lastAddedSection && *lastAddedSection != symbolQuad.sectionIndex) { + updatePaintPropertiesForSection(bucket, feature, *lastAddedSection); + } + lastAddedSection = symbolQuad.sectionIndex; + } + size_t index = addSymbol(bucket.text, sizeData, symbolQuad, symbolInstance.anchor, placedSymbol); + if (firstSymbol) { + placedSymbol.vertexStartIndex = index; + firstSymbol = false; + } + } + + return lastAddedSection ? *lastAddedSection : 0u; +} + +size_t SymbolLayout::addSymbol(SymbolBucket::Buffer& buffer, + const Range<float> sizeData, + const SymbolQuad& symbol, + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol) { constexpr const uint16_t vertexLength = 4; const auto &tl = symbol.tl; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index ab6dc049a2..53c66d31fe 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -6,18 +6,15 @@ #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 <mbgl/programs/symbol_program.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <memory> #include <map> -#include <unordered_set> #include <vector> namespace mbgl { class BucketParameters; -class SymbolBucket; class Anchor; class RenderLayer; class PlacedSymbol; @@ -26,7 +23,7 @@ namespace style { class Filter; } // namespace style -class SymbolLayout : public Layout { +class SymbolLayout final : public Layout { public: SymbolLayout(const BucketParameters&, const std::vector<const RenderLayer*>&, @@ -62,12 +59,25 @@ private: void addToDebugBuffers(SymbolBucket&); // Adds placed items to the buffer. - template <typename Buffer> - size_t addSymbol(Buffer&, - const Range<float> sizeData, - const SymbolQuad&, - const Anchor& labelAnchor, - PlacedSymbol& placedSymbol); + size_t addSymbol(SymbolBucket::Buffer&, + const Range<float> sizeData, + const SymbolQuad&, + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol); + + // Adds symbol quads to bucket and returns formatted section index of last + // added quad. + std::size_t addSymbolGlyphQuads(SymbolBucket&, + SymbolInstance&, + const SymbolFeature&, + WritingModeType, + optional<size_t>& placedIndex, + const SymbolQuads&, + optional<std::size_t> lastAddedSection = nullopt); + + void updatePaintPropertiesForSection(SymbolBucket&, + const SymbolFeature&, + std::size_t sectionIndex); // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature, // which may reference data from this object. |