summaryrefslogtreecommitdiff
path: root/src/mbgl/style
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/style')
-rw-r--r--src/mbgl/style/conversion/function.cpp2
-rw-r--r--src/mbgl/style/expression/dsl.cpp6
-rw-r--r--src/mbgl/style/expression/format_expression.cpp62
-rw-r--r--src/mbgl/style/expression/formatted.cpp36
-rw-r--r--src/mbgl/style/expression/is_constant.cpp10
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs5
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp15
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp98
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp5
-rw-r--r--src/mbgl/style/layout_property.hpp2
-rw-r--r--src/mbgl/style/light_impl.hpp1
-rw-r--r--src/mbgl/style/paint_property.hpp7
-rw-r--r--src/mbgl/style/properties.hpp4
-rw-r--r--src/mbgl/style/property_expression.cpp68
14 files changed, 282 insertions, 39 deletions
diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp
index 5877d0eb7c..79ad2fc7d8 100644
--- a/src/mbgl/style/conversion/function.cpp
+++ b/src/mbgl/style/conversion/function.cpp
@@ -41,7 +41,7 @@ bool hasTokens(const std::string& source) {
std::unique_ptr<Expression> convertTokenStringToFormatExpression(const std::string& source) {
auto textExpression = convertTokenStringToExpression(source);
std::vector<FormatExpressionSection> sections;
- sections.emplace_back(std::move(textExpression), nullopt, nullopt);
+ sections.emplace_back(std::move(textExpression), nullopt, nullopt, nullopt);
return std::make_unique<FormatExpression>(sections);
}
diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp
index f5ff83a9e7..e7d90ba07b 100644
--- a/src/mbgl/style/expression/dsl.cpp
+++ b/src/mbgl/style/expression/dsl.cpp
@@ -189,13 +189,13 @@ std::unique_ptr<Expression> concat(std::vector<std::unique_ptr<Expression>> inpu
std::unique_ptr<Expression> format(const char* value) {
return std::make_unique<Literal>(Formatted(value));
}
-
+
std::unique_ptr<Expression> format(std::unique_ptr<Expression> input) {
std::vector<FormatExpressionSection> sections;
- sections.emplace_back(std::move(input), nullopt, nullopt);
+ sections.emplace_back(std::move(input), nullopt, nullopt, nullopt);
return std::make_unique<FormatExpression>(sections);
}
-
+
} // namespace dsl
} // namespace expression
} // namespace style
diff --git a/src/mbgl/style/expression/format_expression.cpp b/src/mbgl/style/expression/format_expression.cpp
index 144df4b160..b5e4ba62c4 100644
--- a/src/mbgl/style/expression/format_expression.cpp
+++ b/src/mbgl/style/expression/format_expression.cpp
@@ -1,8 +1,6 @@
#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/format_expression.hpp>
-#include <mbgl/style/expression/literal.hpp>
-#include <mbgl/util/font_stack.hpp>
-#include <mbgl/util/string.hpp>
+#include <mbgl/style/expression/formatted.hpp>
namespace mbgl {
namespace style {
@@ -10,15 +8,21 @@ namespace expression {
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_)
: text(std::move(text_))
{
if (fontScale_) {
fontScale = std::shared_ptr<Expression>(std::move(*fontScale_));
}
+
if (textFont_) {
textFont = std::shared_ptr<Expression>(std::move(*textFont_));
}
+
+ if (textColor_) {
+ textColor = std::shared_ptr<Expression>(std::move(*textColor_));
+ }
}
FormatExpression::FormatExpression(std::vector<FormatExpressionSection> sections_)
@@ -53,7 +57,7 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct
return ParseResult();
}
- const optional<Convertible> fontScaleOption = objectMember(options, "font-scale");
+ const optional<Convertible> fontScaleOption = objectMember(options, kFormattedSectionFontScale);
ParseResult fontScale;
if (fontScaleOption) {
fontScale = ctx.parse(*fontScaleOption, 1, {type::Number});
@@ -62,7 +66,7 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct
}
}
- const optional<Convertible> textFontOption = objectMember(options, "text-font");
+ const optional<Convertible> textFontOption = objectMember(options, kFormattedSectionTextFont);
ParseResult textFont;
if (textFontOption) {
textFont = ctx.parse(*textFontOption, 1, {type::Array(type::String)});
@@ -70,7 +74,20 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct
return ParseResult();
}
}
- sections.emplace_back(std::move(*text), std::move(fontScale), std::move(textFont));
+
+ const optional<Convertible> textColorOption = objectMember(options, kFormattedSectionTextColor);
+ ParseResult textColor;
+ if (textColorOption) {
+ textColor = ctx.parse(*textColorOption, 1, {type::Color});
+ if (!textColor) {
+ return ParseResult();
+ }
+ }
+
+ sections.emplace_back(std::move(*text),
+ std::move(fontScale),
+ std::move(textFont),
+ std::move(textColor));
}
return ParseResult(std::make_unique<FormatExpression>(std::move(sections)));
@@ -85,6 +102,9 @@ void FormatExpression::eachChild(const std::function<void(const Expression&)>& f
if (section.textFont) {
fn(**section.textFont);
}
+ if (section.textColor) {
+ fn(**section.textColor);
+ }
}
}
@@ -108,6 +128,10 @@ bool FormatExpression::operator==(const Expression& e) const {
(!lhsSection.textFont && rhsSection.textFont)) {
return false;
}
+ if ((lhsSection.textColor && (!rhsSection.textColor || **lhsSection.textColor != **rhsSection.textColor)) ||
+ (!lhsSection.textColor && rhsSection.textColor)) {
+ return false;
+ }
}
return true;
}
@@ -115,15 +139,18 @@ bool FormatExpression::operator==(const Expression& e) const {
}
mbgl::Value FormatExpression::serialize() const {
- std::vector<mbgl::Value> serialized{{ std::string("format") }};
+ std::vector<mbgl::Value> serialized{{ getOperator() }};
for (const auto& section : sections) {
serialized.push_back(section.text->serialize());
std::unordered_map<std::string, mbgl::Value> options;
if (section.fontScale) {
- options.emplace("font-scale", (*section.fontScale)->serialize());
+ options.emplace(kFormattedSectionFontScale, (*section.fontScale)->serialize());
}
if (section.textFont) {
- options.emplace("text-font", (*section.textFont)->serialize());
+ options.emplace(kFormattedSectionTextFont, (*section.textFont)->serialize());
+ }
+ if (section.textColor) {
+ options.emplace(kFormattedSectionTextColor, (*section.textColor)->serialize());
}
serialized.push_back(options);
}
@@ -164,7 +191,20 @@ EvaluationResult FormatExpression::evaluate(const EvaluationContext& params) con
}
evaluatedTextFont = *textFontValue;
}
- evaluatedSections.emplace_back(*evaluatedText, evaluatedFontScale, evaluatedTextFont);
+
+ optional<Color> evaluatedTextColor;
+ if (section.textColor) {
+ auto textColorResult = (*section.textColor)->evaluate(params);
+ if (!textColorResult) {
+ return textColorResult.error();
+ }
+
+ evaluatedTextColor = fromExpressionValue<Color>(*textColorResult);
+ if (!evaluatedTextColor) {
+ return EvaluationError { "Format text-color option must evaluate to Color" };
+ }
+ }
+ evaluatedSections.emplace_back(*evaluatedText, evaluatedFontScale, evaluatedTextFont, evaluatedTextColor);
}
return Formatted(evaluatedSections);
}
diff --git a/src/mbgl/style/expression/formatted.cpp b/src/mbgl/style/expression/formatted.cpp
index 8232d0c698..3fa39b2cdc 100644
--- a/src/mbgl/style/expression/formatted.cpp
+++ b/src/mbgl/style/expression/formatted.cpp
@@ -1,18 +1,15 @@
#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/conversion_impl.hpp>
-#include <mbgl/style/expression/is_constant.hpp>
-#include <mbgl/style/expression/is_expression.hpp>
-#include <mbgl/style/expression/literal.hpp>
-#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/expression/type.hpp>
-#include <mbgl/style/expression/compound_expression.hpp>
-#include <mbgl/style/expression/boolean_operator.hpp>
+#include <mbgl/style/conversion/constant.hpp>
namespace mbgl {
namespace style {
-
namespace expression {
+const char* const kFormattedSectionFontScale = "font-scale";
+const char* const kFormattedSectionTextFont = "text-font";
+const char* const kFormattedSectionTextColor = "text-color";
+
bool Formatted::operator==(const Formatted& other) const {
if (other.sections.size() != sections.size()) {
return false;
@@ -22,14 +19,14 @@ bool Formatted::operator==(const Formatted& other) const {
const auto& otherSection = other.sections.at(i);
if (thisSection.text != otherSection.text ||
thisSection.fontScale != otherSection.fontScale ||
- thisSection.fontStack != otherSection.fontStack) {
+ thisSection.fontStack != otherSection.fontStack ||
+ thisSection.textColor != otherSection.textColor) {
return false;
}
}
return true;
}
-
-
+
std::string Formatted::toString() const {
std::string result;
for (const auto& section : sections) {
@@ -37,7 +34,7 @@ std::string Formatted::toString() const {
}
return result;
}
-
+
} // namespace expression
namespace conversion {
@@ -65,6 +62,7 @@ optional<Formatted> Converter<Formatted>::operator()(const Convertible& value, E
optional<double> fontScale;
optional<FontStack> textFont;
+ optional<Color> textColor;
if (sectionLength > 1) {
Convertible sectionParams = arrayMember(section, 1);
if (!isObject(sectionParams)) {
@@ -72,12 +70,12 @@ optional<Formatted> Converter<Formatted>::operator()(const Convertible& value, E
return nullopt;
}
- optional<Convertible> fontScaleMember = objectMember(sectionParams, "font-scale");
+ optional<Convertible> fontScaleMember = objectMember(sectionParams, kFormattedSectionFontScale);
if (fontScaleMember) {
fontScale = toDouble(*fontScaleMember);
}
- optional<Convertible> textFontMember = objectMember(sectionParams, "text-font");
+ optional<Convertible> textFontMember = objectMember(sectionParams, kFormattedSectionTextFont);
if (textFontMember) {
if (isArray(*textFontMember)) {
std::vector<std::string> fontsVector;
@@ -96,9 +94,17 @@ optional<Formatted> Converter<Formatted>::operator()(const Convertible& value, E
return nullopt;
}
}
+
+ optional<Convertible> textColorMember = objectMember(sectionParams, kFormattedSectionTextColor);
+ if (textColorMember) {
+ textColor = convert<Color>(*textColorMember, error);
+ if (!textColor) {
+ return nullopt;
+ }
+ }
}
- sections.push_back(FormattedSection(*sectionText, fontScale, textFont));
+ sections.push_back(FormattedSection(*sectionText, fontScale, textFont, textColor));
}
return Formatted(sections);
} else if (optional<std::string> result = toString(value)) {
diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp
index 3b20f49a86..9704168a41 100644
--- a/src/mbgl/style/expression/is_constant.cpp
+++ b/src/mbgl/style/expression/is_constant.cpp
@@ -17,18 +17,22 @@ bool isFeatureConstant(const Expression& expression) {
return false;
} else if (name == "has" && parameterCount && *parameterCount == 1) {
return false;
- } else if (0 == name.rfind(filter, 0)) {
- // Legacy filters begin with "filter-" and are never constant.
- return false;
} else if (
name == "properties" ||
name == "geometry-type" ||
name == "id"
) {
return false;
+ } else if (0u == name.rfind(filter, 0u)) {
+ // Legacy filters begin with "filter-" and are never constant.
+ return false;
}
}
+ if (expression.getKind() == Kind::FormatSectionOverride) {
+ return false;
+ }
+
if (expression.getKind() == Kind::CollatorExpression) {
// Although the results of a Collator expression with fixed arguments
// generally shouldn't change between executions, we can't serialize them
diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs
index 792f858862..89dffdcd42 100644
--- a/src/mbgl/style/layers/layer_properties.hpp.ejs
+++ b/src/mbgl/style/layers/layer_properties.hpp.ejs
@@ -31,6 +31,11 @@ struct <%- camelize(property.name) %> : ColorRampProperty {
<% } else { -%>
struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> {
static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
+<% if (isOverridable(property)) { -%>
+ static constexpr const char *name() { return "<%- property.name %>"; }
+ static constexpr auto expressionType() { return expression::type::<%- expressionType(property) %>{}; };
+ template<typename T> static bool hasOverride(const T& t) { return !!t.<%- camelizeWithLeadingLowercase(property.name) %>; };
+<% } -%>
};
<% } -%>
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index 3dd1da1136..e35e7b0b9f 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -1,17 +1,24 @@
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-
#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace style {
+bool SymbolLayer::Impl::hasFormatSectionOverrides() const {
+ if (!hasFormatSectionOverrides_) {
+ hasFormatSectionOverrides_ = SymbolLayerPaintPropertyOverrides::hasOverrides(layout.get<TextField>());
+ }
+ return *hasFormatSectionOverrides_;
+}
+
bool SymbolLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
assert(other.getTypeInfo() == getTypeInfo());
const auto& impl = static_cast<const style::SymbolLayer::Impl&>(other);
return filter != impl.filter ||
visibility != impl.visibility ||
layout != impl.layout ||
- paint.hasDataDrivenPropertyDifference(impl.paint);
+ paint.hasDataDrivenPropertyDifference(impl.paint) ||
+ (hasFormatSectionOverrides() && SymbolLayerPaintPropertyOverrides::hasPaintPropertyDifference(paint, impl.paint));
}
void SymbolLayer::Impl::populateFontStack(std::set<FontStack>& fontStack) const {
@@ -20,10 +27,10 @@ void SymbolLayer::Impl::populateFontStack(std::set<FontStack>& fontStack) const
}
layout.get<TextFont>().match(
- [&] (Undefined) {
+ [&fontStack] (Undefined) {
fontStack.insert({"Open Sans Regular", "Arial Unicode MS Regular"});
},
- [&] (const FontStack& constant) {
+ [&fontStack] (const FontStack& constant) {
fontStack.insert(constant);
},
[&] (const auto& function) {
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index a5b0332f6c..f937fccaa8 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -3,10 +3,104 @@
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/style/expression/format_expression.hpp>
+#include <mbgl/style/expression/formatted.hpp>
+#include <mbgl/style/expression/format_section_override.hpp>
namespace mbgl {
namespace style {
+template<typename PaintProperty>
+struct FormatSectionOverrides;
+
+template<typename... PaintProperty>
+struct FormatSectionOverrides<TypeList<PaintProperty...>> {
+ template<typename Property, typename T, typename U>
+ static void setOverride(const T& overrides, U& overridable) {
+ if (hasOverride<Property>(overrides.template get<TextField>())) {
+ auto override =
+ std::make_unique<expression::FormatSectionOverride<typename Property::Type>>(Property::expressionType(),
+ std::move(overridable.template get<Property>()),
+ Property::name());
+ PropertyExpression<typename Property::Type> expr(std::move(override));
+ overridable.template get<Property>() = PossiblyEvaluatedPropertyValue<typename Property::Type>(std::move(expr));
+ }
+ }
+
+ template<typename T, typename U>
+ static void setOverrides(const T& overrides, U& overridable) {
+ util::ignore({(setOverride<PaintProperty>(overrides, overridable), 0)...});
+ }
+
+ template<typename Property, typename T, typename U>
+ static void updateOverride(T& evaluated, U& updated) {
+ auto property = evaluated.template get<Property>();
+ if (!property.isConstant()) {
+ const bool hasFormatSectionOverride = property.match(
+ [] (const style::PropertyExpression<typename Property::Type>& e) {
+ return e.getExpression().getKind() == expression::Kind::FormatSectionOverride;
+ },
+ [] (const auto&) {
+ return false;
+ });
+ if (hasFormatSectionOverride) {
+ updated.template get<Property>() = std::move(property);
+ }
+ }
+ }
+
+ template<typename T, typename U>
+ static void updateOverrides(T& evaluated, U& updated) {
+ util::ignore({(updateOverride<PaintProperty>(evaluated, updated), 0)...});
+ }
+
+ template<typename Property, typename FormattedProperty>
+ static bool hasOverride(const FormattedProperty& formatted) {
+ return formatted.match(
+ [] (const TextField::Type& t) {
+ for (const auto& section : t.sections) {
+ if (Property::hasOverride(section)) {
+ return true;
+ }
+ }
+ return false;
+ },
+ [] (const PropertyExpression<TextField::Type>& t) {
+ if (t.getExpression().getKind() == expression::Kind::FormatExpression) {
+ const auto* e = static_cast<const expression::FormatExpression*>(&t.getExpression());
+ for (const auto& section : e->getSections()) {
+ if (Property::hasOverride(section)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ },
+ [] (const auto&) {
+ return false;
+ }
+ );
+ }
+
+ template <typename FormattedProperty>
+ static bool hasOverrides(const FormattedProperty& formatted) {
+ bool result = false;
+ util::ignore({ (result |= hasOverride<PaintProperty>(formatted))... });
+ return result;
+ }
+
+ template <typename PaintProperties>
+ static bool hasPaintPropertyDifference(const PaintProperties& lhs, const PaintProperties& rhs) {
+ bool result = false;
+ util::ignore({ (result |= lhs.template get<PaintProperty>().value.isConstant() &&
+ rhs.template get<PaintProperty>().value.isConstant() &&
+ (lhs.template get<PaintProperty>().value.asConstant() != rhs.template get<PaintProperty>().value.asConstant()))... });
+ return result;
+ }
+};
+
+using SymbolLayerPaintPropertyOverrides = FormatSectionOverrides<SymbolPaintProperties::OverridableProperties>;
+
class SymbolLayer::Impl : public Layer::Impl {
public:
using Layer::Impl::Impl;
@@ -19,6 +113,10 @@ public:
SymbolPaintProperties::Transitionable paint;
DECLARE_LAYER_TYPE_INFO;
+
+private:
+ bool hasFormatSectionOverrides() const;
+ mutable optional<bool> hasFormatSectionOverrides_;
};
} // namespace style
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index d5bdce1f5d..c352ab8e77 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -229,8 +229,11 @@ struct TextOpacity : DataDrivenPaintProperty<float, attributes::a_opacity, unifo
static float defaultValue() { return 1; }
};
-struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color, uniforms::u_fill_color> {
+struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color, uniforms::u_fill_color, true> {
static Color defaultValue() { return Color::black(); }
+ static constexpr const char *name() { return "text-color"; }
+ static constexpr auto expressionType() { return expression::type::ColorType{}; };
+ template<typename T> static bool hasOverride(const T& t) { return !!t.textColor; };
};
struct TextHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color, uniforms::u_halo_color> {
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index 0fcad30cc4..d98a1cbf31 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -16,6 +16,7 @@ public:
using PossiblyEvaluatedType = T;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
template <class T>
@@ -27,6 +28,7 @@ public:
using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>;
using Type = T;
static constexpr bool IsDataDriven = true;
+ static constexpr bool IsOverridable = false;
};
} // namespace style
diff --git a/src/mbgl/style/light_impl.hpp b/src/mbgl/style/light_impl.hpp
index f094c9d462..33db64ae3f 100644
--- a/src/mbgl/style/light_impl.hpp
+++ b/src/mbgl/style/light_impl.hpp
@@ -21,6 +21,7 @@ public:
using PossiblyEvaluatedType = T;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
struct LightAnchor : LightProperty<LightAnchorType> {
diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp
index 343e689a32..7d398748f2 100644
--- a/src/mbgl/style/paint_property.hpp
+++ b/src/mbgl/style/paint_property.hpp
@@ -21,9 +21,10 @@ public:
using PossiblyEvaluatedType = T;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
-template <class T, class A, class U>
+template <class T, class A, class U, bool isOverridable = false>
class DataDrivenPaintProperty {
public:
using TransitionableType = Transitionable<PropertyValue<T>>;
@@ -32,6 +33,7 @@ public:
using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>;
using Type = T;
static constexpr bool IsDataDriven = true;
+ static constexpr bool IsOverridable = isOverridable;
using Attribute = A;
using AttributeList = TypeList<A>;
@@ -48,6 +50,7 @@ public:
using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<Faded<T>>;
using Type = T;
static constexpr bool IsDataDriven = true;
+ static constexpr bool IsOverridable = false;
using Attribute = A1;
using AttributeList = TypeList<A1, A2>;
@@ -64,6 +67,7 @@ public:
using PossiblyEvaluatedType = Faded<T>;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
/*
@@ -84,6 +88,7 @@ public:
using PossiblyEvaluatedType = Color;
using Type = Color;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
static Color defaultValue() { return {}; }
};
diff --git a/src/mbgl/style/properties.hpp b/src/mbgl/style/properties.hpp
index d836735c65..7f58ff223d 100644
--- a/src/mbgl/style/properties.hpp
+++ b/src/mbgl/style/properties.hpp
@@ -99,6 +99,9 @@ public:
template <class P>
struct IsDataDriven : std::integral_constant<bool, P::IsDataDriven> {};
+template <class P>
+struct IsOverridable : std::integral_constant<bool, P::IsOverridable> {};
+
template <class... Ps>
class Properties {
public:
@@ -122,6 +125,7 @@ public:
using EvaluatedTypes = TypeList<typename Ps::Type...>;
using DataDrivenProperties = FilteredTypeList<PropertyTypes, IsDataDriven>;
+ using OverridableProperties = FilteredTypeList<PropertyTypes, IsOverridable>;
template <class TypeList>
using Tuple = IndexedTuple<PropertyTypes, TypeList>;
diff --git a/src/mbgl/style/property_expression.cpp b/src/mbgl/style/property_expression.cpp
new file mode 100644
index 0000000000..9ebecc4b40
--- /dev/null
+++ b/src/mbgl/style/property_expression.cpp
@@ -0,0 +1,68 @@
+#include <mbgl/style/property_expression.hpp>
+
+namespace mbgl {
+namespace style {
+
+PropertyExpressionBase::PropertyExpressionBase(std::unique_ptr<expression::Expression> expression_)
+ : expression(std::move(expression_)),
+ zoomCurve(expression::findZoomCurveChecked(expression.get())) {
+ isZoomConstant_ = expression::isZoomConstant(*expression);
+ isFeatureConstant_ = expression::isFeatureConstant(*expression);
+}
+
+bool PropertyExpressionBase::isZoomConstant() const noexcept {
+ return isZoomConstant_;
+}
+
+bool PropertyExpressionBase::isFeatureConstant() const noexcept {
+ return isFeatureConstant_;
+}
+
+bool PropertyExpressionBase::canEvaluateWith(const expression::EvaluationContext& context) const noexcept {
+ if (context.zoom) {
+ if (context.feature != nullptr) {
+ return !isFeatureConstant();
+ }
+ return !isZoomConstant() && isFeatureConstant();
+ }
+
+ if (context.feature != nullptr) {
+ return isZoomConstant() && !isFeatureConstant();
+ }
+
+ return true;
+}
+
+float PropertyExpressionBase::interpolationFactor(const Range<float>& inputLevels, const float inputValue) const noexcept {
+ 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;
+ }
+ );
+}
+
+Range<float> PropertyExpressionBase::getCoveringStops(const float lower, const float upper) const noexcept {
+ return zoomCurve.match(
+ [](std::nullptr_t) {
+ assert(false);
+ return Range<float>(0.0f, 0.0f);
+ },
+ [&](auto z) {
+ return z->getCoveringStops(lower, upper);
+ }
+ );
+}
+
+const expression::Expression& PropertyExpressionBase::getExpression() const noexcept {
+ return *expression;
+}
+
+} // namespace style
+} // namespace mbgl