From 8be135231d9efe41a3b12037518d02b36104e8cf Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 11 Mar 2019 10:26:19 +0200 Subject: [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 --- test/style/property_expression.test.cpp | 50 +++++++++++++++++++ test/style/style_layer.test.cpp | 87 +++++++++++++++++++++++++++++++-- test/text/tagged_string.test.cpp | 10 ++-- test/util/merge_lines.test.cpp | 2 +- 4 files changed, 140 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/test/style/property_expression.test.cpp b/test/style/property_expression.test.cpp index e4ee5f115f..75c8c59490 100644 --- a/test/style/property_expression.test.cpp +++ b/test/style/property_expression.test.cpp @@ -5,9 +5,11 @@ #include #include #include +#include using namespace mbgl; using namespace mbgl::style; +using namespace mbgl::style::expression; using namespace mbgl::style::expression::dsl; using namespace std::string_literals; @@ -24,10 +26,23 @@ static StubGeometryTileFeature oneString { PropertyMap {{ "property", "1"s }} }; +static StubGeometryTileFeature oneColor { + PropertyMap {{ "color", "red"s }} +}; + float evaluate(PropertyValue value, float zoom) { return value.evaluate(PropertyEvaluator(PropertyEvaluationParameters(zoom), 0)); } +template +auto createOverride(expression::type::Type exprType, + PossiblyEvaluatedPropertyValue propValue, + std::string propName) { + return std::make_unique>(std::move(exprType), + std::move(propValue), + std::move(propName)); +} + TEST(PropertyExpression, Constant) { EXPECT_EQ(2.0f, evaluate(PropertyValue(2.0), 0)); EXPECT_EQ(3.8f, evaluate(PropertyValue(3.8), 0)); @@ -121,3 +136,38 @@ TEST(PropertyExpression, Issue8460) { EXPECT_NEAR(600.0f, fn2.evaluate(18.0f, oneInteger, -1.0f), 0.00); EXPECT_NEAR(600.0f, fn2.evaluate(19.0f, oneInteger, -1.0f), 0.00); } + +TEST(PropertyExpression, FormatSectionOverride) { + using Value = expression::Value; + Value formattedSection = + std::unordered_map{ {"text-color", Value{Color::blue()}} }; + auto ctx = expression::EvaluationContext(&oneDouble).withFormattedSection(&formattedSection); + PossiblyEvaluatedPropertyValue constantValueRed(Color::red()); + PossiblyEvaluatedPropertyValue constantValueGreen(Color::green()); + PossiblyEvaluatedPropertyValue ddsValueRed(toColor(string(get("color")))); + + // Evaluation test + { + auto override1 = createOverride(expression::type::Color, constantValueGreen, "text-color"); + PropertyExpression propExpr(std::move(override1)); + EXPECT_EQ(Color::green(), propExpr.evaluate(15.0f, oneDouble, Color())); + EXPECT_EQ(Color::green(), propExpr.evaluate(oneDouble, Color())); + EXPECT_EQ(Color::blue(), propExpr.evaluate(ctx)); + + auto override2 = createOverride(expression::type::Color, ddsValueRed, "text-color"); + PropertyExpression propExprDDS(std::move(override2)); + EXPECT_EQ(Color::red(), propExprDDS.evaluate(oneColor, Color())); + EXPECT_EQ(Color::blue(), propExprDDS.evaluate(ctx)); + } + + // Equality test + { + auto override1 = createOverride(expression::type::Color, constantValueRed, "text-color"); + auto override2 = createOverride(expression::type::Color, constantValueGreen, "text-color"); + auto override3 = createOverride(expression::type::Color, constantValueGreen, "text-halo-color"); + auto override4 = createOverride(expression::type::Color, ddsValueRed, "text-color"); + EXPECT_TRUE(*override1 != *override2); + EXPECT_TRUE(*override2 != *override3); + EXPECT_TRUE(*override1 != *override4); + } +} diff --git a/test/style/style_layer.test.cpp b/test/style/style_layer.test.cpp index 50aa643b50..e58a5fe5d0 100644 --- a/test/style/style_layer.test.cpp +++ b/test/style/style_layer.test.cpp @@ -1,6 +1,5 @@ -#include -#include -#include +#include +#include #include #include #include @@ -16,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -25,6 +27,9 @@ using namespace mbgl; using namespace mbgl::style; +using namespace expression; +using namespace expression::dsl; +using namespace std::literals::string_literals; namespace { @@ -50,6 +55,10 @@ const auto saturation = 1.0f; const auto contrast = 1.0f; const auto duration = 1.0f; +class MockLayoutProperties : public Properties {}; +class MockPaintProperties : public Properties {}; +using MockOverrides = FormatSectionOverrides; + } // namespace TEST(Layer, BackgroundProperties) { @@ -291,3 +300,75 @@ TEST(Layer, DuplicateLayer) { } } +namespace { + +template class PropertyValueType, typename LayoutType> +void testHasOverrides(LayoutType& layout) { + // Undefined + layout.template get() = PropertyValueType(); + EXPECT_FALSE(MockOverrides::hasOverrides(layout.template get())); + + // Constant, no overrides. + layout.template get() = PropertyValueType(Formatted("")); + EXPECT_FALSE(MockOverrides::hasOverrides(layout.template get())); + + // Constant, overridden text-color. + auto formatted = Formatted(""); + formatted.sections.emplace_back("section text"s, nullopt, nullopt, Color::green()); + layout.template get() = PropertyValueType(std::move(formatted)); + EXPECT_TRUE(MockOverrides::hasOverrides(layout.template get())); + + // Expression, no overrides. + auto formatExpr = std::make_unique(std::vector{}); + PropertyExpression propExpr(std::move(formatExpr)); + layout.template get() = PropertyValueType(std::move(propExpr)); + EXPECT_FALSE(MockOverrides::hasOverrides(layout.template get())); + + // Expression, overridden text-color. + FormatExpressionSection section(literal(""), nullopt, nullopt, toColor(literal("red"))); + auto formatExprOverride = std::make_unique(std::vector{section}); + PropertyExpression propExprOverride(std::move(formatExprOverride)); + layout.template get() = PropertyValueType(std::move(propExprOverride)); + EXPECT_TRUE(MockOverrides::hasOverrides(layout.template get())); +} + +} // namespace + +TEST(Layer, SymbolLayerOverrides) { + + // Unevaluated / transitionable. + { + MockLayoutProperties::Unevaluated layout; + testHasOverrides(layout); + + MockPaintProperties::Transitionable current; + MockPaintProperties::Transitionable updated; + current.get() = Transitionable>{{Color::green()}, {}}; + updated.get() = Transitionable>{{Color::green()}, {}}; + EXPECT_FALSE(MockOverrides::hasPaintPropertyDifference(current, updated)); + + current.get() = Transitionable>{{Color::red()}, {}}; + EXPECT_TRUE(MockOverrides::hasPaintPropertyDifference(current, updated)); + } + + // Possibly evaluated. + { + MockLayoutProperties::PossiblyEvaluated layout; + MockPaintProperties::PossiblyEvaluated paint; + testHasOverrides(layout); + + // Constant, overridden text-color. + auto formatted = Formatted(""); + formatted.sections.emplace_back("section text"s, nullopt, nullopt, Color::green()); + layout.get() = PossiblyEvaluatedPropertyValue(std::move(formatted)); + paint.get() = PossiblyEvaluatedPropertyValue{Color::red()}; + EXPECT_TRUE(paint.get().isConstant()); + MockOverrides::setOverrides(layout, paint); + EXPECT_FALSE(paint.get().isConstant()); + + MockPaintProperties::PossiblyEvaluated updated; + updated.get() = PossiblyEvaluatedPropertyValue{Color::red()}; + MockOverrides::updateOverrides(paint, updated); + EXPECT_FALSE(updated.get().isConstant()); + } +} diff --git a/test/text/tagged_string.test.cpp b/test/text/tagged_string.test.cpp index 3c58ccd94b..da1141f00b 100644 --- a/test/text/tagged_string.test.cpp +++ b/test/text/tagged_string.test.cpp @@ -6,22 +6,22 @@ using namespace mbgl; TEST(TaggedString, Trim) { - TaggedString basic(u" \t\ntrim that and not this \n\t", SectionOptions(1.0f, 0)); + TaggedString basic(u" \t\ntrim that and not this \n\t", SectionOptions(1.0f, {})); basic.trim(); EXPECT_EQ(basic.rawText(), u"trim that and not this"); TaggedString twoSections; - twoSections.addSection(u" \t\ntrim that", 1.5f, 1); - twoSections.addSection(u" and not this \n\t", 0.5f, 2); + twoSections.addSection(u" \t\ntrim that", 1.5f, {}); + twoSections.addSection(u" and not this \n\t", 0.5f, {}); twoSections.trim(); EXPECT_EQ(twoSections.rawText(), u"trim that and not this"); - TaggedString empty(u"\n\t\v \r \t\n", SectionOptions(1.0f, 0)); + TaggedString empty(u"\n\t\v \r \t\n", SectionOptions(1.0f, {})); empty.trim(); EXPECT_EQ(empty.rawText(), u""); - TaggedString noTrim(u"no trim!", SectionOptions(1.0f, 0)); + TaggedString noTrim(u"no trim!", SectionOptions(1.0f, {})); noTrim.trim(); EXPECT_EQ(noTrim.rawText(), u"no trim!"); } diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp index f76a1ea72a..1d4b0d230e 100644 --- a/test/util/merge_lines.test.cpp +++ b/test/util/merge_lines.test.cpp @@ -25,7 +25,7 @@ public: SymbolFeature(std::make_unique(std::move(id_), type_, std::move(geometry_), std::move(properties_))) { if (text_) { - formattedText = TaggedString(*text_, SectionOptions(1.0, 0)); + formattedText = TaggedString(*text_, SectionOptions(1.0, {})); } icon = std::move(icon_); index = index_; -- cgit v1.2.1