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 /include/mbgl | |
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 'include/mbgl')
-rw-r--r-- | include/mbgl/style/expression/expression.hpp | 17 | ||||
-rw-r--r-- | include/mbgl/style/expression/format_expression.hpp | 17 | ||||
-rw-r--r-- | include/mbgl/style/expression/format_section_override.hpp | 82 | ||||
-rw-r--r-- | include/mbgl/style/expression/formatted.hpp | 16 | ||||
-rw-r--r-- | include/mbgl/style/property_expression.hpp | 103 |
5 files changed, 147 insertions, 88 deletions
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index 97b143b3d9..22ae57c2be 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -25,18 +25,26 @@ public: class EvaluationContext { public: - EvaluationContext(float zoom_) : zoom(zoom_), feature(nullptr) {} - EvaluationContext(GeometryTileFeature const * feature_) : zoom(optional<float>()), feature(feature_) {} + EvaluationContext() = default; + explicit EvaluationContext(float zoom_) : zoom(zoom_) {} + explicit EvaluationContext(GeometryTileFeature const * feature_) : feature(feature_) {} EvaluationContext(float zoom_, GeometryTileFeature const * feature_) : zoom(zoom_), feature(feature_) {} EvaluationContext(optional<float> zoom_, GeometryTileFeature const * feature_, optional<double> colorRampParameter_) : zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_)) {} - + + EvaluationContext& withFormattedSection(const Value* formattedSection_) noexcept { + formattedSection = formattedSection_; + return *this; + }; + optional<float> zoom; - GeometryTileFeature const * feature; + GeometryTileFeature const * feature = nullptr; optional<double> colorRampParameter; + // Contains formatted section object, std::unordered_map<std::string, Value>. + const Value* formattedSection = nullptr; }; template <typename T> @@ -134,6 +142,7 @@ enum class Kind : int32_t { All, Comparison, FormatExpression, + FormatSectionOverride }; class Expression { diff --git a/include/mbgl/style/expression/format_expression.hpp b/include/mbgl/style/expression/format_expression.hpp index b00674a88e..180df0139d 100644 --- a/include/mbgl/style/expression/format_expression.hpp +++ b/include/mbgl/style/expression/format_expression.hpp @@ -1,11 +1,7 @@ #pragma once #include <mbgl/style/expression/expression.hpp> -#include <mbgl/style/expression/formatted.hpp> #include <mbgl/style/expression/parsing_context.hpp> -#include <mbgl/style/conversion.hpp> - -#include <memory> namespace mbgl { namespace style { @@ -14,16 +10,18 @@ namespace expression { struct FormatExpressionSection { FormatExpressionSection(std::unique_ptr<Expression> text_, optional<std::unique_ptr<Expression>> fontScale_, - optional<std::unique_ptr<Expression>> textFont_); + optional<std::unique_ptr<Expression>> textFont_, + optional<std::unique_ptr<Expression>> textColor_); std::shared_ptr<Expression> text; optional<std::shared_ptr<Expression>> fontScale; optional<std::shared_ptr<Expression>> textFont; + optional<std::shared_ptr<Expression>> textColor; }; -class FormatExpression : public Expression { +class FormatExpression final : public Expression { public: - FormatExpression(std::vector<FormatExpressionSection> sections); + explicit FormatExpression(std::vector<FormatExpressionSection> sections); EvaluationResult evaluate(const EvaluationContext&) const override; static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); @@ -38,13 +36,12 @@ public: return { nullopt }; } + const std::vector<FormatExpressionSection>& getSections() const { return sections; } + mbgl::Value serialize() const override; std::string getOperator() const override { return "format"; } private: std::vector<FormatExpressionSection> sections; - std::unique_ptr<Expression> text; - optional<std::unique_ptr<Expression>> fontScale; - optional<std::unique_ptr<Expression>> textFont; }; } // namespace expression diff --git a/include/mbgl/style/expression/format_section_override.hpp b/include/mbgl/style/expression/format_section_override.hpp new file mode 100644 index 0000000000..7dc3a8dbb4 --- /dev/null +++ b/include/mbgl/style/expression/format_section_override.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/renderer/possibly_evaluated_property_value.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +template<class T> +class FormatSectionOverride final : public Expression { +public: + FormatSectionOverride(const type::Type& type_, + PossiblyEvaluatedPropertyValue<T> defaultValue_, + std::string propertyName_) : + Expression(Kind::FormatSectionOverride, type_), + defaultValue(std::move(defaultValue_)), + propertyName(std::move(propertyName_)) + {} + + EvaluationResult evaluate(const EvaluationContext& context) const final { + using Object = std::unordered_map<std::string, expression::Value>; + if (context.formattedSection && + context.formattedSection->is<Object>()) { + const auto& section = context.formattedSection->get<Object>(); + if (section.find(propertyName) != section.end()) { + return section.at(propertyName); + } + } + return defaultValue.evaluate(*context.feature, *context.zoom, T()); + } + + void eachChild(const std::function<void(const Expression&)>& fn) const final { + defaultValue.match([&fn] (const style::PropertyExpression<T>& e) { fn(e.getExpression()); }, + [] (const T&) {}); + } + + bool operator==(const Expression& e) const final { + if (e.getKind() == Kind::FormatSectionOverride) { + const auto* other = static_cast<const FormatSectionOverride*>(&e); + + if (getType() != other->getType() || propertyName != other->propertyName) { + return false; + } + + // Check that default values or property expressions are equal. + return defaultValue.match( + [other] (const style::PropertyExpression<T>& thisExpr) { + return other->defaultValue.match([&thisExpr] (const style::PropertyExpression<T>& otherExpr) { + return thisExpr == otherExpr; + }, + [] (const T&) { + return false; + }); + }, + [other] (const T& thisValue) { + return other->defaultValue.match([&thisValue] (const T& otherValue) { + return thisValue == otherValue; + }, + [] (const style::PropertyExpression<T>&) { + return false; + }); + }); + } + + return false; + } + + std::vector<optional<Value>> possibleOutputs() const final { + return {nullopt}; + } + + std::string getOperator() const final { return "format-section-override"; } + +private: + PossiblyEvaluatedPropertyValue<T> defaultValue; + std::string propertyName; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/formatted.hpp b/include/mbgl/style/expression/formatted.hpp index 9e7e7308cb..f4f08e9197 100644 --- a/include/mbgl/style/expression/formatted.hpp +++ b/include/mbgl/style/expression/formatted.hpp @@ -1,9 +1,9 @@ #pragma once #include <mbgl/style/conversion.hpp> +#include <mbgl/util/color.hpp> #include <mbgl/util/font_stack.hpp> #include <mbgl/util/optional.hpp> -#include <mbgl/util/variant.hpp> #include <vector> #include <string> @@ -12,15 +12,25 @@ namespace mbgl { namespace style { namespace expression { +extern const char* const kFormattedSectionFontScale; +extern const char* const kFormattedSectionTextFont; +extern const char* const kFormattedSectionTextColor; + struct FormattedSection { - FormattedSection(std::string text_, optional<double> fontScale_, optional<FontStack> fontStack_) + FormattedSection(std::string text_, + optional<double> fontScale_, + optional<FontStack> fontStack_, + optional<Color> textColor_) : text(std::move(text_)) , fontScale(std::move(fontScale_)) , fontStack(std::move(fontStack_)) + , textColor(std::move(textColor_)) {} + std::string text; optional<double> fontScale; optional<FontStack> fontStack; + optional<Color> textColor; }; class Formatted { @@ -28,7 +38,7 @@ public: Formatted() = default; Formatted(const char* plainU8String) { - sections.emplace_back(std::string(plainU8String), nullopt, nullopt); + sections.emplace_back(std::string(plainU8String), nullopt, nullopt, nullopt); } Formatted(std::vector<FormattedSection> sections_) diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp index b198de02b2..32983e2380 100644 --- a/include/mbgl/style/property_expression.hpp +++ b/include/mbgl/style/property_expression.hpp @@ -1,7 +1,6 @@ #pragma once #include <mbgl/style/expression/expression.hpp> -#include <mbgl/style/expression/value.hpp> #include <mbgl/style/expression/is_constant.hpp> #include <mbgl/style/expression/interpolate.hpp> #include <mbgl/style/expression/step.hpp> @@ -11,46 +10,38 @@ namespace mbgl { namespace style { -template <class T> -class PropertyExpression { +class PropertyExpressionBase { public: - // Second parameter to be used only for conversions from legacy functions. - PropertyExpression(std::unique_ptr<expression::Expression> expression_, optional<T> defaultValue_ = {}) - : expression(std::move(expression_)), - defaultValue(std::move(defaultValue_)), - zoomCurve(expression::findZoomCurveChecked(expression.get())) { - } + explicit PropertyExpressionBase(std::unique_ptr<expression::Expression>); - bool isZoomConstant() const { return expression::isZoomConstant(*expression); } - bool isFeatureConstant() const { return expression::isFeatureConstant(*expression); } + bool isZoomConstant() const noexcept; + bool isFeatureConstant() const noexcept; + bool canEvaluateWith(const expression::EvaluationContext&) const noexcept; + float interpolationFactor(const Range<float>&, const float) const noexcept; + Range<float> getCoveringStops(const float, const float) const noexcept; + const expression::Expression& getExpression() const noexcept; - T evaluate(float zoom) const { - assert(!expression::isZoomConstant(*expression)); - assert(expression::isFeatureConstant(*expression)); - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(zoom, nullptr)); - if (result) { - const optional<T> typed = expression::fromExpressionValue<T>(*result); - return typed ? *typed : defaultValue ? *defaultValue : T(); - } - return defaultValue ? *defaultValue : T(); - } + bool useIntegerZoom = false; - template <class Feature> - T evaluate(const Feature& feature, T finalDefaultValue) const { - assert(expression::isZoomConstant(*expression)); - assert(!expression::isFeatureConstant(*expression)); - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(&feature)); - if (result) { - const optional<T> typed = expression::fromExpressionValue<T>(*result); - return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; - } - return defaultValue ? *defaultValue : finalDefaultValue; +protected: + std::shared_ptr<const expression::Expression> expression; + variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve; + bool isZoomConstant_; + bool isFeatureConstant_; +}; + +template <class T> +class PropertyExpression final : public PropertyExpressionBase { +public: + // Second parameter to be used only for conversions from legacy functions. + PropertyExpression(std::unique_ptr<expression::Expression> expression_, optional<T> defaultValue_ = nullopt) + : PropertyExpressionBase(std::move(expression_)), + defaultValue(std::move(defaultValue_)) { } - template <class Feature> - T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const { - assert(!expression::isFeatureConstant(*expression)); - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext({zoom}, &feature)); + T evaluate(const expression::EvaluationContext& context, T finalDefaultValue = T()) const { + assert(canEvaluateWith(context)); + const expression::EvaluationResult result = expression->evaluate(context); if (result) { const optional<T> typed = expression::fromExpressionValue<T>(*result); return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; @@ -58,59 +49,29 @@ public: return defaultValue ? *defaultValue : finalDefaultValue; } - float interpolationFactor(const Range<float>& inputLevels, const float inputValue) const { - return zoomCurve.match( - [](std::nullptr_t) { - assert(false); - return 0.0f; - }, - [&](const expression::Interpolate* z) { - return z->interpolationFactor(Range<double> { inputLevels.min, inputLevels.max }, inputValue); - }, - [&](const expression::Step*) { - return 0.0f; - } - ); + T evaluate(float zoom) const { + return evaluate(expression::EvaluationContext(zoom)); } - Range<float> getCoveringStops(const float lower, const float upper) const { - return zoomCurve.match( - [](std::nullptr_t) { - assert(false); - return Range<float>(0.0f, 0.0f); - }, - [&](auto z) { - return z->getCoveringStops(lower, upper); - } - ); + T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const { + return evaluate(expression::EvaluationContext(&feature), finalDefaultValue); } - // Return the range obtained by evaluating the function at each of the zoom levels in zoomRange - template <class Feature> - Range<T> evaluate(const Range<float>& zoomRange, const Feature& feature, T finalDefaultValue) { - return Range<T> { - evaluate(zoomRange.min, feature, finalDefaultValue), - evaluate(zoomRange.max, feature, finalDefaultValue) - }; + T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const { + return evaluate(expression::EvaluationContext(zoom, &feature), finalDefaultValue); } std::vector<optional<T>> possibleOutputs() const { return expression::fromExpressionValues<T>(expression->possibleOutputs()); } - const expression::Expression& getExpression() const { return *expression; } - - bool useIntegerZoom = false; - friend bool operator==(const PropertyExpression& lhs, const PropertyExpression& rhs) { return *lhs.expression == *rhs.expression; } private: - std::shared_ptr<const expression::Expression> expression; optional<T> defaultValue; - variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve; }; } // namespace style |