diff --git a/CMakeLists.txt b/CMakeLists.txt index 38a496d40..b5a5a2792 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,6 +379,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/style/transition_options.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/types.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/undefined.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/style/variable_anchor_offset_collection.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/text/glyph.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/text/glyph_range.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/tile/tile_id.hpp @@ -864,6 +865,7 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/style/style_impl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/style_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/types.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/variable_anchor_offset_collection.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/custom_layer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/custom_layer_render_parameters.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/custom_layer_factory.cpp diff --git a/bazel/core.bzl b/bazel/core.bzl index faad8fbaf..472fde181 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -511,6 +511,7 @@ MLN_CORE_SOURCE = [ "src/mbgl/style/style_impl.cpp", "src/mbgl/style/style_impl.hpp", "src/mbgl/style/types.cpp", + "src/mbgl/style/variable_anchor_offset_collection.cpp", "src/mbgl/text/bidi.hpp", "src/mbgl/text/check_max_angle.cpp", "src/mbgl/text/check_max_angle.hpp", @@ -802,6 +803,7 @@ MLN_CORE_HEADERS = [ "include/mbgl/style/transition_options.hpp", "include/mbgl/style/types.hpp", "include/mbgl/style/undefined.hpp", + "include/mbgl/style/variable_anchor_offset_collection.hpp", "include/mbgl/text/glyph.hpp", "include/mbgl/text/glyph_range.hpp", "include/mbgl/tile/tile_id.hpp", diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 58f6d5cef..a73f6f461 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,11 @@ struct Converter { std::optional operator()(const Convertible& value, Error& error) const; }; +template <> +struct Converter { + std::optional operator()(const Convertible& value, Error& error) const; +}; + template struct Converter> { std::optional> operator()(const Convertible& value, Error& error) const; diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 7e7ccbfd7..cf425b09d 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -320,6 +320,13 @@ struct ValueFactory { static Value make(const Padding& padding) { return padding.serialize(); } }; +template <> +struct ValueFactory { + static Value make(const VariableAnchorOffsetCollection& variableAnchorOffset) { + return variableAnchorOffset.serialize(); + } +}; + template struct ValueFactory && !is_linear_container::value)>> { static Value make(const T& arg) { return {arg}; } @@ -370,6 +377,9 @@ StyleProperty makeStyleProperty(const PropertyValue& value) { [](const Undefined&) -> StyleProperty { return {}; }, [](const Color& c) -> StyleProperty { return {makeValue(c), StyleProperty::Kind::Expression}; }, [](const Padding& p) -> StyleProperty { return {makeValue(p), StyleProperty::Kind::Expression}; }, + [](const VariableAnchorOffsetCollection& v) -> StyleProperty { + return {makeValue(v), StyleProperty::Kind::Expression}; + }, [](const PropertyExpression& fn) -> StyleProperty { return {fn.getExpression().serialize(), StyleProperty::Kind::Expression}; }, diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp index cbd699672..a5d371bd7 100644 --- a/include/mbgl/style/expression/dsl.hpp +++ b/include/mbgl/style/expression/dsl.hpp @@ -43,6 +43,8 @@ std::unique_ptr boolean(std::unique_ptr, std::unique_ptr std::unique_ptr toColor(std::unique_ptr, std::unique_ptr def = nullptr); std::unique_ptr toPadding(std::unique_ptr value, std::unique_ptr def = nullptr); +std::unique_ptr toVariableAnchorOffset(std::unique_ptr, + std::unique_ptr def = nullptr); std::unique_ptr toString(std::unique_ptr, std::unique_ptr def = nullptr); std::unique_ptr toFormatted(std::unique_ptr, std::unique_ptr def = nullptr); std::unique_ptr toImage(std::unique_ptr, std::unique_ptr def = nullptr); diff --git a/include/mbgl/style/expression/type.hpp b/include/mbgl/style/expression/type.hpp index 4d26dac3b..31883b0ef 100644 --- a/include/mbgl/style/expression/type.hpp +++ b/include/mbgl/style/expression/type.hpp @@ -50,6 +50,12 @@ struct PaddingType { bool operator==(const PaddingType&) const { return true; } }; +struct VariableAnchorOffsetCollectionType { + constexpr VariableAnchorOffsetCollectionType() = default; + std::string getName() const { return "variableAnchorOffsetCollection"; } + bool operator==(const VariableAnchorOffsetCollectionType&) const { return true; } +}; + struct ObjectType { constexpr ObjectType() = default; std::string getName() const { return "object"; } @@ -92,6 +98,7 @@ constexpr StringType String; constexpr BooleanType Boolean; constexpr ColorType Color; constexpr PaddingType Padding; +constexpr VariableAnchorOffsetCollectionType VariableAnchorOffsetCollection; constexpr ValueType Value; constexpr ObjectType Object; constexpr CollatorType Collator; @@ -107,6 +114,7 @@ using Type = variant, diff --git a/include/mbgl/style/expression/value.hpp b/include/mbgl/style/expression/value.hpp index d4f72d7af..d7a305ac3 100644 --- a/include/mbgl/style/expression/value.hpp +++ b/include/mbgl/style/expression/value.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ using ValueBase = variant <% if (type === 'symbol') { -%> #include +#include <% } -%> #include diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 31fb64da9..4d565cb9b 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -184,6 +185,10 @@ public: const PropertyValue>& getTextVariableAnchor() const; void setTextVariableAnchor(const PropertyValue>&); + static PropertyValue getDefaultTextVariableAnchorOffset(); + const PropertyValue& getTextVariableAnchorOffset() const; + void setTextVariableAnchorOffset(const PropertyValue&); + static PropertyValue> getDefaultTextWritingMode(); const PropertyValue>& getTextWritingMode() const; void setTextWritingMode(const PropertyValue>&); diff --git a/include/mbgl/style/variable_anchor_offset_collection.hpp b/include/mbgl/style/variable_anchor_offset_collection.hpp new file mode 100644 index 000000000..5a0948adb --- /dev/null +++ b/include/mbgl/style/variable_anchor_offset_collection.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace mbgl { + +struct AnchorOffsetPair { + style::SymbolAnchorType anchorType; + std::array offset; + + AnchorOffsetPair(style::SymbolAnchorType anchorType_, std::array offset_) + : anchorType(anchorType_), + offset(offset_) {} + + bool operator==(const AnchorOffsetPair& other) const = default; +}; + +class VariableAnchorOffsetCollection { +private: + using CollectionType = std::vector; + CollectionType anchorOffsets; + +public: + VariableAnchorOffsetCollection() = default; + + VariableAnchorOffsetCollection(const VariableAnchorOffsetCollection& other) = default; + + VariableAnchorOffsetCollection(VariableAnchorOffsetCollection&& other) noexcept = default; + + VariableAnchorOffsetCollection(std::vector&& values) { anchorOffsets = std::move(values); } + + std::array getOffsetByAnchor(const style::SymbolAnchorType& anchorType) const; + + std::string toString() const; + + mbgl::Value serialize() const; + + bool empty() const { return anchorOffsets.size() == 0; } + + CollectionType::size_type size() const { return anchorOffsets.size(); } + + CollectionType::const_iterator begin() const { return anchorOffsets.begin(); } + + CollectionType::const_iterator end() const { return anchorOffsets.end(); } + + const AnchorOffsetPair& operator[](size_t index) const { return anchorOffsets[index]; } + + VariableAnchorOffsetCollection& operator=(const VariableAnchorOffsetCollection& other) = default; + + VariableAnchorOffsetCollection& operator=(VariableAnchorOffsetCollection&& other) noexcept = default; + + bool operator==(const VariableAnchorOffsetCollection& other) const = default; +}; + +} // namespace mbgl diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index 8199bd944..509d721d4 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -3,8 +3,12 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include @@ -143,6 +147,36 @@ public: } }; +template <> +struct Interpolator { +public: + VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, + const VariableAnchorOffsetCollection& b, + const float t) const { + if (a.size() != b.size()) { + throw std::runtime_error("Cannot interpolate values of different length. from: " + a.toString() + + ", to: " + b.toString()); + } + std::vector offsetMap; + offsetMap.reserve(a.size()); + for (size_t index = 0; index < a.size(); index++) { + const auto& aPair = a[index]; + const auto& bPair = b[index]; + if (aPair.anchorType != bPair.anchorType) { + throw std::runtime_error( + "Cannot interpolate values containing mismatched anchors. index: " + util::toString(index) + + "from: " + Enum::toString(aPair.anchorType) + + ", to: " + Enum::toString(bPair.anchorType)); + } + auto offset = std::array{interpolate(aPair.offset[0], bPair.offset[0], t), + interpolate(aPair.offset[1], bPair.offset[1], t)}; + offsetMap.emplace_back(aPair.anchorType, offset); + } + + return VariableAnchorOffsetCollection(std::move(offsetMap)); + } +}; + template <> struct Interpolator { public: diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json new file mode 100644 index 000000000..9953c2ea9 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 8, + 13, + 37, + 1, + [ + 90448, + 90448 + ], + [ + 100366, + 100366 + ], + [ + 1337984, + 1337984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json new file mode 100644 index 000000000..dca033517 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 4, + 686859 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 1, + 5, + 9, + 1, + [ + 52212, + 52212 + ], + [ + 5494, + 5494 + ], + [ + 73024, + 73024 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json new file mode 100644 index 000000000..806d886e7 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json new file mode 100644 index 000000000..806d886e7 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json new file mode 100644 index 000000000..806d886e7 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json new file mode 100644 index 000000000..806d886e7 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json new file mode 100644 index 000000000..9f7789217 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 6, + 19, + 1, + [ + 32043, + 32043 + ], + [ + 422, + 422 + ], + [ + 4928, + 4928 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json new file mode 100644 index 000000000..2a7b3b9cd --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 12, + 27, + 1, + [ + 215680, + 215680 + ], + [ + 406, + 406 + ], + [ + 3744, + 3744 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json new file mode 100644 index 000000000..9dca847cb --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 32566, + 32566 + ], + [ + 433984, + 433984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json new file mode 100644 index 000000000..a8acd8972 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 10870, + 10870 + ], + [ + 144704, + 144704 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json new file mode 100644 index 000000000..40b67f144 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 118, + 118 + ], + [ + 768, + 768 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json new file mode 100644 index 000000000..74f5df99b --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1198157 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 7, + 17, + 1, + [ + 171106, + 171106 + ], + [ + 22450, + 22450 + ], + [ + 264688, + 264688 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/cache-style.db b/metrics/cache-style.db index 7fbe6a9aa..2368b94aa 100644 Binary files a/metrics/cache-style.db and b/metrics/cache-style.db differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/expected.png new file mode 100644 index 000000000..38a36fcec Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/style.json new file mode 100644 index 000000000..f56251a14 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/style.json @@ -0,0 +1,66 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "icon-image": "motorway_lg_6", + "icon-text-fit": "both", + "icon-text-fit-padding": [5, 5, 5, 5], + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 0], + "bottom", [0, 0], + "left", [0, 0], + "right", [0, 0], + "top-left", [0, 0], + "top-right", [0, 0], + "bottom-left", [0, 0], + "bottom-right", [0, 0] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/expected.png new file mode 100644 index 000000000..02b933be2 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/style.json new file mode 100644 index 000000000..ee7b23c34 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/style.json @@ -0,0 +1,65 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256, + "allowed": 0.003 + } + }, + "center": [ + 13.418056, + 52.501000 + ], + "zoom": 16, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-allow-overlap": true, + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 1], + "bottom", [0, -1], + "left", [1, 0], + "right", [-1, 0], + "top-left", [1, 1], + "top-right", [-1, 1], + "bottom-left", [1, -1], + "bottom-right", [-1, -1] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/expected.png new file mode 100644 index 000000000..ed2122a69 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/style.json new file mode 100644 index 000000000..7d74b15a5 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/style.json @@ -0,0 +1,122 @@ +{ + "version": 8, + "metadata": { + "test": { + "description": "All 8 anchor positions specified, custom offsets to distinguish top-left and bottom-right", + "height": 128, + "width": 128 + } + }, + "center": [ 0, 0 ], + "zoom": 0, + "sources": { + "point": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + } + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "text", + "type": "symbol", + "source": "point", + "layout": { + "text-field": "x", + "text-size": 20, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 1], + "bottom", [0, -1], + "left", [1, 0], + "right", [-1, 0], + "top-left", [1, 1], + "top-right", [-0.5, 1], + "bottom-left", [0.5, -1], + "bottom-right", [-1, -1] + ], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "anchor", + "type": "circle", + "source": "point", + "paint" :{ + "circle-color": "#f00", + "circle-radius": 4 + } + } + ] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png new file mode 100644 index 000000000..309c9039a Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/style.json new file mode 100644 index 000000000..ea7a2e13c --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/style.json @@ -0,0 +1,56 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 240, + "height": 100 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [{ + "type": "Feature", + "properties": { }, + "geometry": { "type": "Point", "coordinates": [-30, 0] } + }, { + "type": "Feature", + "properties": { "tvao": ["top", [0, -4.5]] }, + "geometry": { "type": "Point", "coordinates": [0, 0] } + }, { + "type": "Feature", + "properties": { "tvao": ["right", [4.5, 0]] }, + "geometry": { "type": "Point", "coordinates": [30, 0] } + } + ] + } + } + }, + "sprite": "local://sprites/2x", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [{ + "id": "bg", + "type": "background", + "paint": { + "background-color": "#ccc" + } + }, { + "id": "test", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": "icon", + "text-field": "Label", + "text-size": 10, + "text-justify": "auto", + "text-variable-anchor-offset": ["coalesce", ["get", "tvao"], ["literal", ["left", [-4.5, 0]]]], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + } + ] +} \ No newline at end of file diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png new file mode 100644 index 000000000..819011015 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/style.json new file mode 100644 index 000000000..f18f9fff7 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/style.json @@ -0,0 +1,56 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 240, + "height": 100 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [{ + "type": "Feature", + "properties": { "x": 0}, + "geometry": { "type": "Point", "coordinates": [-30, 0] } + }, { + "type": "Feature", + "properties": { "x": 5}, + "geometry": { "type": "Point", "coordinates": [0, 0] } + }, { + "type": "Feature", + "properties": { "x": 10}, + "geometry": { "type": "Point", "coordinates": [30, 0] } + } + ] + } + } + }, + "sprite": "local://sprites/2x", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [{ + "id": "bg", + "type": "background", + "paint": { + "background-color": "#ccc" + } + }, { + "id": "test", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": "icon", + "text-field": "Label", + "text-size": 10, + "text-justify": "auto", + "text-variable-anchor-offset": ["interpolate", ["linear"], ["get", "x"], 1, ["literal", ["top", [-3, -3]]], 10, ["literal", ["top", [3, 3]]]], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + } + ] + } \ No newline at end of file diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/expected.png new file mode 100644 index 000000000..2b52e1bd4 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/style.json new file mode 100644 index 000000000..a3b03852b --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/style.json @@ -0,0 +1,73 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 128, + "width": 128 + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "image": "bank-12" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 0, + -10 + ] + } + }, + { + "type": "Feature", + "properties": { + "image": "bakery-12" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 0, + 10 + ] + } + } + ] + } + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "text", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": ["get", "image"], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-justify": "auto", + "text-variable-anchor-offset" : [ + "top", [0, 0.5], + "bottom", [0, -0.5], + "left", [0.5, 0], + "right", [-0.5, 0], + "top-left", [0.5, 0.5], + "top-right", [-0.5, 0.5], + "bottom-left", [0.5, -0.5], + "bottom-right", [-0.5, -0.5] + ], + "text-field": ["get", "image"] + } + } + ] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/expected.png new file mode 100644 index 000000000..32caa9ba8 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/style.json new file mode 100644 index 000000000..5d40ad76b --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/style.json @@ -0,0 +1,103 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 128, + "width": 128 + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sources": { + "icon": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [{ + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }] + } + }, + "text": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] + } + } + }, + "sprite": "local://sprites/icon-offset", + "layers": [ + { + "id": "icon", + "type": "symbol", + "source": "icon", + "layout": { + "icon-anchor": "bottom", + "icon-image": "icon" + } + }, + { + "id": "text", + "type": "symbol", + "source": "text", + "layout": { + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-justify": "auto", + "text-variable-anchor-offset" : [ + "top", [0, 0.8], + "bottom", [0, -2.5], + "left", [1.2, -1.5], + "right", [-1.2, -1.5], + "top-left", [1.2, 0], + "top-right", [-1.2, 0] + ], + "text-field": "Test" + } + } + ] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-image/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image/expected.png new file mode 100644 index 000000000..62599fec5 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-image/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image/style.json new file mode 100644 index 000000000..3f78695bf --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/icon-image/style.json @@ -0,0 +1,67 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 128, + "width": 128 + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "image": "bank-12" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 0, + -10 + ] + } + }, + { + "type": "Feature", + "properties": { + "image": "bakery-12" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 0, + 10 + ] + } + } + ] + } + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "text", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": ["get", "image"], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-justify": "auto", + "text-variable-anchor-offset" : [ + "top", [1, 0.5], + "bottom", [-1, -0.5] + ], + "text-field": ["get", "image"] + } + } + ] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/expected.png new file mode 100644 index 000000000..840debc8d Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/style.json new file mode 100644 index 000000000..0e87f114b --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/style.json @@ -0,0 +1,71 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 128, + "width": 128, + "allowed": 0.0075, + "collisionDebug": true + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "image": "motorway_lg_4" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 0, + -10 + ] + } + }, + { + "type": "Feature", + "properties": { + "image": "motorway_lg_6" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 0, + 10 + ] + } + } + ] + } + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "text", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": ["get", "image"], + "icon-text-fit": "both", + "icon-text-fit-padding": [8, 8, 8, 8], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-justify": "auto", + "text-variable-anchor-offset" : [ + "top-left", [0.5, 0.5], + "bottom-right", [-0.5, -0.5] + ], + "text-field": ["get", "image"] + } + } + ] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/expected.png new file mode 100644 index 000000000..ba66232da Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/style.json new file mode 100644 index 000000000..1836f862d --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/style.json @@ -0,0 +1,89 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256, + "width": 256, + "fadeDuration": 100, + "description": "Start with space for two labels. Zoom out so that second has to switch anchors. Render after half a fade duration, but verify that label has moved the whole way.", + "operations": [ + ["wait", 100], + ["wait", 100], + ["setZoom", 0.5], + ["wait"], + ["wait", 100], + [ + "wait", + 50 + ] + ] + } + }, + "center": [ 0, 0 ], + "zoom": 1.5, + "sources": { + "point": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "First" + }, + "geometry": { + "type": "Point", + "coordinates": [ 10, 0 ] + } + }, + { + "type": "Feature", + "properties": { + "name": "Second" + }, + "geometry": { + "type": "Point", + "coordinates": [ -10, 0 ] + } + }] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "text", + "type": "symbol", + "source": "point", + "layout": { + "text-field": ["get", "name"], + "text-size": 20, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "left", [0.5, 0], + "right", [-0.5, 0] + ], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "anchor", + "type": "circle", + "source": "point", + "paint" :{ + "circle-radius": 2 + } + } + ] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/expected.png new file mode 100644 index 000000000..6b5d70237 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/style.json new file mode 100644 index 000000000..816939227 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/style.json @@ -0,0 +1,68 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256, + "operations": [ + ["idle"], + ["wait", 500] + ] + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "pitch": 60, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 5], + "bottom", [0, -5], + "left", [5, 0], + "right", [-5, 0], + "top-left", [5, 5], + "top-right", [-5, 5], + "bottom-left", [5, -5], + "bottom-right", [-5, -5] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/expected.png new file mode 100644 index 000000000..8b0da17d9 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/style.json new file mode 100644 index 000000000..3fe64bd74 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/style.json @@ -0,0 +1,69 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256, + "operations": [ + ["idle"], + ["wait", 500] + ] + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "pitch": 60, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-pitch-alignment": "map", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 0], + "bottom", [0, 0], + "left", [0, 0], + "right", [0, 0], + "top-left", [0, 0], + "top-right", [0, 0], + "bottom-left", [0, 0], + "bottom-right", [0, 0] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/pitched/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/pitched/expected.png new file mode 100644 index 000000000..4750b301d Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/pitched/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/pitched/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/pitched/style.json new file mode 100644 index 000000000..7d40c7996 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/pitched/style.json @@ -0,0 +1,65 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256, + "operations": [["idle"], ["wait", 300]] + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "pitch": 60, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 0], + "bottom", [0, 0], + "left", [0, 0], + "right", [0, 0], + "top-left", [0, 0], + "top-right", [0, 0], + "bottom-left", [0, 0], + "bottom-right", [0, 0] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/expected.png new file mode 100644 index 000000000..e6f11ba15 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/style.json new file mode 100644 index 000000000..a77786522 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/style.json @@ -0,0 +1,64 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "bearing": 90, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 5], + "bottom", [0, -5], + "left", [5, 0], + "right", [-5, 0], + "top-left", [5, 5], + "top-right", [-5, 5], + "bottom-left", [5, -5], + "bottom-right", [-5, -5] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/expected.png new file mode 100644 index 000000000..a7598d9d6 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/style.json new file mode 100644 index 000000000..06bf9b9e5 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/style.json @@ -0,0 +1,66 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256, + "description": "Note that there are collisions in this example. This is because of the limitation that collision boxes don't rotate; however, their position should still be correct." + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "bearing": 90, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-rotation-alignment": "map", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 0], + "bottom", [0, 0], + "left", [0, 0], + "right", [0, 0], + "top-left", [0, 0], + "top-right", [0, 0], + "bottom-left", [0, 0], + "bottom-right", [0, 0] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/rotated/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/rotated/expected.png new file mode 100644 index 000000000..d3142f71a Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/rotated/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/rotated/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/rotated/style.json new file mode 100644 index 000000000..86f84359b --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/rotated/style.json @@ -0,0 +1,64 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "bearing": 90, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 0], + "bottom", [0, 0], + "left", [0, 0], + "right", [0, 0], + "top-left", [0, 0], + "top-right", [0, 0], + "bottom-left", [0, 0], + "bottom-right", [0, 0] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/single-justification/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/single-justification/expected.png new file mode 100644 index 000000000..28c2d72b6 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/single-justification/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/single-justification/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/single-justification/style.json new file mode 100644 index 000000000..35b3b163e --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/single-justification/style.json @@ -0,0 +1,63 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test Test Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "left", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 0], + "bottom", [0, 0], + "left", [0, 0], + "right", [0, 0], + "top-left", [0, 0], + "top-right", [0, 0], + "bottom-left", [0, 0], + "bottom-right", [0, 0] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/single-line/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/single-line/expected.png new file mode 100644 index 000000000..9559860ee Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/single-line/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/single-line/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/single-line/style.json new file mode 100644 index 000000000..1ed7aae88 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/single-line/style.json @@ -0,0 +1,64 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256, + "description": "Single line labels render differently because they use the same glyphs for all justifications." + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "text-field": "Test", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 5, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "center", [0, 0], + "top", [0, 0], + "bottom", [0, 0], + "left", [0, 0], + "right", [0, 0], + "top-left", [0, 0], + "top-right", [0, 0], + "bottom-left", [0, 0], + "bottom-right", [0, 0] + ] + } + }] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/expected.png new file mode 100644 index 000000000..b59d67799 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/style.json new file mode 100644 index 000000000..d636697bd --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/style.json @@ -0,0 +1,82 @@ +{ + "version": 8, + "metadata": { + "test": { + "description": "Even though text-overlap is set to true, all four possible anchor positions are used to avoid unnecessary overlap", + "height": 128, + "width": 128 + } + }, + "center": [ 0, 0 ], + "zoom": 0, + "sources": { + "point": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + } + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "text", + "type": "symbol", + "source": "point", + "layout": { + "text-field": "x", + "text-size": 20, + "text-justify": "auto", + "text-allow-overlap": true, + "text-variable-anchor-offset": [ + "left", [0.7, 0], + "right", [-0.7, 0], + "top", [0, 0.5], + "bottom", [0, -0.5] + ], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "anchor", + "type": "circle", + "source": "point", + "paint" :{ + "circle-radius": 2 + } + } + ] +} diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/expected.png new file mode 100644 index 000000000..663fa5fb7 Binary files /dev/null and b/metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/expected.png differ diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/style.json new file mode 100644 index 000000000..d310fab36 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/style.json @@ -0,0 +1,74 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14.5, + "sources": { + "maplibre": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "top", + "type": "symbol", + "source": "maplibre", + "source-layer": "poi_label", + "filter": ["all", [ + "==", + "maki", + "restaurant" + ] + ], + "layout": { + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-field": ["get", "name"], + "text-size": 12, + "text-justify": "auto", + "text-variable-anchor-offset": [ + "top", [0, 0.1], + "bottom", [0, -0.1], + "left", [0.5, 0], + "right", [-0.5, 0] + ] + } + }, + { + "id": "circles", + "type": "circle", + "source": "maplibre", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "paint": { + "circle-radius": 2 + } + } + ] +} diff --git a/metrics/integration/sprites/icon-offset.json b/metrics/integration/sprites/icon-offset.json new file mode 100644 index 000000000..e8e15268e --- /dev/null +++ b/metrics/integration/sprites/icon-offset.json @@ -0,0 +1,9 @@ +{ + "icon": { + "width": 20, + "height": 32, + "x": 0, + "y": 0, + "pixelRatio": 1 + } +} \ No newline at end of file diff --git a/metrics/integration/sprites/icon-offset.png b/metrics/integration/sprites/icon-offset.png new file mode 100644 index 000000000..b112096c1 Binary files /dev/null and b/metrics/integration/sprites/icon-offset.png differ diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json new file mode 100644 index 000000000..9953c2ea9 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 8, + 13, + 37, + 1, + [ + 90448, + 90448 + ], + [ + 100366, + 100366 + ], + [ + 1337984, + 1337984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json new file mode 100644 index 000000000..dca033517 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 4, + 686859 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 1, + 5, + 9, + 1, + [ + 52212, + 52212 + ], + [ + 5494, + 5494 + ], + [ + 73024, + 73024 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json new file mode 100644 index 000000000..dfa752091 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 238, + 238 + ], + [ + 1648, + 1648 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json new file mode 100644 index 000000000..7bbece367 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 86050 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 6, + 13, + 1, + [ + 42916, + 42916 + ], + [ + 322, + 322 + ], + [ + 4064, + 4064 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json new file mode 100644 index 000000000..9f7789217 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 6, + 19, + 1, + [ + 32043, + 32043 + ], + [ + 422, + 422 + ], + [ + 4928, + 4928 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json new file mode 100644 index 000000000..2a7b3b9cd --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 12, + 27, + 1, + [ + 215680, + 215680 + ], + [ + 406, + 406 + ], + [ + 3744, + 3744 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json new file mode 100644 index 000000000..9dca847cb --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 32566, + 32566 + ], + [ + 433984, + 433984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json new file mode 100644 index 000000000..a8acd8972 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 10870, + 10870 + ], + [ + 144704, + 144704 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json new file mode 100644 index 000000000..40b67f144 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 118, + 118 + ], + [ + 768, + 768 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json new file mode 100644 index 000000000..74f5df99b --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1198157 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 7, + 17, + 1, + [ + 171106, + 171106 + ], + [ + 22450, + 22450 + ], + [ + 264688, + 264688 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json new file mode 100644 index 000000000..9953c2ea9 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 8, + 13, + 37, + 1, + [ + 90448, + 90448 + ], + [ + 100366, + 100366 + ], + [ + 1337984, + 1337984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json new file mode 100644 index 000000000..dca033517 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 4, + 686859 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 1, + 5, + 9, + 1, + [ + 52212, + 52212 + ], + [ + 5494, + 5494 + ], + [ + 73024, + 73024 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json new file mode 100644 index 000000000..dfa752091 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 238, + 238 + ], + [ + 1648, + 1648 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json new file mode 100644 index 000000000..7bbece367 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 86050 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 6, + 13, + 1, + [ + 42916, + 42916 + ], + [ + 322, + 322 + ], + [ + 4064, + 4064 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json new file mode 100644 index 000000000..9f7789217 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 6, + 19, + 1, + [ + 32043, + 32043 + ], + [ + 422, + 422 + ], + [ + 4928, + 4928 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json new file mode 100644 index 000000000..2a7b3b9cd --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 12, + 27, + 1, + [ + 215680, + 215680 + ], + [ + 406, + 406 + ], + [ + 3744, + 3744 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json new file mode 100644 index 000000000..9dca847cb --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 32566, + 32566 + ], + [ + 433984, + 433984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json new file mode 100644 index 000000000..a8acd8972 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 10870, + 10870 + ], + [ + 144704, + 144704 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json new file mode 100644 index 000000000..40b67f144 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 118, + 118 + ], + [ + 768, + 768 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json new file mode 100644 index 000000000..74f5df99b --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1198157 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 7, + 17, + 1, + [ + 171106, + 171106 + ], + [ + 22450, + 22450 + ], + [ + 264688, + 264688 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json new file mode 100644 index 000000000..9953c2ea9 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 8, + 13, + 37, + 1, + [ + 90448, + 90448 + ], + [ + 100366, + 100366 + ], + [ + 1337984, + 1337984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json new file mode 100644 index 000000000..dca033517 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 4, + 686859 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 1, + 5, + 9, + 1, + [ + 52212, + 52212 + ], + [ + 5494, + 5494 + ], + [ + 73024, + 73024 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json new file mode 100644 index 000000000..dfa752091 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 238, + 238 + ], + [ + 1648, + 1648 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json new file mode 100644 index 000000000..7bbece367 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 86050 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 6, + 13, + 1, + [ + 42916, + 42916 + ], + [ + 322, + 322 + ], + [ + 4064, + 4064 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json new file mode 100644 index 000000000..9f7789217 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 6, + 19, + 1, + [ + 32043, + 32043 + ], + [ + 422, + 422 + ], + [ + 4928, + 4928 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json new file mode 100644 index 000000000..2a7b3b9cd --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 12, + 27, + 1, + [ + 215680, + 215680 + ], + [ + 406, + 406 + ], + [ + 3744, + 3744 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json new file mode 100644 index 000000000..9dca847cb --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 32566, + 32566 + ], + [ + 433984, + 433984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json new file mode 100644 index 000000000..a8acd8972 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 10870, + 10870 + ], + [ + 144704, + 144704 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json new file mode 100644 index 000000000..40b67f144 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 118, + 118 + ], + [ + 768, + 768 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json new file mode 100644 index 000000000..74f5df99b --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1198157 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 7, + 17, + 1, + [ + 171106, + 171106 + ], + [ + 22450, + 22450 + ], + [ + 264688, + 264688 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json new file mode 100644 index 000000000..9953c2ea9 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 8, + 13, + 37, + 1, + [ + 90448, + 90448 + ], + [ + 100366, + 100366 + ], + [ + 1337984, + 1337984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json new file mode 100644 index 000000000..dca033517 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 4, + 686859 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 1, + 5, + 9, + 1, + [ + 52212, + 52212 + ], + [ + 5494, + 5494 + ], + [ + 73024, + 73024 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json new file mode 100644 index 000000000..dfa752091 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 238, + 238 + ], + [ + 1648, + 1648 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json new file mode 100644 index 000000000..d4202bfa2 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 87036 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 38722, + 38722 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json new file mode 100644 index 000000000..7bbece367 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 86050 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 6, + 13, + 1, + [ + 42916, + 42916 + ], + [ + 322, + 322 + ], + [ + 4064, + 4064 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json new file mode 100644 index 000000000..031fe7104 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 13, + 1, + [ + 28467, + 28467 + ], + [ + 238, + 238 + ], + [ + 2944, + 2944 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json new file mode 100644 index 000000000..9f7789217 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 3, + 296601 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 6, + 19, + 1, + [ + 32043, + 32043 + ], + [ + 422, + 422 + ], + [ + 4928, + 4928 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json new file mode 100644 index 000000000..2a7b3b9cd --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 12, + 27, + 1, + [ + 215680, + 215680 + ], + [ + 406, + 406 + ], + [ + 3744, + 3744 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched/metrics.json new file mode 100644 index 000000000..b06ed0feb --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 11, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 21, + 21, + 1, + [ + 274384, + 274384 + ], + [ + 97654, + 97654 + ], + [ + 1301824, + 1301824 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated/metrics.json new file mode 100644 index 000000000..33eed36df --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 5, + 1004220 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 7, + 13, + 1, + [ + 71656, + 71656 + ], + [ + 48406, + 48406 + ], + [ + 645184, + 645184 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json new file mode 100644 index 000000000..9dca847cb --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 32566, + 32566 + ], + [ + 433984, + 433984 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-line/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-line/metrics.json new file mode 100644 index 000000000..a8acd8972 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-line/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1778473 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 13, + 21, + 1, + [ + 143312, + 143312 + ], + [ + 10870, + 10870 + ], + [ + 144704, + 144704 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json new file mode 100644 index 000000000..40b67f144 --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 1, + 84942 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 2, + 4, + 11, + 1, + [ + 33209, + 33209 + ], + [ + 118, + 118 + ], + [ + 768, + 768 + ] + ] + ] +} \ No newline at end of file diff --git a/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json new file mode 100644 index 000000000..74f5df99b --- /dev/null +++ b/metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 7, + 1198157 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 4, + 7, + 17, + 1, + [ + 171106, + 171106 + ], + [ + 22450, + 22450 + ], + [ + 264688, + 264688 + ] + ] + ] +} \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp index 915bc6dc7..44321e488 100644 --- a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp @@ -44,6 +44,25 @@ Result>> Converter>, Padding>: return result; } +Result>> Converter>, VariableAnchorOffsetCollection>::operator()( + jni::JNIEnv& env, const VariableAnchorOffsetCollection& value) const { + auto variableAnchorOffsets = jni::Array>::New(env, value.size() * 2); + for (std::size_t i = 0; i < value.size(); i++) { + auto anchorOffsetPair = value[i]; + auto anchorType = jni::Make(env, + Enum::toString(anchorOffsetPair.anchorType)); + auto offset = jni::Array::New(env, anchorOffsetPair.offset.size()); + for (size_t j = 0; j < anchorOffsetPair.offset.size(); j++) { + offset.Set(env, j, jni::Box(env, anchorOffsetPair.offset[j])); + } + + variableAnchorOffsets.Set(env, i, anchorType); + variableAnchorOffsets.Set(env, i + 1, offset); + } + + return variableAnchorOffsets; +} + Result>> Converter>, style::expression::Formatted>::operator()( jni::JNIEnv& env, const style::expression::Formatted& value) const { return Formatted::New(env, value); diff --git a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp index 9a4e05e8e..661a58ce1 100644 --- a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp @@ -8,6 +8,7 @@ #include #include +#include #include @@ -63,6 +64,11 @@ struct Converter>, Padding> { Result>> operator()(jni::JNIEnv& env, const Padding& value) const; }; +template <> +struct Converter>, VariableAnchorOffsetCollection> { + Result>> operator()(jni::JNIEnv& env, const VariableAnchorOffsetCollection& value) const; +}; + template <> struct Converter>, style::expression::Formatted> { Result>> operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const; diff --git a/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.cpp b/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.cpp index 2068aa4c2..7038fc3ec 100644 --- a/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.cpp @@ -189,6 +189,11 @@ jni::Local> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) { return std::move(*convert>>(env, toSymbolLayer(layer).getTextVariableAnchor())); } +jni::Local> SymbolLayer::getTextVariableAnchorOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextVariableAnchorOffset())); +} + jni::Local> SymbolLayer::getTextAnchor(jni::JNIEnv& env) { using namespace mbgl::android::conversion; return std::move(*convert>>(env, toSymbolLayer(layer).getTextAnchor())); @@ -540,6 +545,7 @@ void SymbolJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"), METHOD(&SymbolLayer::getTextRadialOffset, "nativeGetTextRadialOffset"), METHOD(&SymbolLayer::getTextVariableAnchor, "nativeGetTextVariableAnchor"), + METHOD(&SymbolLayer::getTextVariableAnchorOffset, "nativeGetTextVariableAnchorOffset"), METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"), METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"), METHOD(&SymbolLayer::getTextWritingMode, "nativeGetTextWritingMode"), diff --git a/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.hpp b/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.hpp index fc181d185..d7333784c 100644 --- a/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/style/layers/symbol_layer.hpp @@ -86,6 +86,8 @@ public: jni::Local> getTextVariableAnchor(jni::JNIEnv&); + jni::Local> getTextVariableAnchorOffset(jni::JNIEnv&); + jni::Local> getTextAnchor(jni::JNIEnv&); jni::Local> getTextMaxAngle(jni::JNIEnv&); diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/PropertyFactory.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/PropertyFactory.java index 6bb73c6dd..e845ca276 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/PropertyFactory.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/PropertyFactory.java @@ -2387,6 +2387,50 @@ The unit is in density-independent pixels only for SDF sprites that were created return new LayoutPropertyValue<>("text-variable-anchor", value); } + /** + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations, each paired with an offset value. The renderer will attempt to place the label at each location, in order, before moving on to the next location+offset. Use `text-justify: auto` to choose justification based on anchor position. + + The length of the array must be even, and must alternate between enum and point entries. i.e., each anchor location must be accompanied by a point, and that point defines the offset when the corresponding anchor location is used. Positive offset values indicate right and down, while negative values indicate left and up. Anchor locations may repeat, allowing the renderer to try multiple offsets to try and place a label using the same anchor. + + When present, this property takes precedence over {@link Property.TEXT_ANCHOR}, {@link PropertyFactory#textVariableAnchor}, {@link PropertyFactory#textOffset}, and {@link PropertyFactory#textRadialOffset}. + + ```json + { "text-variable-anchor-offset": ["top", [0, 4], "left", [3,0], "bottom", [1, 1]] } + ``` + + When the renderer chooses the `top` anchor, `[0, 4]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted down by 4 ems. + + When the renderer chooses the `left` anchor, `[3, 0]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted right by 3 ems. + * + * @param value a Object[] value + * @return property wrapper around Object[] + */ + public static PropertyValue textVariableAnchorOffset(Object[] value) { + return new LayoutPropertyValue<>("text-variable-anchor-offset", value); + } + + /** + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations, each paired with an offset value. The renderer will attempt to place the label at each location, in order, before moving on to the next location+offset. Use `text-justify: auto` to choose justification based on anchor position. + + The length of the array must be even, and must alternate between enum and point entries. i.e., each anchor location must be accompanied by a point, and that point defines the offset when the corresponding anchor location is used. Positive offset values indicate right and down, while negative values indicate left and up. Anchor locations may repeat, allowing the renderer to try multiple offsets to try and place a label using the same anchor. + + When present, this property takes precedence over {@link Property.TEXT_ANCHOR}, {@link PropertyFactory#textVariableAnchor}, {@link PropertyFactory#textOffset}, and {@link PropertyFactory#textRadialOffset}. + + ```json + { "text-variable-anchor-offset": ["top", [0, 4], "left", [3,0], "bottom", [1, 1]] } + ``` + + When the renderer chooses the `top` anchor, `[0, 4]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted down by 4 ems. + + When the renderer chooses the `left` anchor, `[3, 0]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted right by 3 ems. + * + * @param value a Object[] value + * @return property wrapper around Object[] + */ + public static PropertyValue textVariableAnchorOffset(Expression value) { + return new LayoutPropertyValue<>("text-variable-anchor-offset", value); + } + /** * Part of the text placed closest to the anchor. * diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/SymbolLayer.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/SymbolLayer.java index adc8148e5..8d5212776 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/SymbolLayer.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/SymbolLayer.java @@ -505,6 +505,18 @@ public class SymbolLayer extends Layer { return (PropertyValue) new PropertyValue("text-variable-anchor", nativeGetTextVariableAnchor()); } + /** + * Get the TextVariableAnchorOffset property + * + * @return property wrapper value around Object[] + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getTextVariableAnchorOffset() { + checkThread(); + return (PropertyValue) new PropertyValue("text-variable-anchor-offset", nativeGetTextVariableAnchorOffset()); + } + /** * Get the TextAnchor property * @@ -1245,6 +1257,10 @@ public class SymbolLayer extends Layer { @Keep private native Object nativeGetTextVariableAnchor(); + @NonNull + @Keep + private native Object nativeGetTextVariableAnchorOffset(); + @NonNull @Keep private native Object nativeGetTextAnchor(); diff --git a/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/SymbolLayerTest.java b/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/SymbolLayerTest.java index 425038418..cd1ed59fe 100644 --- a/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/SymbolLayerTest.java +++ b/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/SymbolLayerTest.java @@ -722,6 +722,19 @@ public class SymbolLayerTest extends BaseLayerTest { assertEquals(layer.getTextVariableAnchor().getValue(), propertyValue); } + @Test + @UiThreadTest + public void testTextVariableAnchorOffsetAsConstant() { + Timber.i("text-variable-anchor-offset"); + assertNotNull(layer); + assertNull(layer.getTextVariableAnchorOffset().getValue()); + + // Set and Get + Object[] propertyValue = new Object[] {"top", new Float[]{1f, 2f}}; + layer.setProperties(textVariableAnchorOffset(propertyValue)); + assertEquals(layer.getTextVariableAnchorOffset().getValue(), propertyValue); + } + @Test @UiThreadTest public void testTextAnchorAsConstant() { diff --git a/platform/android/scripts/generate-style-code.mjs b/platform/android/scripts/generate-style-code.mjs index 4afd01a80..53b65babb 100644 --- a/platform/android/scripts/generate-style-code.mjs +++ b/platform/android/scripts/generate-style-code.mjs @@ -120,7 +120,9 @@ global.propertyType = function propertyType(property) { case 'color': return 'String'; case 'padding': - return 'Float[]' + return 'Float[]'; + case 'variableAnchorOffsetCollection': + return 'Object[]'; case 'array': return `${propertyType({type:property.value, name: property.name})}[]`; default: @@ -197,6 +199,8 @@ global.propertyNativeType = function (property) { return `Color`; case 'padding': return 'Padding'; + case 'variableAnchorOffsetCollection': + return 'VariableAnchorOffsetCollection'; case 'array': if (property.length) { return `std::array<${propertyType({type: property.value})}, ${property.length}>`; @@ -269,6 +273,8 @@ global.defaultValueJava = function(property) { return '"rgba(255,128,0,0.7)"'; case 'padding': return '{2.0f, 2.0f, 2.0f, 2.0f}'; + case 'variableAnchorOffsetCollection': + return 'new Object[] {"top", new Float[]{1f, 2f}}'; case 'array': switch (property.value) { case 'string': diff --git a/platform/darwin/scripts/generate-style-code.mjs b/platform/darwin/scripts/generate-style-code.mjs index dc1098448..f532739cd 100644 --- a/platform/darwin/scripts/generate-style-code.mjs +++ b/platform/darwin/scripts/generate-style-code.mjs @@ -25,7 +25,7 @@ function setupGlobalEjsHelpers() { global[funcName] = func; } } - + setupGlobalEjsHelpers(); // Parse command line @@ -208,6 +208,8 @@ global.objCTestValue = function (property, layerType, arraysAsStructs, indent) { return '@"%@", [MLNColor redColor]'; case 'padding': return paddingTestValue(); + case 'variableAnchorOffsetCollection': + return `@"{"top": [1, 2]}"`; case 'array': switch (arrayType(property)) { case 'dasharray': @@ -248,6 +250,7 @@ global.mbglTestValue = function (property, layerType) { case 'formatted': case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': return `"${_.startCase(propertyName)}"`; case 'enum': { let type = camelize(originalPropertyName(property)); @@ -337,6 +340,7 @@ global.testHelperMessage = function (property, layerType, isFunction) { case 'formatted': case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': return 'testString' + fnSuffix; case 'enum': let objCType = global.objCType(layerType, property.name); @@ -547,6 +551,8 @@ global.describeType = function (property) { return 'array'; } break; + case 'variableAnchorOffsetCollection': + return 'interleaved `MLNTextAnchor` and `CGVector` array'; default: throw new Error(`unknown type for ${property.name}`); } @@ -643,6 +649,8 @@ global.describeValue = function (value, property, layerType) { default: return 'the array `' + value.join('`, `') + '`'; } + case 'variableAnchorOffsetCollection': + return 'array of interleaved `MLNTextAnchor` and `CGVector` values'; default: throw new Error(`unknown type for ${property.name}`); } @@ -701,6 +709,8 @@ global.propertyType = function (property) { default: throw new Error(`unknown array type for ${property.name}`); } + case 'variableAnchorOffsetCollection': + return 'NSArray *'; default: throw new Error(`unknown type for ${property.name}`); } @@ -734,6 +744,8 @@ global.valueTransformerArguments = function (property) { return ['mbgl::Color', objCType]; case 'padding': return ['mbgl::Padding', objCType]; + case 'variableAnchorOffsetCollection': + return ['mbgl::VariableAnchorOffsetCollection', objCType]; case 'array': switch (arrayType(property)) { case 'dasharray': @@ -791,6 +803,8 @@ global.mbglType = function(property) { return 'mbgl::Color'; case 'padding': return 'mbgl::Padding'; + case 'variableAnchorOffsetCollection': + return 'mbgl::VariableAnchorOffsetCollection'; case 'array': switch (arrayType(property)) { case 'dasharray': diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index 50f2a8464..f95638eee 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -15,6 +15,7 @@ #import #import #import "MLNConversion.h" +#import "MLNSymbolStyleLayer.h" #import #include @@ -239,6 +240,32 @@ class MLNStyleValueTransformer { // Color void getMBGLValue(MLNColor *rawValue, mbgl::Color &mbglValue) { mbglValue = rawValue.mgl_color; } + // VariableAnchorOffsetCollection + void getMBGLValue(id rawValue, mbgl::VariableAnchorOffsetCollection &mbglValue) { + if ([rawValue isKindOfClass:[NSArray class]]) { + NSArray *array = (NSArray *)rawValue; + if (array.count % 2 != 0) { + [NSException + raise:NSInvalidArgumentException + format:@"VariableTextAnchorOffset array should have an even number of elements."]; + } + + std::vector anchorOffsets; + anchorOffsets.reserve(array.count / 2); + for (NSUInteger i = 0; i < array.count; i += 2) { + mbgl::style::SymbolAnchorType anchor{0}; + getMBGLValue(array[i], anchor); + + std::array offsetArray; + getMBGLValue(array[i + 1], offsetArray); + + anchorOffsets.emplace_back(anchor, offsetArray); + } + + mbglValue = mbgl::VariableAnchorOffsetCollection(std::move(anchorOffsets)); + } + } + // Image void getMBGLValue(NSString *rawValue, mbgl::style::expression::Image &mbglValue) { mbglValue = mbgl::style::expression::Image(rawValue.UTF8String); @@ -266,9 +293,8 @@ class MLNStyleValueTransformer { } // Enumerations - template ::value>::type, - typename MLNEnum = ObjCEnum, class = typename std::enable_if::value>::type> void getMBGLValue(id rawValue, MBGLEnum &mbglValue) { if ([rawValue isKindOfClass:[NSString class]]) { @@ -321,6 +347,19 @@ class MLNStyleValueTransformer { return [MLNColor mgl_colorWithColor:mbglStopValue]; } + // VariableAnchorOffsetCollection + static NSArray *toMLNRawStyleValue( + const mbgl::VariableAnchorOffsetCollection mbglStopValue) { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size() * 2]; + for (const auto &anchorOffset : mbglStopValue) { + NSString *anchor = toMLNRawStyleValue(anchorOffset.anchorType); + NSValue *offset = [NSValue mgl_valueWithOffsetArray:anchorOffset.offset]; + [array addObject:[NSExpression expressionForConstantValue:anchor]]; + [array addObject:[NSExpression expressionForConstantValue:offset]]; + } + return array; + } + // Image static NSString *toMLNRawStyleValue(const mbgl::style::expression::Image &mbglImageValue) { return @(mbglImageValue.id().c_str()); diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index e37b689bd..b2ab3e8d1 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -40,16 +40,18 @@ void NodeExpression::Init(v8::Local target) { } type::Type parseType(v8::Local type) { - static std::unordered_map types = {{"string", type::String}, - {"number", type::Number}, - {"boolean", type::Boolean}, - {"object", type::Object}, - {"color", type::Color}, - {"padding", type::Padding}, - {"value", type::Value}, - {"formatted", type::Formatted}, - {"number-format", type::String}, - {"resolvedImage", type::Image}}; + static std::unordered_map types = { + {"string", type::String}, + {"number", type::Number}, + {"boolean", type::Boolean}, + {"object", type::Object}, + {"color", type::Color}, + {"padding", type::Padding}, + {"value", type::Value}, + {"formatted", type::Formatted}, + {"number-format", type::String}, + {"resolvedImage", type::Image}, + {"variableAnchorOffsetCollection", type::VariableAnchorOffsetCollection}}; v8::Local v8kind = Nan::Get(type, Nan::New("kind").ToLocalChecked()).ToLocalChecked(); std::string kind(*v8::String::Utf8Value(v8::Isolate::GetCurrent(), v8kind)); @@ -235,6 +237,18 @@ struct ToValue { } v8::Local operator()(const Image& image) { return toJS(image.toValue()); } + + v8::Local operator()(const mbgl::VariableAnchorOffsetCollection& variableAnchorOffsets) { + std::vector components; + components.reserve(variableAnchorOffsets.size() * 2); + for (const auto& variableAnchorOffset : variableAnchorOffsets) { + components.emplace_back( + std::string(mbgl::Enum::toString(variableAnchorOffset.anchorType))); + components.emplace_back(std::vector{static_cast(variableAnchorOffset.offset[0]), + static_cast(variableAnchorOffset.offset[1])}); + } + return operator()(components); + } }; v8::Local toJS(const Value& value) { diff --git a/scripts/generate-style-code.mjs b/scripts/generate-style-code.mjs old mode 100755 new mode 100644 index 196726056..9f1c6826f --- a/scripts/generate-style-code.mjs +++ b/scripts/generate-style-code.mjs @@ -33,7 +33,7 @@ function isLightProperty(property) { }; /** - * @param {any} property + * @param {any} property */ function isOverridable(property) { return ['text-color'].includes(property.name); @@ -58,6 +58,8 @@ function expressionType(property) { return `ColorType`; case 'padding': return `PaddingType`; + case 'variableAnchorOffsetCollection': + return `VariableAnchorOffsetCollectionType`; case 'formatted': return `FormattedType`; case 'array': @@ -72,6 +74,9 @@ function expressionType(property) { * @returns {string} */ function evaluatedType(property) { + if (/text-variable-anchor-offset/.test(property.name)) { + return 'VariableAnchorOffsetCollection'; + } if (/-translate-anchor$/.test(property.name)) { return 'TranslateAnchorType'; } @@ -232,6 +237,7 @@ function defaultValue(property) { case 'formatted': case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': return property.default ? `{${JSON.stringify(property.default)}}` : '{}'; case 'enum': if (property.default === undefined) { diff --git a/scripts/style-spec.mjs b/scripts/style-spec.mjs index fc1abe989..aec25a030 100644 --- a/scripts/style-spec.mjs +++ b/scripts/style-spec.mjs @@ -6,9 +6,6 @@ let modifiedReferenceSpec = referenceSpec; // https://github.com/maplibre/maplibre-native/issues/250 delete modifiedReferenceSpec['layout_symbol']['text-rotation-alignment']["values"]['viewport-glyph'] -// https://github.com/maplibre/maplibre-native/issues/2358 -delete modifiedReferenceSpec['layout_symbol']['text-variable-anchor-offset']; - // https://github.com/maplibre/maplibre-native/issues/251 delete modifiedReferenceSpec['layout_symbol']['icon-overlap']; delete modifiedReferenceSpec['layout_symbol']['text-overlap']; @@ -193,4 +190,4 @@ modifiedReferenceSpec["paint_location-indicator"] = { } }; -export default modifiedReferenceSpec; \ No newline at end of file +export default modifiedReferenceSpec; diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index aa6156ace..6ca7c6f2f 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -96,7 +96,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor_, const float overscaling, const float iconRotation, const float textRotation, - const std::array& variableTextOffset_, + const std::optional& textVariableAnchorOffset_, bool allowVerticalPlacement, const SymbolContent iconType) : sharedData(std::move(sharedData_)), @@ -123,7 +123,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor_, iconOffset(iconOffset_), key(std::move(key_)), textBoxScale(textBoxScale_), - variableTextOffset(variableTextOffset_), + textVariableAnchorOffset(textVariableAnchorOffset_), singleLine(shapedTextOrientations.singleLine) { // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap if (!sharedData->empty()) symbolContent |= SymbolContent::Text; @@ -206,6 +206,18 @@ bool SymbolInstance::hasSdfIcon() const { return symbolContent & SymbolContent::IconSDF; } +std::vector SymbolInstance::getTextAnchors() const { + std::vector result; + if (textVariableAnchorOffset) { + result.reserve(textVariableAnchorOffset->size()); + for (const auto& anchorOffset : *textVariableAnchorOffset) { + result.push_back(anchorOffset.anchorType); + } + } + + return result; +} + const std::optional& SymbolInstance::verticalIconQuads() const { assert(sharedData); return sharedData->verticalIconQuads; diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index dc64699ae..1520ebff9 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -120,7 +120,7 @@ public: float overscaling, float iconRotation, float textRotation, - const std::array& variableTextOffset, + const std::optional& textVariableAnchorOffset, bool allowVerticalPlacement, SymbolContent iconType = SymbolContent::None); @@ -136,6 +136,7 @@ public: const std::optional& iconQuads() const; const std::optional& verticalIconQuads() const; void releaseSharedData(); + std::vector getTextAnchors() const; #if MLN_SYMBOL_GUARDS /// Check all guard blocks @@ -183,7 +184,9 @@ public: std::optional getPlacedIconIndex() const { return placedIconIndex; } std::optional getPlacedVerticalIconIndex() const { return placedVerticalIconIndex; } float getTextBoxScale() const { return textBoxScale; } - std::array getVariableTextOffset() const { return variableTextOffset; } + std::optional getTextVariableAnchorOffset() const { + return textVariableAnchorOffset; + } bool getSingleLine() const { return singleLine; } uint32_t getCrossTileID() const { return crossTileID; } @@ -267,7 +270,7 @@ private: SYM_GUARD_VALUE(24) float textBoxScale; SYM_GUARD_VALUE(25) - std::array variableTextOffset; + std::optional textVariableAnchorOffset; SYM_GUARD_VALUE(26) bool singleLine; SYM_GUARD_VALUE(27) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index b46096e00..21a3d2d21 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -104,6 +104,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, textSize = leader.layout.get(); iconSize = leader.layout.get(); textRadialOffset = leader.layout.get(); + textVariableAnchorOffset = leader.layout.get(); const bool hasText = has(*layout) && has(*layout); const bool hasIcon = has(*layout); @@ -358,6 +359,69 @@ std::array SymbolLayout::evaluateVariableOffset(style::SymbolAnchorTyp return result; } +std::optional SymbolLayout::getTextVariableAnchorOffset(const SymbolFeature& feature) { + std::optional result; + + // If style specifies text-variable-anchor-offset, just return it + if (!textVariableAnchorOffset.isUndefined()) { + auto variableAnchorOffset = layout->evaluate(zoom, feature, canonicalID); + if (!variableAnchorOffset.empty()) { + std::vector anchorOffsets; + anchorOffsets.reserve(variableAnchorOffset.size()); + // Convert offsets from EM to PX, and apply baseline shift + for (const auto& anchorOffset : variableAnchorOffset) { + std::array variableTextOffset = { + {anchorOffset.offset[0] * util::ONE_EM, anchorOffset.offset[1] * util::ONE_EM}}; + switch (anchorOffset.anchorType) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::Top: + variableTextOffset[1] -= baselineOffset; + break; + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::BottomLeft: + case SymbolAnchorType::Bottom: + variableTextOffset[1] += baselineOffset; + break; + case SymbolAnchorType::Center: + case SymbolAnchorType::Left: + case SymbolAnchorType::Right: + break; + } + + anchorOffsets.push_back(AnchorOffsetPair{anchorOffset.anchorType, variableTextOffset}); + } + + result = VariableAnchorOffsetCollection(std::move(anchorOffsets)); + } + } else { + const std::vector variableTextAnchor = layout->evaluate( + zoom, feature, canonicalID); + if (!variableTextAnchor.empty()) { + std::array variableTextOffset; + if (!textRadialOffset.isUndefined()) { + variableTextOffset = {{layout->evaluate(zoom, feature, canonicalID) * util::ONE_EM, + INVALID_OFFSET_VALUE}}; + } else { + variableTextOffset = {{layout->evaluate(zoom, feature, canonicalID)[0] * util::ONE_EM, + layout->evaluate(zoom, feature, canonicalID)[1] * util::ONE_EM}}; + } + + std::vector anchorOffsetPairs; + anchorOffsetPairs.reserve(variableTextAnchor.size()); + for (auto anchor : variableTextAnchor) { + auto offset = variableTextOffset; + offset = SymbolLayout::evaluateVariableOffset(anchor, offset); + anchorOffsetPairs.push_back(AnchorOffsetPair{anchor, offset}); + } + + result = VariableAnchorOffsetCollection(std::move(anchorOffsetPairs)); + } + } + + return result; +} + void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, @@ -408,10 +472,9 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, return result; }; - const std::vector variableTextAnchor = layout->evaluate( - zoom, feature, canonicalID); + const auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); const SymbolAnchorType textAnchor = layout->evaluate(zoom, feature, canonicalID); - if (variableTextAnchor.empty()) { + if (!variableAnchorOffsets || variableAnchorOffsets->empty()) { // Layers with variable anchors use the `text-radial-offset` // property and the [x, y] offset vector is calculated at // placement time instead of layout time @@ -445,13 +508,13 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, // If this layer uses text-variable-anchor, generate shapings for // all justification possibilities. - if (!textAlongLine && !variableTextAnchor.empty()) { + if (!textAlongLine && variableAnchorOffsets && !variableAnchorOffsets->empty()) { std::vector justifications; if (textJustify != TextJustifyType::Auto) { justifications.push_back(textJustify); } else { - for (auto anchor : variableTextAnchor) { - justifications.push_back(getAnchorJustification(anchor)); + for (const auto& anchorOffset : *variableAnchorOffsets) { + justifications.push_back(getAnchorJustification(anchorOffset.anchorType)); } } for (TextJustifyType justification : justifications) { @@ -570,14 +633,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const float textMaxAngle = util::deg2radf(layout->get()); const float iconRotation = layout->evaluate(zoom, feature, canonicalID); const float textRotation = layout->evaluate(zoom, feature, canonicalID); - std::array variableTextOffset = {0, 0}; - if (!textRadialOffset.isUndefined()) { - variableTextOffset = { - {layout->evaluate(zoom, feature, canonicalID) * util::ONE_EM, INVALID_OFFSET_VALUE}}; - } else { - variableTextOffset = {{layout->evaluate(zoom, feature, canonicalID)[0] * util::ONE_EM, - layout->evaluate(zoom, feature, canonicalID)[1] * util::ONE_EM}}; - } + const auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); const SymbolPlacementType textPlacement = layout->get() != AlignmentType::Map ? SymbolPlacementType::Point @@ -635,7 +691,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, overscaling, iconRotation, textRotation, - variableTextOffset, + variableAnchorOffsets, allowVerticalPlacement, iconType); diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 12afca0c6..37848d6ef 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,10 @@ private: std::size_t sectionIndex, const CanonicalTileID& canonical); + // Helper to support both text-variable-anchor and text-variable-anchor-offset. + // Offset values converted from EMs to PXs. + std::optional getTextVariableAnchorOffset(const SymbolFeature&); + // Stores the layer so that we can hold on to GeometryTileFeature instances // in SymbolFeature, which may reference data from this object. const std::unique_ptr sourceLayer; @@ -134,6 +139,7 @@ private: style::TextSize::UnevaluatedType textSize; style::IconSize::UnevaluatedType iconSize; style::TextRadialOffset::UnevaluatedType textRadialOffset; + style::TextVariableAnchorOffset::UnevaluatedType textVariableAnchorOffset; Immutable layout; std::vector features; diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 98428132a..cad152417 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -356,6 +356,22 @@ bool SymbolBucket::hasFormatSectionOverrides() const { return *hasFormatSectionOverrides_; } +bool SymbolBucket::hasVariableTextAnchors() const { + auto hasTextVariableAnchorOffset = [&]() -> bool { + auto tvao = layout->get(); + if (tvao.isConstant()) { + const auto constValue = tvao.constant(); + return constValue && !constValue->empty(); + } else if (tvao.isExpression()) { + return true; + } + + return false; + }; + + return hasTextVariableAnchorOffset() || !layout->get().empty(); +} + std::pair SymbolBucket::registerAtCrossTileIndex(CrossTileSymbolLayerIndex& index, const RenderTile& renderTile) { bool firstTimeAdded = index.addBucket(renderTile.getOverscaledTileID(), renderTile.matrix, *this); diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 9960c72fc..760dee6a1 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -96,6 +96,7 @@ public: bool hasTextCollisionBoxData() const; bool hasTextCollisionCircleData() const; bool hasFormatSectionOverrides() const; + bool hasVariableTextAnchors() const; void sortFeatures(float angle); // Returns references to the `symbolInstances` items, sorted by viewport Y. diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp index 18997b3ba..8d3a365c7 100644 --- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp +++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp @@ -23,6 +23,8 @@ public: bool isConstant() const noexcept { return value.template is(); } + bool isExpression() const noexcept { return value.template is>(); } + std::optional constant() const { return value.match([&](const T& t) { return std::optional(t); }, [&](const auto&) { return std::nullopt; }); } diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 96dd4a5bb..4f1f0f976 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -136,6 +136,55 @@ std::optional Converter::operator()(const Convertible& value, return result; } +std::optional Converter::operator()( + const Convertible& value, Error& error) const { + if (!isArray(value)) { + error.message = "value must be an array"; + return std::nullopt; + } + + const auto arraySize = arrayLength(value); + if (arraySize < 1 || arraySize % 2 != 0) { + error.message = "array must contain an even number of elements"; + return std::nullopt; + } + + std::vector collection; + collection.reserve(arraySize / 2); + for (size_t index = 0; index < arraySize; index += 2) { + Convertible offsetValue = arrayMember(value, index + 1); + std::optional anchor = Converter{}(arrayMember(value, index), error); + + if (!anchor) { + error.message = "anchor must be a valid anchor value"; + return std::nullopt; + } + + if (!isArray(offsetValue)) { + error.message = "anchor offset must be an array"; + return std::nullopt; + } + + if (arrayLength(offsetValue) != 2) { + error.message = "anchor offset must have two elements"; + return std::nullopt; + } + + std::optional xOffset = toNumber(arrayMember(offsetValue, 0)); + std::optional yOffset = toNumber(arrayMember(offsetValue, 1)); + if (!xOffset || !yOffset) { + error.message = "anchor offset must have two numbers"; + return std::nullopt; + } + + auto anchorType = anchor.value(); + auto offset = std::array{xOffset.value(), yOffset.value()}; + collection.push_back(AnchorOffsetPair{anchorType, offset}); + } + + return VariableAnchorOffsetCollection(std::move(collection)); +} + template std::optional> Converter>::operator()(const Convertible& value, Error& error) const { diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index cef1bf469..e605be860 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -134,6 +134,8 @@ template std::optional> convertFunctionToExpression> convertFunctionToExpression(const Convertible&, Error&, bool); +template std::optional> +convertFunctionToExpression(const Convertible&, Error&, bool); template std::optional> convertFunctionToExpression(const Convertible&, Error&, bool); @@ -213,6 +215,7 @@ bool interpolatable(type::Type type) noexcept { return type.match([&](const type::NumberType&) { return true; }, [&](const type::ColorType&) { return true; }, [&](const type::PaddingType&) { return true; }, + [&](const type::VariableAnchorOffsetCollectionType&) { return true; }, [&](const type::Array& array) { return array.N && array.itemType == type::Number; }, [&](const auto&) { return false; }); } @@ -257,6 +260,13 @@ std::optional> convertLiteral(type::Type type, } return literal(*result); }, + [&](const type::VariableAnchorOffsetCollectionType&) -> std::optional> { + auto result = convert(value, error); + if (!result) { + return std::nullopt; + } + return literal(*result); + }, [&](const type::Array& array) -> std::optional> { if (!isArray(value)) { error.message = "value must be an array"; @@ -793,6 +803,9 @@ std::optional> convertFunctionToExpression(type::Typ [&](const type::PaddingType&) -> std::optional> { return toPadding(get(literal(*property)), defaultExpr()); }, + [&](const type::VariableAnchorOffsetCollectionType&) -> std::optional> { + return toVariableAnchorOffset(get(literal(*property)), defaultExpr()); + }, [&](const type::Array& array) -> std::optional> { return assertion(array, get(literal(*property)), defaultExpr()); }, diff --git a/src/mbgl/style/conversion/property_value.cpp b/src/mbgl/style/conversion/property_value.cpp index 65d9b75c1..811a5cf1f 100644 --- a/src/mbgl/style/conversion/property_value.cpp +++ b/src/mbgl/style/conversion/property_value.cpp @@ -80,6 +80,11 @@ template std::optional> Converter>::op bool) const; template std::optional> Converter>::operator()( conversion::Convertible const&, conversion::Error&, bool, bool) const; +template std::optional> +Converter>::operator()(conversion::Convertible const&, + conversion::Error&, + bool, + bool) const; template std::optional> Converter>::operator()( conversion::Convertible const&, conversion::Error&, bool, bool) const; template std::optional>> diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index 0e1983360..53a269297 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,21 @@ void stringify(Writer& writer, const Color& v) { writer.String(v.stringify()); } +template +void stringify(Writer& writer, const VariableAnchorOffsetCollection& v) { + writer.StartArray(); + + for (const auto& pair : v) { + writer.String(Enum::toString(pair.anchorType)); + writer.StartArray(); + writer.Double(pair.offset[0]); + writer.Double(pair.offset[1]); + writer.EndArray(); + } + + writer.EndArray(); +} + template void stringify(Writer& writer, const std::array& v) { writer.StartArray(); diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index 10e5edfe6..208c48288 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -98,6 +98,47 @@ EvaluationResult toPadding(const Value& paddingValue) { }); } +EvaluationResult toVariableAnchorOffset(const Value& value) { + return value.match( + [&](const VariableAnchorOffsetCollection& anchorOffset) -> EvaluationResult { return anchorOffset; }, + [&](const std::vector& components) -> EvaluationResult { + if (components.size() % 2 != 0) { + return EvaluationError{"Invalid variableAnchorOffset value " + stringify(components) + + ": expected an array containing an even number of values."}; + } + + std::vector anchorOffsets; + for (std::size_t i = 0; i < components.size(); i += 2) { + const auto& anchorTypeValue = components[i]; + const auto& offsetArray = components[i + 1]; + + if (!anchorTypeValue.is() || !offsetArray.is>() || + offsetArray.get>().size() != 2) { + return EvaluationError{"Invalid variableAnchorOffset value " + stringify(components) + + ": expected a string value as the first and an array with two elements as " + "the second element of each pair."}; + } + + const auto anchor = Enum::toEnum(anchorTypeValue.get()); + if (!anchor) { + return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + + ": unknown anchor type '" + anchorTypeValue.get() + "'"}; + } + + const auto& offset = offsetArray.get>(); + const auto x = static_cast(offset[0].template get()); + const auto y = static_cast(offset[1].template get()); + + anchorOffsets.emplace_back(*anchor, std::array{{x, y}}); + } + + return VariableAnchorOffsetCollection(std::move(anchorOffsets)); + }, + [&](const auto&) -> EvaluationResult { + return EvaluationError{"Could not parse variableAnchorOffset from '" + stringify(value) + "'"}; + }); +} + EvaluationResult toFormatted(const Value& formattedValue) { return Formatted(toString(formattedValue).c_str()); } @@ -117,6 +158,8 @@ CoerceFunction getCoerceFunction(const type::Type& t) { return toColor; } else if (t.is()) { return toPadding; + } else if (t.is()) { + return toVariableAnchorOffset; } else if (t.is()) { return toNumber; } else if (t.is()) { @@ -161,25 +204,29 @@ mbgl::Value Coercion::serialize() const { }; std::string Coercion::getOperator() const { - auto s = getType().match([](const type::BooleanType&) -> std::string_view { return "to-boolean"; }, - [](const type::ColorType&) -> std::string_view { return "to-color"; }, - [](const type::PaddingType&) -> std::string_view { return "to-padding"; }, - [](const type::NumberType&) -> std::string_view { return "to-number"; }, - [](const type::StringType&) -> std::string_view { return "to-string"; }, - [](const auto&) noexcept -> std::string_view { - assert(false); - return ""; - }); + auto s = getType().match( + [](const type::BooleanType&) -> std::string_view { return "to-boolean"; }, + [](const type::ColorType&) -> std::string_view { return "to-color"; }, + [](const type::PaddingType&) -> std::string_view { return "to-padding"; }, + [](const type::NumberType&) -> std::string_view { return "to-number"; }, + [](const type::StringType&) -> std::string_view { return "to-string"; }, + [](const type::VariableAnchorOffsetCollectionType&) -> std::string_view { return "to-variableanchoroffset"; }, + [](const auto&) noexcept -> std::string_view { + assert(false); + return ""; + }); return std::string(s); } using namespace mbgl::style::conversion; ParseResult Coercion::parse(const Convertible& value, ParsingContext& ctx) { - static std::unordered_map types{{"to-boolean", type::Boolean}, - {"to-color", type::Color}, - {"to-padding", type::Padding}, - {"to-number", type::Number}, - {"to-string", type::String}}; + static std::unordered_map types{ + {"to-boolean", type::Boolean}, + {"to-color", type::Color}, + {"to-padding", type::Padding}, + {"to-number", type::Number}, + {"to-string", type::String}, + {"to-variableanchoroffset", type::VariableAnchorOffsetCollection}}; std::size_t length = arrayLength(value); diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp index dc518d38f..7e76718af 100644 --- a/src/mbgl/style/expression/dsl.cpp +++ b/src/mbgl/style/expression/dsl.cpp @@ -121,6 +121,10 @@ std::unique_ptr toPadding(std::unique_ptr value, std::un return coercion(type::Padding, std::move(value), std::move(def)); } +std::unique_ptr toVariableAnchorOffset(std::unique_ptr value, std::unique_ptr def) { + return coercion(type::VariableAnchorOffsetCollection, std::move(value), std::move(def)); +} + std::unique_ptr toString(std::unique_ptr value, std::unique_ptr def) { return coercion(type::String, std::move(value), std::move(def)); } diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 889d6ea37..c404aa283 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -236,6 +236,10 @@ ParseResult createInterpolate(type::Type type, return ParseResult( std::make_unique>(type, interpolator, std::move(input), std::move(stops))); }, + [&](const type::VariableAnchorOffsetCollectionType&) -> ParseResult { + return ParseResult(std::make_unique>( + type, interpolator, std::move(input), std::move(stops))); + }, [&](const type::Array& arrayType) -> ParseResult { if (arrayType.itemType != type::Number || !arrayType.N) { ctx.error("Type " + toString(type) + " is not interpolatable."); diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 12e11c423..eff15749e 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -213,6 +213,10 @@ ParseResult ParsingContext::parse(const Convertible& value, (actual == type::Value || actual == type::Number || actual.is())) { parsed = {annotate( std::move(*parsed), std::move(*expected), typeAnnotationOption.value_or(TypeAnnotationOption::coerce))}; + } else if (*expected == type::VariableAnchorOffsetCollection && + (actual == type::Value || actual.is())) { + parsed = {annotate( + std::move(*parsed), std::move(*expected), typeAnnotationOption.value_or(TypeAnnotationOption::coerce))}; } else { checkType((*parsed)->getType()); if (!errors->empty()) { diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index 0701d0dac..afd691f2a 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -8,37 +8,40 @@ namespace style { namespace expression { type::Type typeOf(const Value& value) { - return value.match([&](bool) -> type::Type { return type::Boolean; }, - [&](double) -> type::Type { return type::Number; }, - [&](const std::string&) -> type::Type { return type::String; }, - [&](const Color&) -> type::Type { return type::Color; }, - [&](const Padding&) -> type::Type { return type::Padding; }, - [&](const Collator&) -> type::Type { return type::Collator; }, - [&](const Formatted&) -> type::Type { return type::Formatted; }, - [&](const Image&) -> type::Type { return type::Image; }, - [&](const NullValue&) -> type::Type { return type::Null; }, - [&](const std::unordered_map&) -> type::Type { return type::Object; }, - [&](const std::vector& arr) -> type::Type { - std::optional itemType; - for (const auto& item : arr) { - const type::Type t = typeOf(item); - if (!itemType) { - itemType = {t}; - } else if (*itemType == t) { - continue; - } else { - itemType = {type::Value}; - break; - } - } + return value.match( + [&](bool) -> type::Type { return type::Boolean; }, + [&](double) -> type::Type { return type::Number; }, + [&](const std::string&) -> type::Type { return type::String; }, + [&](const Color&) -> type::Type { return type::Color; }, + [&](const Padding&) -> type::Type { return type::Padding; }, + [&](const VariableAnchorOffsetCollection&) -> type::Type { return type::VariableAnchorOffsetCollection; }, + [&](const Collator&) -> type::Type { return type::Collator; }, + [&](const Formatted&) -> type::Type { return type::Formatted; }, + [&](const Image&) -> type::Type { return type::Image; }, + [&](const NullValue&) -> type::Type { return type::Null; }, + [&](const std::unordered_map&) -> type::Type { return type::Object; }, + [&](const std::vector& arr) -> type::Type { + std::optional itemType; + for (const auto& item : arr) { + const type::Type t = typeOf(item); + if (!itemType) { + itemType = {t}; + } else if (*itemType == t) { + continue; + } else { + itemType = {type::Value}; + break; + } + } - return type::Array(itemType.value_or(type::Value), arr.size()); - }); + return type::Array(itemType.value_or(type::Value), arr.size()); + }); } std::string toString(const Value& value) { return value.match([](const NullValue&) { return std::string(); }, - [](const Color& c) { return c.stringify(); }, // avoid quoting + [](const Color& c) { return c.stringify(); }, // avoid quoting + [](const VariableAnchorOffsetCollection& v) { return v.toString(); }, // avoid quoting [](const Formatted& f) { return f.toString(); }, [](const Image& i) { return i.id(); }, [](const std::string& s) { return s; }, // avoid quoting @@ -55,6 +58,7 @@ void writeJSON(rapidjson::Writer& writer, const Value& [&](const std::string& s) { writer.String(s); }, [&](const Color& c) { writer.String(c.stringify()); }, [&](const Padding& p) { mbgl::style::conversion::stringify(writer, p); }, + [&](const VariableAnchorOffsetCollection& v) { mbgl::style::conversion::stringify(writer, v); }, [&](const Collator&) { // Collators are excluded from constant folding and there's no Literal parser // for them so there shouldn't be any way to serialize this value. @@ -126,6 +130,7 @@ mbgl::Value ValueConverter::fromExpressionValue(const Value& value) return value.match( [&](const Color& color) -> mbgl::Value { return color.serialize(); }, [&](const Padding& padding) -> mbgl::Value { return padding.serialize(); }, + [&](const VariableAnchorOffsetCollection& anchorOffset) -> mbgl::Value { return anchorOffset.serialize(); }, [&](const Collator&) -> mbgl::Value { // fromExpressionValue can't be used for Collator values, // because they have no meaningful representation as an mbgl::Value @@ -316,6 +321,10 @@ type::Type valueTypeToExpressionType() { return type::Padding; } template <> +type::Type valueTypeToExpressionType() { + return type::VariableAnchorOffsetCollection; +} +template <> type::Type valueTypeToExpressionType() { return type::Collator; } diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 949f571a1..6aec283b0 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -648,6 +648,7 @@ void SymbolLayer::setTextTransform(const PropertyValue& value baseImpl = std::move(impl_); observer->onLayerChanged(*this); } + PropertyValue> SymbolLayer::getDefaultTextVariableAnchor() { return TextVariableAnchor::defaultValue(); } @@ -663,6 +664,23 @@ void SymbolLayer::setTextVariableAnchor(const PropertyValueonLayerChanged(*this); } + +PropertyValue SymbolLayer::getDefaultTextVariableAnchorOffset() { + return TextVariableAnchorOffset::defaultValue(); +} + +const PropertyValue& SymbolLayer::getTextVariableAnchorOffset() const { + return impl().layout.get(); +} + +void SymbolLayer::setTextVariableAnchorOffset(const PropertyValue& value) { + if (value == getTextVariableAnchorOffset()) return; + auto impl_ = mutableImpl(); + impl_->layout.get() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + PropertyValue> SymbolLayer::getDefaultTextWritingMode() { return TextWritingMode::defaultValue(); } @@ -1134,6 +1152,7 @@ enum class Property : uint8_t { TextSize, TextTransform, TextVariableAnchor, + TextVariableAnchorOffset, TextWritingMode, }; @@ -1211,6 +1230,7 @@ constexpr const auto layerProperties = mapbox::eternal::hash_map SymbolLayer::setPropertyInternal(const std::string& name, c setTextVariableAnchor(*typedValue); return std::nullopt; } + if (property == Property::TextVariableAnchorOffset) { + Error error; + const auto& typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextVariableAnchorOffset(*typedValue); + return std::nullopt; + } if (property == Property::TextWritingMode) { Error error; const auto& typedValue = convert>>(value, error, false, false); diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index cdc1fdf9b..b4bd6d254 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.hpp +++ b/src/mbgl/style/layers/symbol_layer_properties.hpp @@ -216,6 +216,11 @@ struct TextVariableAnchor : LayoutProperty> static std::vector defaultValue() { return {}; } }; +struct TextVariableAnchorOffset : DataDrivenLayoutProperty { + static constexpr const char *name() { return "text-variable-anchor-offset"; } + static VariableAnchorOffsetCollection defaultValue() { return {}; } +}; + struct TextWritingMode : LayoutProperty> { static constexpr const char *name() { return "text-writing-mode"; } static std::vector defaultValue() { return {}; } @@ -321,6 +326,7 @@ class SymbolLayoutProperties : public Properties< TextSize, TextTransform, TextVariableAnchor, + TextVariableAnchorOffset, TextWritingMode > {}; diff --git a/src/mbgl/style/variable_anchor_offset_collection.cpp b/src/mbgl/style/variable_anchor_offset_collection.cpp new file mode 100644 index 000000000..f4d275590 --- /dev/null +++ b/src/mbgl/style/variable_anchor_offset_collection.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include +#include + +namespace mbgl { + +using namespace std; +using namespace style; +using namespace style::expression; + +std::array VariableAnchorOffsetCollection::getOffsetByAnchor(const SymbolAnchorType& anchorType) const { + for (const auto& entry : anchorOffsets) { + if (anchorType == entry.anchorType) { + return entry.offset; + } + } + + return {0, 0}; +} + +std::string VariableAnchorOffsetCollection::toString() const { + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + writer.StartArray(); + for (const auto& entry : anchorOffsets) { + writer.String(Enum::toString(entry.anchorType)); + writer.StartArray(); + writer.Double(entry.offset[0]); + writer.Double(entry.offset[1]); + writer.EndArray(); + } + + writer.EndArray(); + string stringValue = buffer.GetString(); + return stringValue; +} + +mbgl::Value VariableAnchorOffsetCollection::serialize() const { + std::vector serialized; + for (const auto& entry : anchorOffsets) { + serialized.emplace_back(Enum::toString(entry.anchorType)); + std::vector offset{entry.offset[0], entry.offset[1]}; + serialized.emplace_back(offset); + } + + return serialized; +} + +} // namespace mbgl diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index d9f33d9bc..88402e142 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -97,10 +97,6 @@ public: const TransformState& getTransformState() const { return state; } - const std::vector& getVariableTextAnchors() const { - return getLayout().get(); - } - float pixelsToTileUnits; float scale; float pixelRatio; @@ -229,8 +225,7 @@ Point calculateVariableLayoutOffset(style::SymbolAnchorType anchor, AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); float shiftX = -(alignment.horizontalAlign - 0.5f) * width; float shiftY = -(alignment.verticalAlign - 0.5f) * height; - auto variableOffset = SymbolLayout::evaluateVariableOffset(anchor, offset); - Point shift{shiftX + variableOffset[0] * textBoxScale, shiftY + variableOffset[1] * textBoxScale}; + Point shift{shiftX + offset[0] * textBoxScale, shiftY + offset[1] * textBoxScale}; if (rotateWithMap) { shift = util::rotate(shift, pitchWithMap ? bearing : -bearing); } @@ -284,7 +279,7 @@ JointPlacement Placement::placeSymbol(const SymbolInstance& symbolInstance, cons const SymbolBucket& bucket = ctx.getBucket(); const mat4& posMatrix = ctx.getRenderTile().matrix; const auto& collisionGroup = ctx.collisionGroup; - auto variableTextAnchors = ctx.getVariableTextAnchors(); + auto variableTextAnchors = symbolInstance.getTextAnchors(); textBoxes.clear(); iconBoxes.clear(); @@ -411,11 +406,12 @@ JointPlacement Placement::placeSymbol(const SymbolInstance& symbolInstance, cons // so this code would not be reached // NOLINTNEXTLINE(clang-analyzer-core.DivideZero) auto anchor = variableTextAnchors[i % anchorsSize]; + auto variableTextOffset = symbolInstance.getTextVariableAnchorOffset()->getOffsetByAnchor(anchor); const bool allowOverlap = (i >= anchorsSize); shift = calculateVariableLayoutOffset(anchor, width, height, - symbolInstance.getVariableTextOffset(), + variableTextOffset, textBoxScale, ctx.rotateTextWithMap, ctx.pitchTextWithMap, @@ -478,13 +474,9 @@ JointPlacement Placement::placeSymbol(const SymbolInstance& symbolInstance, cons } } - variableOffsets.insert(std::make_pair(symbolInstance.getCrossTileID(), - VariableOffset{symbolInstance.getVariableTextOffset(), - width, - height, - anchor, - textBoxScale, - prevAnchor})); + variableOffsets.insert(std::make_pair( + symbolInstance.getCrossTileID(), + VariableOffset{variableTextOffset, width, height, anchor, textBoxScale, prevAnchor})); if (bucket.allowVerticalPlacement) { placedOrientations.emplace(symbolInstance.getCrossTileID(), orientation); @@ -772,9 +764,8 @@ Point calculateVariableRenderShift(style::SymbolAnchorType anchor, const AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); const float shiftX = -(alignment.horizontalAlign - 0.5f) * width; const float shiftY = -(alignment.verticalAlign - 0.5f) * height; - auto variableOffset = SymbolLayout::evaluateVariableOffset(anchor, textOffset); - return {(shiftX / textBoxScale + variableOffset[0]) * renderTextSize, - (shiftY / textBoxScale + variableOffset[1]) * renderTextSize}; + return {(shiftX / textBoxScale + textOffset[0]) * renderTextSize, + (shiftY / textBoxScale + textOffset[1]) * renderTextSize}; } } // namespace @@ -784,7 +775,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, using namespace style; const auto& layout = *bucket.layout; const bool alongLine = layout.get() != SymbolPlacementType::Point; - const bool hasVariableAnchors = !layout.get().empty() && bucket.hasTextData(); + const bool hasVariableAnchors = bucket.hasVariableTextAnchors() && bucket.hasTextData(); const bool updateTextFitIcon = layout.get() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && (bucket.hasIconData() || bucket.hasSdfIconData()); @@ -979,7 +970,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const bool textAllowOverlap = bucket.layout->get(); const bool iconAllowOverlap = bucket.layout->get(); - const bool variablePlacement = !bucket.layout->get().empty(); + const bool variablePlacement = bucket.hasVariableTextAnchors(); const bool rotateWithMap = bucket.layout->get() == style::AlignmentType::Map; const bool pitchWithMap = bucket.layout->get() == style::AlignmentType::Map; const bool hasIconTextFit = bucket.layout->get() != style::IconTextFitType::None; @@ -1492,14 +1483,11 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se collisionGroups.get(params.sourceId), getAvoidEdges(bucket, renderTile.matrix)}; - const auto& variableTextAnchors = ctx.getVariableTextAnchors(); // In this case we first try to place symbols, which intersects the tile // borders, so that those symbols will remain even if each tile is handled // independently. SymbolInstanceReferences symbolInstances = getBucketSymbols( bucket, params.sortKeyRange, collisionIndex.getTransformState().getBearing()); - std::optional variableAnchor; - if (!variableTextAnchors.empty()) variableAnchor = variableTextAnchors.front(); // Keeps the data necessary to find a feature location according to a tile. struct NeighborTileData { @@ -1543,13 +1531,18 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se }; auto symbolIntersectsTileEdges = [&collisionBoxIntersectsTileEdges, - variableAnchor, pitchTextWithMap = ctx.pitchTextWithMap, rotateTextWithMap = ctx.rotateTextWithMap, variableIconPlacement = ctx.hasIconTextFit && !ctx.iconAllowOverlap, bearing = static_cast(ctx.getTransformState().getBearing())]( const SymbolInstance& symbol) noexcept -> IntersectStatus { IntersectStatus result; + std::optional variableAnchor; + auto textVariableAnchorOffset = symbol.getTextVariableAnchorOffset(); + if (textVariableAnchorOffset && !textVariableAnchorOffset->empty()) { + variableAnchor = textVariableAnchorOffset->begin()->anchorType; + } + if (!symbol.getTextCollisionFeature().boxes.empty()) { const auto& textCollisionBox = symbol.getTextCollisionFeature().boxes.front(); @@ -1557,10 +1550,13 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se if (variableAnchor) { float width = textCollisionBox.x2 - textCollisionBox.x1; float height = textCollisionBox.y2 - textCollisionBox.y1; + + auto variableTextOffset = textVariableAnchorOffset->getOffsetByAnchor(*variableAnchor); + offset = calculateVariableLayoutOffset(*variableAnchor, width, height, - symbol.getVariableTextOffset(), + variableTextOffset, symbol.getTextBoxScale(), rotateTextWithMap, pitchTextWithMap, @@ -1575,10 +1571,13 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se if (variableAnchor && variableIconPlacement) { float width = iconCollisionBox.x2 - iconCollisionBox.x1; float height = iconCollisionBox.y2 - iconCollisionBox.y1; + + auto variableTextOffset = textVariableAnchorOffset->getOffsetByAnchor(*variableAnchor); + offset = calculateVariableLayoutOffset(*variableAnchor, width, height, - symbol.getVariableTextOffset(), + variableTextOffset, symbol.getTextBoxScale(), rotateTextWithMap, pitchTextWithMap, @@ -1668,7 +1667,7 @@ void TilePlacement::newSymbolPlaced(const SymbolInstance& symbol, bool TilePlacement::shouldRetryPlacement(const JointPlacement& placement, const PlacementContext& ctx) { // We re-try the placement to try out remaining variable anchors. - return populateIntersections && !placement.placed() && !ctx.getVariableTextAnchors().empty(); + return populateIntersections && !placement.placed() && ctx.getBucket().hasVariableTextAnchors(); } // static diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5c70fc951..9d15d5ce4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -63,6 +63,7 @@ add_library( ${PROJECT_SOURCE_DIR}/test/style/style_image.test.cpp ${PROJECT_SOURCE_DIR}/test/style/style_layer.test.cpp ${PROJECT_SOURCE_DIR}/test/style/style_parser.test.cpp + ${PROJECT_SOURCE_DIR}/test/style/variable_anchor_offset_collection.test.cpp $<$>,$>>:${PROJECT_SOURCE_DIR}/test/text/bidi.test.cpp> ${PROJECT_SOURCE_DIR}/test/text/calculate_tile_distances.test.cpp ${PROJECT_SOURCE_DIR}/test/text/cross_tile_symbol_index.test.cpp diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp index a16ab45a7..9705a62f5 100644 --- a/test/style/conversion/stringify.test.cpp +++ b/test/style/conversion/stringify.test.cpp @@ -58,6 +58,12 @@ TEST(Stringify, Color) { ASSERT_EQ(stringify(Color::blue()), "\"rgba(0,0,255,1)\""); } +TEST(Stringify, VariableAnchorOffsetCollection) { + std::array offset = {1, 1}; + std::vector test{{AnchorOffsetPair{SymbolAnchorType::Left, offset}}}; + ASSERT_EQ(stringify(VariableAnchorOffsetCollection(std::move(test))), "[\"left\",[1.0,1.0]]"); +} + TEST(Stringify, Array) { ASSERT_EQ(stringify(std::array{{1, 2}}), "[1.0,2.0]"); } diff --git a/test/style/expression/dependency.test.cpp b/test/style/expression/dependency.test.cpp index 2e0fce7f6..e71b97832 100644 --- a/test/style/expression/dependency.test.cpp +++ b/test/style/expression/dependency.test.cpp @@ -39,6 +39,7 @@ TEST(ExpressionDependencies, Convert) { EXPECT_EQ(Dependency::Feature, toString(number(string(get("color"))))->dependencies); EXPECT_EQ(Dependency::Feature, boolean(string(get("color")))->dependencies); EXPECT_EQ(Dependency::Feature, toFormatted(toColor(string(get("color"))))->dependencies); + EXPECT_EQ(Dependency::Feature, toVariableAnchorOffset(string(get("color")))->dependencies); /// See `coercion.cpp`, `extraDependency` EXPECT_EQ(Dependency::Feature, toImage(string(get("color")))->dependencies); diff --git a/test/style/variable_anchor_offset_collection.test.cpp b/test/style/variable_anchor_offset_collection.test.cpp new file mode 100644 index 000000000..9b7774869 --- /dev/null +++ b/test/style/variable_anchor_offset_collection.test.cpp @@ -0,0 +1,205 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace mbgl; +using namespace mbgl::style; +using namespace mbgl::style::conversion; + +TEST(VariableAnchorOffsetCollection, Calculations) { + auto parseJson = [&](const std::string& src) { + Error error; + return convertJSON(src, error); + }; + + mbgl::util::Interpolator interpolator; + + // valid value + { + auto a = parseJson(R"(["top", [0, 0], "bottom", [2, 2]])"); + auto b = parseJson(R"(["top", [1, 1], "bottom", [4, 4]])"); + ASSERT_TRUE(a.has_value()); + ASSERT_TRUE(b.has_value()); + auto c = interpolator(*a, *b, 0.5); + EXPECT_EQ( + VariableAnchorOffsetCollection({{SymbolAnchorType::Top, {0.5, 0.5}}, {SymbolAnchorType::Bottom, {3, 3}}}), + c); + } + + // should thorw with mismatched endpoints + { + auto a = parseJson(R"(["top", [0, 0]])"); + auto b = parseJson(R"(["bottom", [1, 1]])"); + ASSERT_TRUE(a.has_value()); + ASSERT_TRUE(b.has_value()); + EXPECT_THROW(interpolator(*a, *b, 0.5), std::runtime_error); + + a = parseJson(R"(["top", [0, 0]])"); + b = parseJson(R"(["top", [1, 1], "bottom", [2, 2]])"); + ASSERT_TRUE(a.has_value()); + ASSERT_TRUE(b.has_value()); + EXPECT_THROW(interpolator(*a, *b, 0.5), std::runtime_error); + } +} + +TEST(VariableAnchorOffsetCollection, StyleConversion) { + Error error; + + auto parseVariableAnchorOffsetCollection = [&](const std::string& src) { + return convertJSON(src, error); + }; + + // valid value + { + auto jsonValue = R"(["left",[1.0,2.0],"top",[0.0,0.0]])"; + auto variableAnchorOffset = parseVariableAnchorOffsetCollection(jsonValue); + ASSERT_TRUE(variableAnchorOffset.has_value()); + ASSERT_EQ(variableAnchorOffset->size(), 2); + ASSERT_EQ(variableAnchorOffset->operator[](0).anchorType, style::SymbolAnchorType::Left); + ASSERT_EQ(variableAnchorOffset->operator[](0).offset[0], 1); + ASSERT_EQ(variableAnchorOffset->operator[](0).offset[1], 2); + + ASSERT_EQ(variableAnchorOffset->toString(), jsonValue); + } + + // Invalid values + { + // null + auto expectedError = "value must be an array"; + auto variableAnchorOffset = parseVariableAnchorOffsetCollection("{}"); + ASSERT_FALSE(variableAnchorOffset.has_value()); + ASSERT_EQ(error.message, expectedError); + + // empty array + expectedError = "array must contain an even number of elements"; + variableAnchorOffset = parseVariableAnchorOffsetCollection("[]"); + ASSERT_FALSE(variableAnchorOffset.has_value()); + ASSERT_EQ(error.message, expectedError); + + // invalid anchor type + expectedError = "anchor must be a valid anchor value"; + variableAnchorOffset = parseVariableAnchorOffsetCollection(R"(["test", [1, 2]])"); + ASSERT_FALSE(variableAnchorOffset.has_value()); + ASSERT_EQ(error.message, expectedError); + + // invalid offset array + expectedError = "anchor offset must be an array"; + variableAnchorOffset = parseVariableAnchorOffsetCollection(R"(["top", "left"])"); + ASSERT_FALSE(variableAnchorOffset.has_value()); + ASSERT_EQ(error.message, expectedError); + + expectedError = "anchor offset must have two elements"; + variableAnchorOffset = parseVariableAnchorOffsetCollection(R"(["top", [1, 2, 3]])"); + ASSERT_FALSE(variableAnchorOffset.has_value()); + ASSERT_EQ(error.message, expectedError); + + expectedError = "anchor offset must have two numbers"; + variableAnchorOffset = parseVariableAnchorOffsetCollection(R"(["top", ["test", "test"]])"); + ASSERT_FALSE(variableAnchorOffset.has_value()); + ASSERT_EQ(error.message, expectedError); + } + + auto parseLayer = [&](const std::string& src) -> std::unique_ptr { + auto layer = convertJSON>(src, error); + if (layer) return std::move(*layer); + return nullptr; + }; + + // parse layer + { + auto layer = parseLayer(R"JSON({ + "type": "symbol", + "id": "symbol", + "source": "composite", + "source-layer": "landmarks", + "minzoom": 12, + "maxzoom": 18, + "layout": { + "text-field": "Test Test Test", + "icon-image": ["image", ["get", "landmark_image"]], + "text-size": 24, + "text-justify": "auto", + "text-variable-anchor-offset": ["center", [0, 0],"top", [0, 0]] + } + })JSON"); + + EXPECT_NE(nullptr, layer); + auto value = layer->serialize(); + EXPECT_NE(nullptr, value.getObject()); + EXPECT_EQ(7u, value.getObject()->size()); + } +} + +TEST(VariableAnchorOffsetCollection, Expression) { + Error error; + auto jsonToExpression = [&](const std::string& json) { + auto propertyValue = conversion::convertJSON>( + json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); + return propertyValue->asExpression(); + }; + + // interval function + { + auto expr = jsonToExpression( + R"({"type": "interval", "stops": [[0, ["left", [0, 0]]], [5, ["left", [10, 20]]]]})"); + + EXPECT_EQ(VariableAnchorOffsetCollection({{SymbolAnchorType::Left, {0, 0}}}), expr.evaluate(0)); + EXPECT_EQ(VariableAnchorOffsetCollection({{SymbolAnchorType::Left, {0, 0}}}), expr.evaluate(4)); + EXPECT_EQ(VariableAnchorOffsetCollection({{SymbolAnchorType::Left, {10, 20}}}), expr.evaluate(5)); + } + + // interpolate expression + { + auto expr = jsonToExpression( + R"(["interpolate", ["linear"], ["zoom"], 0, ["literal", ["left", [0, 0]]], 1, ["literal",["left", + [10, 20]]]])"); + auto result = expr.evaluate(0.5f); + EXPECT_EQ(VariableAnchorOffsetCollection(std::vector{ + {AnchorOffsetPair(SymbolAnchorType::Left, std::array{5.0f, 10.0f})}}), + result); + } + + auto jsonToPropertyValue = [&](const std::string& json) { + return conversion::convertJSON>( + json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); + }; + + // invalid expressions + { + // Invalid component size + auto expectedError = + "[4]: Invalid variableAnchorOffset value [\"left\"]: expected an array containing an even number of " + "values."; + auto parsedResult = jsonToPropertyValue( + R"(["interpolate", ["linear"], ["zoom"], 0, ["literal", ["left"]], 1, ["literal",["left", + [10, 20]]]])"); + ASSERT_FALSE(parsedResult.has_value()); + ASSERT_EQ(error.message, expectedError); + + // Invalid offset array size + expectedError = + "[4]: Invalid variableAnchorOffset value [\"left\",[10]]: expected a string value as the first and an " + "array with two elements as the second element of each pair."; + parsedResult = jsonToPropertyValue( + R"(["interpolate", ["linear"], ["zoom"], 0, ["literal", ["left", [10]]], 1, ["literal",["left", + [10, 20]]]])"); + ASSERT_FALSE(parsedResult.has_value()); + ASSERT_EQ(error.message, expectedError); + + // Invalid anchor type + expectedError = + "[4]: Invalid variableAnchorOffsetCollection value [\"test\",[0,0]]: unknown anchor type 'test'"; + parsedResult = jsonToPropertyValue( + R"(["interpolate", ["linear"], ["zoom"], 0, ["literal", ["test", [0, 0]]], 1, ["literal",["left", + [10, 20]]]])"); + ASSERT_FALSE(parsedResult.has_value()); + ASSERT_EQ(error.message, expectedError); + } +} diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index de41ae179..c424f8dd6 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -15,6 +16,8 @@ SymbolInstance makeSymbolInstance(float x, float y, std::u16string key) { std::array textOffset{{0.0f, 0.0f}}; std::array iconOffset{{0.0f, 0.0f}}; std::array variableTextOffset{{0.0f, 0.0f}}; + std::vector anchorOffsets = {{style::SymbolAnchorType::Left, variableTextOffset}}; + VariableAnchorOffsetCollection variableAnchorOffsetCollection(std::move(anchorOffsets)); style::SymbolPlacementType placementType = style::SymbolPlacementType::Point; auto sharedData = std::make_shared(std::move(line), @@ -48,7 +51,7 @@ SymbolInstance makeSymbolInstance(float x, float y, std::u16string key) { 0.0f, 0.0f, 0.0f, - variableTextOffset, + variableAnchorOffsetCollection, false); }