From 75362aabd8bf8103052455915f08a0b9b5240447 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Fri, 23 Aug 2024 19:33:52 +0800 Subject: [PATCH 01/35] add variableAnchorOffsetCollection data type for text-variable-anchor-offset property --- bazel/core.bzl | 2 + include/mbgl/style/conversion/constant.hpp | 6 + include/mbgl/style/conversion_impl.hpp | 6 + include/mbgl/style/expression/dsl.hpp | 1 + include/mbgl/style/expression/type.hpp | 8 ++ include/mbgl/style/expression/value.hpp | 2 + include/mbgl/style/layers/symbol_layer.hpp | 5 + include/mbgl/util/interpolate.hpp | 12 ++ .../variable_anchor_offset_collection.hpp | 46 +++++++ .../darwin/scripts/generate-style-code.js | 11 ++ platform/darwin/src/MLNStyleValue_Private.h | 12 ++ scripts/generate-style-code.js | 6 + scripts/style-spec-reference/v8.json | 32 +++++ src/mbgl/layout/symbol_layout.cpp | 105 +-------------- src/mbgl/layout/symbol_layout.hpp | 11 -- src/mbgl/style/conversion/constant.cpp | 16 +++ src/mbgl/style/conversion/function.cpp | 11 ++ src/mbgl/style/conversion/property_value.cpp | 4 + src/mbgl/style/conversion/stringify.hpp | 6 + src/mbgl/style/expression/coercion.cpp | 18 +++ src/mbgl/style/expression/dsl.cpp | 4 + src/mbgl/style/expression/interpolate.cpp | 4 + src/mbgl/style/expression/parsing_context.cpp | 4 + src/mbgl/style/expression/value.cpp | 8 ++ src/mbgl/style/layers/symbol_layer.cpp | 33 +++++ .../style/layers/symbol_layer_properties.hpp | 6 + src/mbgl/text/placement.cpp | 5 +- .../variable_anchor_offset_collection.cpp | 124 ++++++++++++++++++ 28 files changed, 392 insertions(+), 116 deletions(-) create mode 100644 include/mbgl/util/variable_anchor_offset_collection.hpp create mode 100644 src/mbgl/util/variable_anchor_offset_collection.cpp diff --git a/bazel/core.bzl b/bazel/core.bzl index d62f246be10..1d17e69d598 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -645,6 +645,7 @@ MLN_CORE_SOURCE = [ "src/mbgl/util/url.cpp", "src/mbgl/util/url.hpp", "src/mbgl/util/utf.hpp", + "src/mbgl/util/variable_anchor_offset_collection.cpp", "src/mbgl/util/version.cpp", "src/mbgl/util/version.hpp", "src/mbgl/util/work_request.cpp", @@ -850,6 +851,7 @@ MLN_CORE_HEADERS = [ "include/mbgl/util/type_list.hpp", "include/mbgl/util/unitbezier.hpp", "include/mbgl/util/util.hpp", + "include/mbgl/util/variable_anchor_offset_collection.hpp", "include/mbgl/util/variant.hpp", "include/mbgl/util/vectors.hpp", "include/mbgl/util/work_request.hpp", diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index ae0a40a0bf5..d74a99b8cd5 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,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 a45690d440d..a91c74caf12 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -315,6 +315,11 @@ struct ValueFactory { static Value make(const Color& color) { return color.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}; } @@ -363,6 +368,7 @@ template StyleProperty makeStyleProperty(const PropertyValue& value) { return value.match([](const Undefined&) -> StyleProperty { return {}; }, [](const Color& c) -> StyleProperty { return {makeValue(c), 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 9b6a157eb7d..2596cfbf4b8 100644 --- a/include/mbgl/style/expression/dsl.hpp +++ b/include/mbgl/style/expression/dsl.hpp @@ -42,6 +42,7 @@ std::unique_ptr string(std::unique_ptr, std::unique_ptr< std::unique_ptr boolean(std::unique_ptr, std::unique_ptr def = nullptr); std::unique_ptr toColor(std::unique_ptr, std::unique_ptr def = nullptr); +std::unique_ptr toVariableAnchorOffsetCollection(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 14f18e225bc..64a14117e61 100644 --- a/include/mbgl/style/expression/type.hpp +++ b/include/mbgl/style/expression/type.hpp @@ -44,6 +44,12 @@ struct ColorType { bool operator==(const ColorType&) 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"; } @@ -85,6 +91,7 @@ constexpr NumberType Number; constexpr StringType String; constexpr BooleanType Boolean; constexpr ColorType Color; +constexpr VariableAnchorOffsetCollectionType VariableAnchorOffsetCollection; constexpr ValueType Value; constexpr ObjectType Object; constexpr CollatorType Collator; @@ -99,6 +106,7 @@ using Type = variant, diff --git a/include/mbgl/style/expression/value.hpp b/include/mbgl/style/expression/value.hpp index 6bcc49f613b..764710bb276 100644 --- a/include/mbgl/style/expression/value.hpp +++ b/include/mbgl/style/expression/value.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ using ValueBase = variant #include #include +#include #include @@ -188,6 +189,10 @@ class SymbolLayer final : public Layer { const PropertyValue>& getTextWritingMode() const; void setTextWritingMode(const PropertyValue>&); + static PropertyValue getDefaultTextVariableAnchorOffset(); + const PropertyValue& getTextVariableAnchorOffset() const; + void setTextVariableAnchorOffset(const PropertyValue&); + // Paint properties static PropertyValue getDefaultIconColor(); diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index 13b6ef3f482..ffa23ef7699 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -125,6 +125,18 @@ struct Interpolator { } }; +template <> +struct Interpolator { +public: + VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const float t) noexcept { + return {}; + } + + VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const double t) noexcept { + return {}; + } +}; + template <> struct Interpolator { public: diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp new file mode 100644 index 00000000000..85fd4690728 --- /dev/null +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace mbgl { + +using AnchorOffsetMap = std::unordered_map>; + +class VariableAnchorOffsetCollection { +public: + VariableAnchorOffsetCollection() = default; + VariableAnchorOffsetCollection(const AnchorOffsetMap& values): anchorOffsets(std::move(values)) {}; + + static constexpr float INVALID_OFFSET_VALUE = std::numeric_limits::max(); + /** + * @brief Calculates variable text offset. + * + * @param anchor text anchor + * @param textOffset Either `text-offset` or [ `text-radial-offset`, + * INVALID_OFFSET_VALUE ] + * @return std::array offset along x- and y- axis correspondingly. + */ + static std::array evaluateVariableOffset(style::SymbolAnchorType anchor, std::array textOffset); + + static std::array evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset); + + static std::optional parse(const std::string& s); + + std::string stringify() const; + mbgl::Value serialize() const; + std::size_t getSize() const { return anchorOffsets.size(); } + + bool operator==(const VariableAnchorOffsetCollection& other) const; + +private: + static std::array evaluateTextOffset(style::SymbolAnchorType anchor, float offsetX, float offsetY); + + AnchorOffsetMap anchorOffsets; +}; + +} // namespace mbgl diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index a926089c30b..40d994d52c5 100644 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -179,6 +179,8 @@ global.objCTestValue = function (property, layerType, arraysAsStructs, indent) { return `@"'${_.last(_.keys(property.values))}'"`; case 'color': return '@"%@", [MLNColor redColor]'; + case 'variableAnchorOffsetCollection': + return `@"{"top": [1, 2]}"`; case 'array': switch (arrayType(property)) { case 'dasharray': @@ -224,6 +226,7 @@ global.mbglTestValue = function (property, layerType) { case 'formatted': case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': return `"${_.startCase(propertyName)}"`; case 'enum': { let type = camelize(originalPropertyName(property)); @@ -311,6 +314,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); @@ -495,6 +499,7 @@ global.describeType = function (property) { case 'formatted': case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': return 'string'; case 'enum': return '`MLN' + camelize(property.name) + '`'; @@ -544,6 +549,7 @@ global.describeValue = function (value, property, layerType) { case 'formatted': case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': if (value === '') { return 'the empty string'; } @@ -631,6 +637,7 @@ global.propertyType = function (property) { case 'formatted': case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': return 'NSString *'; case 'enum': return 'NSValue *'; @@ -684,6 +691,8 @@ global.valueTransformerArguments = function (property) { return [mbglType(property), 'NSValue *', mbglType(property), `MLN${camelize(property.name)}`]; case 'color': return ['mbgl::Color', objCType]; + case 'variableAnchorOffsetCollection': + return ['mbgl::VariableAnchorOffsetCollection', objCType]; case 'array': switch (arrayType(property)) { case 'dasharray': @@ -739,6 +748,8 @@ global.mbglType = function(property) { } case 'color': return 'mbgl::Color'; + 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 e20ccb4fdac..f833b70ace6 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -218,6 +218,12 @@ class MLNStyleValueTransformer { // Color void getMBGLValue(MLNColor *rawValue, mbgl::Color &mbglValue) { mbglValue = rawValue.mgl_color; } + // VariableAnchorOffsetCollection + void getMBGLValue(NSString *rawValue, mbgl::VariableAnchorOffsetCollection &mbglValue) { + mbgl::VariableAnchorOffsetCollection anchorOffset{}; + mbglValue = anchorOffset; + } + // Image void getMBGLValue(NSString *rawValue, mbgl::style::expression::Image &mbglValue) { mbglValue = mbgl::style::expression::Image(rawValue.UTF8String); @@ -295,6 +301,12 @@ class MLNStyleValueTransformer { return [MLNColor mgl_colorWithColor:mbglStopValue]; } + // VariableAnchorOffsetCollection + static NSArray *toMLNRawStyleValue(const mbgl::VariableAnchorOffsetCollection mbglStopValue) { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.getSize()]; + return array; + } + // Image static NSString *toMLNRawStyleValue(const mbgl::style::expression::Image &mbglImageValue) { return @(mbglImageValue.id().c_str()); diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index a1c431448d6..3b97fccd71d 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -49,6 +49,8 @@ global.expressionType = function (property) { return 'StringType'; case 'color': return `ColorType`; + case 'variableAnchorOffsetCollection': + return `VariableAnchorOffsetCollectionType`; case 'formatted': return `FormattedType`; case 'array': @@ -58,6 +60,9 @@ global.expressionType = function (property) { }; global.evaluatedType = function (property) { + if (/text-variable-anchor-offset/.test(property.name)) { + return 'VariableAnchorOffsetCollection'; + } if (/-translate-anchor$/.test(property.name)) { return 'TranslateAnchorType'; } @@ -190,6 +195,7 @@ global.defaultValue = function (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-reference/v8.json b/scripts/style-spec-reference/v8.json index 525700a109c..7ca0ea9fc3f 100644 --- a/scripts/style-spec-reference/v8.json +++ b/scripts/style-spec-reference/v8.json @@ -1942,6 +1942,38 @@ }, "property-type": "data-constant" }, + "text-variable-anchor-offset": { + "type": "variableAnchorOffsetCollection", + "requires": [ + "text-field", + { + "symbol-placement": [ + "point" + ] + } + ], + "doc": "To increase the chance of placing high-priority labels on the map, you can provide an array of `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. \n\n 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. \n\n When present, this property takes precedence over `text-anchor`, `text-variable-anchor`, `text-offset`, and `text-radial-offset`. \n\n ```json \n { \"text-variable-anchor-offset\": [\"top\", [0, 4], \"left\", [3,0], \"bottom\", [1, 1]] } \n ``` \n\n When the renderer chooses the `top` anchor, `[0, 4]` will be used for `text-offset`; the text will be shifted down by 4 ems. \n\n When the renderer chooses the `left` anchor, `[3, 0]` will be used for `text-offset`; the text will be shifted right by 3 ems.", + "sdk-support": { + "basic functionality": { + "js": "3.3.0", + "ios": "https://github.com/maplibre/maplibre-native/issues/2358", + "android": "https://github.com/maplibre/maplibre-native/issues/2358" + }, + "data-driven styling": { + "js": "3.3.0", + "ios": "https://github.com/maplibre/maplibre-native/issues/2358", + "android": "https://github.com/maplibre/maplibre-native/issues/2358" + } + }, + "expression": { + "interpolated": true, + "parameters": [ + "zoom", + "feature" + ] + }, + "property-type": "data-driven" + }, "text-anchor": { "type": "enum", "values": { diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 7051712f0ae..be390ccdc9d 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -228,13 +228,6 @@ bool SymbolLayout::hasSymbolInstances() const { namespace { -// The radial offset is to the edge of the text box -// In the horizontal direction, the edge of the text box is where glyphs start -// But in the vertical direction, the glyphs appear to "start" at the baseline -// We don't actually load baseline data, but we assume an offset of ONE_EM - 17 -// (see "yOffset" in shaping.js) -const float baselineOffset = 7.0f; - // We don't care which shaping we get because this is used for collision // purposes and all the justifications have the same collision box. const Shaping& getDefaultHorizontalShaping(const ShapedTextOrientations& shapedTextOrientations) { @@ -258,102 +251,8 @@ Shaping& shapingForTextJustifyType(ShapedTextOrientations& shapedTextOrientation } } -std::array evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset) { - std::array result{{0.0f, 0.0f}}; - if (radialOffset < 0.0f) radialOffset = 0.0f; // Ignore negative offset. - // solve for r where r^2 + r^2 = radialOffset^2 - const float sqrt2 = 1.41421356237f; - const float hypotenuse = radialOffset / sqrt2; - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::TopLeft: - result[1] = hypotenuse - baselineOffset; - break; - case SymbolAnchorType::BottomRight: - case SymbolAnchorType::BottomLeft: - result[1] = -hypotenuse + baselineOffset; - break; - case SymbolAnchorType::Bottom: - result[1] = -radialOffset + baselineOffset; - break; - case SymbolAnchorType::Top: - result[1] = radialOffset - baselineOffset; - break; - default: - break; - } - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::BottomRight: - result[0] = -hypotenuse; - break; - case SymbolAnchorType::TopLeft: - case SymbolAnchorType::BottomLeft: - result[0] = hypotenuse; - break; - case SymbolAnchorType::Left: - result[0] = radialOffset; - break; - case SymbolAnchorType::Right: - result[0] = -radialOffset; - break; - default: - break; - } - - return result; -} - } // namespace -// static -std::array SymbolLayout::evaluateVariableOffset(style::SymbolAnchorType anchor, std::array offset) { - if (offset[1] == INVALID_OFFSET_VALUE) { - return evaluateRadialOffset(anchor, offset[0]); - } - std::array result{{0.0f, 0.0f}}; - offset[0] = std::abs(offset[0]); - offset[1] = std::abs(offset[1]); - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::TopLeft: - case SymbolAnchorType::Top: - result[1] = offset[1] - baselineOffset; - break; - case SymbolAnchorType::BottomRight: - case SymbolAnchorType::BottomLeft: - case SymbolAnchorType::Bottom: - result[1] = -offset[1] + baselineOffset; - break; - case SymbolAnchorType::Center: - case SymbolAnchorType::Left: - case SymbolAnchorType::Right: - break; - } - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::BottomRight: - case SymbolAnchorType::Right: - result[0] = -offset[0]; - break; - case SymbolAnchorType::TopLeft: - case SymbolAnchorType::BottomLeft: - case SymbolAnchorType::Left: - result[0] = offset[0]; - break; - case SymbolAnchorType::Center: - case SymbolAnchorType::Top: - case SymbolAnchorType::Bottom: - break; - } - - return result; -} - void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, @@ -417,7 +316,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, // `text-radial-offset` together but doesn't actually // specify what happens if you use both. We go with the // radial offset. - textOffset = evaluateRadialOffset(textAnchor, radialOffset * util::ONE_EM); + textOffset = VariableAnchorOffsetCollection::evaluateRadialOffset(textAnchor, radialOffset * util::ONE_EM); } else { textOffset = {{layout->evaluate(zoom, feature, canonicalID)[0] * util::ONE_EM, layout->evaluate(zoom, feature, canonicalID)[1] * util::ONE_EM}}; @@ -569,7 +468,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, std::array variableTextOffset; if (!textRadialOffset.isUndefined()) { variableTextOffset = { - {layout->evaluate(zoom, feature, canonicalID) * util::ONE_EM, INVALID_OFFSET_VALUE}}; + {layout->evaluate(zoom, feature, canonicalID) * util::ONE_EM, VariableAnchorOffsetCollection::INVALID_OFFSET_VALUE}}; } else { variableTextOffset = {{layout->evaluate(zoom, feature, canonicalID)[0] * util::ONE_EM, layout->evaluate(zoom, feature, canonicalID)[1] * util::ONE_EM}}; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 12afca0c68a..d3d39b1f390 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -53,17 +53,6 @@ class SymbolLayout final : public Layout { std::vector symbolInstances; std::vector sortKeyRanges; - static constexpr float INVALID_OFFSET_VALUE = std::numeric_limits::max(); - /** - * @brief Calculates variable text offset. - * - * @param anchor text anchor - * @param textOffset Either `text-offset` or [ `text-radial-offset`, - * INVALID_OFFSET_VALUE ] - * @return std::array offset along x- and y- axis correspondingly. - */ - static std::array evaluateVariableOffset(style::SymbolAnchorType anchor, std::array textOffset); - static std::vector calculateTileDistances(const GeometryCoordinates& line, const Anchor& anchor); private: diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 55aa0d2648b..33c135eb794 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -113,6 +113,22 @@ std::optional Converter::operator()(const Convertible& value, Erro return *color; } +std::optional Converter::operator()(const Convertible& value, Error& error) const { + std::optional string = toString(value); + if (!string) { + error.message = "value must be a string"; + return std::nullopt; + } + + std::optional variableAnchorOffset = VariableAnchorOffsetCollection::parse(*string); + if (!variableAnchorOffset) { + error.message = "value must be a valid variable anchor offset"; + return std::nullopt; + } + + return *variableAnchorOffset; +} + 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 75bd885bb72..e782cd68f7e 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -131,6 +131,7 @@ template std::optional> convertFunctionToExpres Error&, bool); template std::optional> convertFunctionToExpression(const Convertible&, Error&, bool); +template std::optional> convertFunctionToExpression(const Convertible&, Error&, bool); template std::optional> convertFunctionToExpression(const Convertible&, Error&, bool); @@ -246,6 +247,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"; @@ -779,6 +787,9 @@ std::optional> convertFunctionToExpression(type::Typ [&](const type::ColorType&) -> std::optional> { return toColor(get(literal(*property)), defaultExpr()); }, + [&](const type::VariableAnchorOffsetCollectionType&) -> std::optional> { + return toVariableAnchorOffsetCollection(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 e7cac3b4221..c800f1f6617 100644 --- a/src/mbgl/style/conversion/property_value.cpp +++ b/src/mbgl/style/conversion/property_value.cpp @@ -78,6 +78,10 @@ template std::optional> Converter>::op 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 cd7c968b58f..ef92e49842b 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,11 @@ void stringify(Writer& writer, const Color& v) { writer.String(v.stringify()); } +template +void stringify(Writer& writer, const VariableAnchorOffsetCollection& v) { + writer.String(v.stringify()); +} + 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 d3f82a1dfaa..a3a9727a8a0 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -72,6 +72,22 @@ EvaluationResult toColor(const Value& colorValue) { }); } +EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { + return value.match( + [&](const VariableAnchorOffsetCollection& anchorOffset) -> EvaluationResult { return anchorOffset; }, + [&](const std::string& anchorOffsetString) -> EvaluationResult { + const std::optional result = VariableAnchorOffsetCollection::parse(anchorOffsetString); + if (result) { + return *result; + } else { + return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + anchorOffsetString + "'"}; + } + }, + [&](const auto&) -> EvaluationResult { + return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + stringify(value) + "'"}; + }); +} + EvaluationResult toFormatted(const Value& formattedValue) { return Formatted(toString(formattedValue).c_str()); } @@ -89,6 +105,8 @@ CoerceFunction getCoerceFunction(const type::Type& t) { return toBoolean; } else if (t.is()) { return toColor; + } else if (t.is()) { + return toVariableAnchorOffsetCollection; } else if (t.is()) { return toNumber; } else if (t.is()) { diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp index 26657949e0d..e6d194df45c 100644 --- a/src/mbgl/style/expression/dsl.cpp +++ b/src/mbgl/style/expression/dsl.cpp @@ -117,6 +117,10 @@ std::unique_ptr toColor(std::unique_ptr value, std::uniq return coercion(type::Color, std::move(value), std::move(def)); } +std::unique_ptr toVariableAnchorOffsetCollection(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 2c49bca5118..d73670db6fa 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -232,6 +232,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 cbeb9547455..7b4189dd63e 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -208,6 +208,10 @@ ParseResult ParsingContext::parse(const Convertible& value, (actual == type::Value || actual == type::String)) { parsed = {annotate( std::move(*parsed), std::move(*expected), typeAnnotationOption.value_or(TypeAnnotationOption::coerce))}; + } else if (*expected == type::VariableAnchorOffsetCollection && + (actual == type::Value || expected->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 3bc06a4322f..19fd096a28a 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -12,6 +12,7 @@ type::Type typeOf(const Value& value) { [&](double) -> type::Type { return type::Number; }, [&](const std::string&) -> type::Type { return type::String; }, [&](const Color&) -> type::Type { return type::Color; }, + [&](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; }, @@ -38,6 +39,7 @@ type::Type typeOf(const Value& value) { std::string toString(const Value& value) { return value.match([](const NullValue&) { return std::string(); }, [](const Color& c) { return c.stringify(); }, // avoid quoting + [](const VariableAnchorOffsetCollection& v) { return v.stringify(); }, [](const Formatted& f) { return f.toString(); }, [](const Image& i) { return i.id(); }, [](const std::string& s) { return s; }, // avoid quoting @@ -53,6 +55,7 @@ void writeJSON(rapidjson::Writer& writer, const Value& }, [&](const std::string& s) { writer.String(s); }, [&](const Color& c) { writer.String(c.stringify()); }, + [&](const VariableAnchorOffsetCollection& v) { writer.String(v.stringify()); }, [&](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. @@ -123,6 +126,7 @@ Value ValueConverter::toExpressionValue(const mbgl::Value& value) { mbgl::Value ValueConverter::fromExpressionValue(const Value& value) { return value.match( [&](const Color& color) -> mbgl::Value { return color.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 @@ -309,6 +313,10 @@ type::Type valueTypeToExpressionType() { return type::Color; } 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 a2ef653e3bd..4ace2f0ac18 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, false, false); + if (!typedValue) { + return error; + } + + setTextVariableAnchor(*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 296fc9e6369..17472a27678 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/text/placement.cpp b/src/mbgl/text/placement.cpp index feedcbdc829..eedcd01c21a 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -229,7 +230,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); + auto variableOffset = VariableAnchorOffsetCollection::evaluateVariableOffset(anchor, offset); Point shift{shiftX + variableOffset[0] * textBoxScale, shiftY + variableOffset[1] * textBoxScale}; if (rotateWithMap) { shift = util::rotate(shift, pitchWithMap ? bearing : -bearing); @@ -757,7 +758,7 @@ Point calculateVariableRenderShift(style::SymbolAnchorType anchor, AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); float shiftX = -(alignment.horizontalAlign - 0.5f) * width; float shiftY = -(alignment.verticalAlign - 0.5f) * height; - auto variablOffset = SymbolLayout::evaluateVariableOffset(anchor, textOffset); + auto variablOffset = VariableAnchorOffsetCollection::evaluateVariableOffset(anchor, textOffset); return {(shiftX / textBoxScale + variablOffset[0]) * renderTextSize, (shiftY / textBoxScale + variablOffset[1]) * renderTextSize}; } diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/util/variable_anchor_offset_collection.cpp new file mode 100644 index 00000000000..02664c17c20 --- /dev/null +++ b/src/mbgl/util/variable_anchor_offset_collection.cpp @@ -0,0 +1,124 @@ +#include + +namespace mbgl { + +using namespace style; + +// The radial offset is to the edge of the text box +// In the horizontal direction, the edge of the text box is where glyphs start +// But in the vertical direction, the glyphs appear to "start" at the baseline +// We don't actually load baseline data, but we assume an offset of ONE_EM - 17 +// (see "yOffset" in shaping.js) +static constexpr float baselineOffset = 7.0f; + +// static +std::array VariableAnchorOffsetCollection::evaluateVariableOffset(style::SymbolAnchorType anchor, std::array offset) { + return offset[1] == INVALID_OFFSET_VALUE ? evaluateRadialOffset(anchor, offset[0]) : evaluateTextOffset(anchor, offset[0], offset[1]); +} + +std::optional VariableAnchorOffsetCollection::parse(const std::string& s) { + return {}; +} + +std::string VariableAnchorOffsetCollection::stringify() const { + return "[]"; +} + +mbgl::Value VariableAnchorOffsetCollection::serialize() const { + return std::vector{}; +} + +bool VariableAnchorOffsetCollection::operator==(const VariableAnchorOffsetCollection& other) const { + return true; +} + +std::array VariableAnchorOffsetCollection::evaluateTextOffset(style::SymbolAnchorType anchor, float offsetX, float offsetY) { + std::array result{{0.0f, 0.0f}}; + offsetX = std::abs(offsetX); + offsetY = std::abs(offsetY); + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::Top: + result[1] = offsetY - baselineOffset; + break; + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::BottomLeft: + case SymbolAnchorType::Bottom: + result[1] = -offsetY + baselineOffset; + break; + case SymbolAnchorType::Center: + case SymbolAnchorType::Left: + case SymbolAnchorType::Right: + break; + } + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::Right: + result[0] = -offsetX; + break; + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::BottomLeft: + case SymbolAnchorType::Left: + result[0] = offsetX; + break; + case SymbolAnchorType::Center: + case SymbolAnchorType::Top: + case SymbolAnchorType::Bottom: + break; + } + + return result; +} + +std::array VariableAnchorOffsetCollection::evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset) { + std::array result{{0.0f, 0.0f}}; + if (radialOffset < 0.0f) radialOffset = 0.0f; // Ignore negative offset. + // solve for r where r^2 + r^2 = radialOffset^2 + const float sqrt2 = 1.41421356237f; + const float hypotenuse = radialOffset / sqrt2; + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::TopLeft: + result[1] = hypotenuse - baselineOffset; + break; + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::BottomLeft: + result[1] = -hypotenuse + baselineOffset; + break; + case SymbolAnchorType::Bottom: + result[1] = -radialOffset + baselineOffset; + break; + case SymbolAnchorType::Top: + result[1] = radialOffset - baselineOffset; + break; + default: + break; + } + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::BottomRight: + result[0] = -hypotenuse; + break; + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::BottomLeft: + result[0] = hypotenuse; + break; + case SymbolAnchorType::Left: + result[0] = radialOffset; + break; + case SymbolAnchorType::Right: + result[0] = -radialOffset; + break; + default: + break; + } + + return result; +} +} // namespace mbgl From 06619f372a016f79dfa80e1e98b1fa0b980f0746 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Fri, 23 Aug 2024 23:17:25 +0800 Subject: [PATCH 02/35] revert change in placement --- src/mbgl/layout/symbol_layout.cpp | 105 +++++++++++++++++++++++++++++- src/mbgl/layout/symbol_layout.hpp | 11 ++++ src/mbgl/text/placement.cpp | 3 +- 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 3a88364de58..bee82a066a4 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -232,6 +232,13 @@ bool SymbolLayout::hasSymbolInstances() const { namespace { +// The radial offset is to the edge of the text box +// In the horizontal direction, the edge of the text box is where glyphs start +// But in the vertical direction, the glyphs appear to "start" at the baseline +// We don't actually load baseline data, but we assume an offset of ONE_EM - 17 +// (see "yOffset" in shaping.js) +const float baselineOffset = 7.0f; + // We don't care which shaping we get because this is used for collision // purposes and all the justifications have the same collision box. const Shaping& getDefaultHorizontalShaping(const ShapedTextOrientations& shapedTextOrientations) { @@ -255,8 +262,102 @@ Shaping& shapingForTextJustifyType(ShapedTextOrientations& shapedTextOrientation } } +std::array evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset) { + std::array result{{0.0f, 0.0f}}; + if (radialOffset < 0.0f) radialOffset = 0.0f; // Ignore negative offset. + // solve for r where r^2 + r^2 = radialOffset^2 + const float sqrt2 = 1.41421356237f; + const float hypotenuse = radialOffset / sqrt2; + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::TopLeft: + result[1] = hypotenuse - baselineOffset; + break; + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::BottomLeft: + result[1] = -hypotenuse + baselineOffset; + break; + case SymbolAnchorType::Bottom: + result[1] = -radialOffset + baselineOffset; + break; + case SymbolAnchorType::Top: + result[1] = radialOffset - baselineOffset; + break; + default: + break; + } + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::BottomRight: + result[0] = -hypotenuse; + break; + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::BottomLeft: + result[0] = hypotenuse; + break; + case SymbolAnchorType::Left: + result[0] = radialOffset; + break; + case SymbolAnchorType::Right: + result[0] = -radialOffset; + break; + default: + break; + } + + return result; +} + } // namespace +// static +std::array SymbolLayout::evaluateVariableOffset(style::SymbolAnchorType anchor, std::array offset) { + if (offset[1] == INVALID_OFFSET_VALUE) { + return evaluateRadialOffset(anchor, offset[0]); + } + std::array result{{0.0f, 0.0f}}; + offset[0] = std::abs(offset[0]); + offset[1] = std::abs(offset[1]); + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::Top: + result[1] = offset[1] - baselineOffset; + break; + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::BottomLeft: + case SymbolAnchorType::Bottom: + result[1] = -offset[1] + baselineOffset; + break; + case SymbolAnchorType::Center: + case SymbolAnchorType::Left: + case SymbolAnchorType::Right: + break; + } + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::Right: + result[0] = -offset[0]; + break; + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::BottomLeft: + case SymbolAnchorType::Left: + result[0] = offset[0]; + break; + case SymbolAnchorType::Center: + case SymbolAnchorType::Top: + case SymbolAnchorType::Bottom: + break; + } + + return result; +} + void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, @@ -320,7 +421,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, // `text-radial-offset` together but doesn't actually // specify what happens if you use both. We go with the // radial offset. - textOffset = VariableAnchorOffsetCollection::evaluateRadialOffset(textAnchor, radialOffset * util::ONE_EM); + textOffset = evaluateRadialOffset(textAnchor, radialOffset * util::ONE_EM); } else { textOffset = {{layout->evaluate(zoom, feature, canonicalID)[0] * util::ONE_EM, layout->evaluate(zoom, feature, canonicalID)[1] * util::ONE_EM}}; @@ -472,7 +573,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, std::array variableTextOffset; if (!textRadialOffset.isUndefined()) { variableTextOffset = { - {layout->evaluate(zoom, feature, canonicalID) * util::ONE_EM, VariableAnchorOffsetCollection::INVALID_OFFSET_VALUE}}; + {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}}; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index d3d39b1f390..12afca0c68a 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -53,6 +53,17 @@ class SymbolLayout final : public Layout { std::vector symbolInstances; std::vector sortKeyRanges; + static constexpr float INVALID_OFFSET_VALUE = std::numeric_limits::max(); + /** + * @brief Calculates variable text offset. + * + * @param anchor text anchor + * @param textOffset Either `text-offset` or [ `text-radial-offset`, + * INVALID_OFFSET_VALUE ] + * @return std::array offset along x- and y- axis correspondingly. + */ + static std::array evaluateVariableOffset(style::SymbolAnchorType anchor, std::array textOffset); + static std::vector calculateTileDistances(const GeometryCoordinates& line, const Anchor& anchor); private: diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 9eee263142c..f43c6cad88b 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -230,7 +229,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 = VariableAnchorOffsetCollection::evaluateVariableOffset(anchor, offset); + auto variableOffset = SymbolLayout::evaluateVariableOffset(anchor, offset); Point shift{shiftX + variableOffset[0] * textBoxScale, shiftY + variableOffset[1] * textBoxScale}; if (rotateWithMap) { shift = util::rotate(shift, pitchWithMap ? bearing : -bearing); From 7096c765f1f52ad6b6d08e843c33596821097b86 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Fri, 6 Sep 2024 16:00:50 +0800 Subject: [PATCH 03/35] use text-variable-anchor-offset in placement --- include/mbgl/util/interpolate.hpp | 29 +++- .../variable_anchor_offset_collection.hpp | 69 +++++---- src/mbgl/layout/symbol_instance.cpp | 4 +- src/mbgl/layout/symbol_instance.hpp | 4 +- src/mbgl/layout/symbol_layout.cpp | 69 +++++++-- src/mbgl/layout/symbol_layout.hpp | 5 + src/mbgl/style/conversion/constant.cpp | 44 +++++- src/mbgl/style/conversion/stringify.hpp | 12 +- src/mbgl/style/expression/coercion.cpp | 8 +- src/mbgl/style/expression/value.cpp | 6 +- .../style/layers/symbol_layer_properties.hpp | 2 +- src/mbgl/text/placement.cpp | 49 ++++-- .../variable_anchor_offset_collection.cpp | 140 ++++-------------- test/style/conversion/stringify.test.cpp | 7 + test/text/cross_tile_symbol_index.test.cpp | 5 +- 15 files changed, 269 insertions(+), 184 deletions(-) diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index ffa23ef7699..cfc035280bb 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -3,8 +3,11 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -128,12 +131,26 @@ struct Interpolator { template <> struct Interpolator { public: - VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const float t) noexcept { - return {}; - } - - VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const double t) noexcept { - return {}; + VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const float t) noexcept { + auto aOffsets = a.getOffsets(); + auto bOffsets = b.getOffsets(); + if (aOffsets.size() != bOffsets.size()) + { + throw std::runtime_error("Cannot interpolate values of different length. from: " + a.toString() + ", to: " + b.toString()); + } + + AnchorOffsetMap offsetMap; + for (auto index = 0; index < aOffsets.size(); index++) { + auto aPair = std::next(aOffsets.begin(), index); + auto bPair = std::next(bOffsets.begin(), index); + if (aPair->first != bPair->first) { + throw std::runtime_error("Cannot interpolate values containing mismatched anchors. index:" + util::toString(index) + "from: " + Enum::toString(aPair->first) + ", to:" + Enum::toString(bPair->first)); + } + + offsetMap[aPair->first] = std::array{ interpolate(aPair->second[0], bPair->second[0], t), interpolate(aPair->second[1], bPair->second[1], t) }; + } + + return VariableAnchorOffsetCollection(offsetMap); } }; diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index 85fd4690728..f5b00ec3df1 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -2,45 +2,64 @@ #include #include +#include #include -#include +#include #include namespace mbgl { -using AnchorOffsetMap = std::unordered_map>; +using AnchorOffsetMap = std::map>; class VariableAnchorOffsetCollection { + public: - VariableAnchorOffsetCollection() = default; - VariableAnchorOffsetCollection(const AnchorOffsetMap& values): anchorOffsets(std::move(values)) {}; - - static constexpr float INVALID_OFFSET_VALUE = std::numeric_limits::max(); - /** - * @brief Calculates variable text offset. - * - * @param anchor text anchor - * @param textOffset Either `text-offset` or [ `text-radial-offset`, - * INVALID_OFFSET_VALUE ] - * @return std::array offset along x- and y- axis correspondingly. - */ - static std::array evaluateVariableOffset(style::SymbolAnchorType anchor, std::array textOffset); - - static std::array evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset); + VariableAnchorOffsetCollection() = default; + + // Copy constructor + VariableAnchorOffsetCollection(const VariableAnchorOffsetCollection& other) { + anchorOffsets = other.anchorOffsets; + } + + // Move constructor + VariableAnchorOffsetCollection(VariableAnchorOffsetCollection&& other) noexcept { + anchorOffsets = std::move(other.anchorOffsets); + } - static std::optional parse(const std::string& s); + VariableAnchorOffsetCollection(const AnchorOffsetMap& values) { + anchorOffsets = std::move(values); + } - std::string stringify() const; - mbgl::Value serialize() const; - std::size_t getSize() const { return anchorOffsets.size(); } + std::string toString() const; + mbgl::Value serialize() const; + bool empty() const; + AnchorOffsetMap getOffsets() const; - bool operator==(const VariableAnchorOffsetCollection& other) const; + // Copy assignment operator + VariableAnchorOffsetCollection& operator=(VariableAnchorOffsetCollection& other) { + if (this != &other) { + anchorOffsets = other.anchorOffsets; + } + + return *this; + } + + // Move assignment operator + VariableAnchorOffsetCollection& operator=(VariableAnchorOffsetCollection&& other) noexcept { + if (this != &other) { + anchorOffsets = std::move(other.anchorOffsets); + } + + return *this; + } + + bool operator==(const VariableAnchorOffsetCollection& other) const { + return anchorOffsets == other.anchorOffsets; + } private: - static std::array evaluateTextOffset(style::SymbolAnchorType anchor, float offsetX, float offsetY); - - AnchorOffsetMap anchorOffsets; + AnchorOffsetMap anchorOffsets; }; } // namespace mbgl diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index 02447956609..5ab92097d79 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -94,7 +94,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_)), @@ -121,7 +121,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; diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 3d57d1d71d6..05d8848c433 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -73,7 +73,7 @@ class SymbolInstance { float overscaling, float iconRotation, float textRotation, - const std::array& variableTextOffset, + const std::optional& textVariableAnchorOffset, bool allowVerticalPlacement, SymbolContent iconType = SymbolContent::None); @@ -120,7 +120,7 @@ class SymbolInstance { std::optional placedIconIndex; std::optional placedVerticalIconIndex; float textBoxScale; - std::array variableTextOffset; + std::optional textVariableAnchorOffset; bool singleLine; uint32_t crossTileID = 0; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index bee82a066a4..4ca92d4b586 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -103,6 +103,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,63 @@ std::array SymbolLayout::evaluateVariableOffset(style::SymbolAnchorTyp return result; } +std::optional SymbolLayout::getTextVariableAnchorOffset(const SymbolFeature& feature) +{ + // If style specifies text-variable-anchor-offset, just return it + std::array variableTextOffset; + if (!textVariableAnchorOffset.isUndefined()) { + AnchorOffsetMap anchorOffsets; + auto variableAnchorOffset = layout->evaluate(zoom, feature, canonicalID); + + // Convert offsets from EM to PX, and apply baseline shift + for (const auto anchorOffset: variableAnchorOffset.getOffsets()) { + variableTextOffset = {{anchorOffset.second[0] * util::ONE_EM, anchorOffset.second[1] * util::ONE_EM}}; + switch (anchorOffset.first) { + 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[anchorOffset.first] = std::array{ variableTextOffset[0], variableTextOffset[1] }; + } + + return VariableAnchorOffsetCollection(anchorOffsets); + } + + const std::vector variableTextAnchor = layout->evaluate(zoom, feature, canonicalID); + const SymbolAnchorType textAnchor = layout->evaluate(zoom, feature, canonicalID); + if (!variableTextAnchor.empty()) { + 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}}; + } + + AnchorOffsetMap anchorOffsets; + for (auto anchor : variableTextAnchor) { + variableTextOffset = SymbolLayout::evaluateVariableOffset(anchor, variableTextOffset); + anchorOffsets[anchor] = std::array{ variableTextOffset[0], variableTextOffset[1] }; + } + + return VariableAnchorOffsetCollection(anchorOffsets); + } + + return std::nullopt; +} + void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, @@ -570,14 +628,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; - 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}}; - } + auto textVariableAnchorOffset = getTextVariableAnchorOffset(feature); const SymbolPlacementType textPlacement = layout->get() != AlignmentType::Map ? SymbolPlacementType::Point @@ -635,7 +686,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, overscaling, iconRotation, textRotation, - variableTextOffset, + textVariableAnchorOffset, allowVerticalPlacement, iconType); diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 12afca0c68a..4aa950d27c1 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,9 @@ class SymbolLayout final : public Layout { const SymbolFeature&, 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. @@ -134,6 +138,7 @@ class SymbolLayout final : public Layout { 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/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 33c135eb794..7fc7e4085a3 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -114,19 +114,47 @@ std::optional Converter::operator()(const Convertible& value, Erro } std::optional Converter::operator()(const Convertible& value, Error& error) const { - std::optional string = toString(value); - if (!string) { - error.message = "value must be a string"; + if (!isArray(value)) { + error.message = "value must be an array"; return std::nullopt; } - - std::optional variableAnchorOffset = VariableAnchorOffsetCollection::parse(*string); - if (!variableAnchorOffset) { - error.message = "value must be a valid variable anchor offset"; + + const auto arraySize = arrayLength(value); + if (arraySize < 1 || arraySize % 2 != 0) { return std::nullopt; } + + AnchorOffsetMap collection; + 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; + } - return *variableAnchorOffset; + 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; + } + + collection[anchor.value()] = std::array{ xOffset.value(), yOffset.value() }; + } + + return VariableAnchorOffsetCollection(collection); } template diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index ef92e49842b..eff69de0f16 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -61,7 +61,17 @@ void stringify(Writer& writer, const Color& v) { template void stringify(Writer& writer, const VariableAnchorOffsetCollection& v) { - writer.String(v.stringify()); + writer.StartArray(); + + for (const auto& pair : v.getOffsets()) { + writer.String(Enum::toString(pair.first)); + writer.StartArray(); + writer.Double(pair.second[0]); + writer.Double(pair.second[1]); + writer.EndArray(); + } + + writer.EndArray(); } template diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index a3a9727a8a0..c0ce181a6ba 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -72,16 +72,12 @@ EvaluationResult toColor(const Value& colorValue) { }); } +// TODO (Yingfang) need evaluate the expression value to mbgl value EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { return value.match( [&](const VariableAnchorOffsetCollection& anchorOffset) -> EvaluationResult { return anchorOffset; }, [&](const std::string& anchorOffsetString) -> EvaluationResult { - const std::optional result = VariableAnchorOffsetCollection::parse(anchorOffsetString); - if (result) { - return *result; - } else { - return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + anchorOffsetString + "'"}; - } + return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + anchorOffsetString + "'"}; }, [&](const auto&) -> EvaluationResult { return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + stringify(value) + "'"}; diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index 19fd096a28a..1d6f2c3a203 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -39,7 +39,7 @@ type::Type typeOf(const Value& value) { std::string toString(const Value& value) { return value.match([](const NullValue&) { return std::string(); }, [](const Color& c) { return c.stringify(); }, // avoid quoting - [](const VariableAnchorOffsetCollection& v) { return v.stringify(); }, + [](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,7 +55,9 @@ void writeJSON(rapidjson::Writer& writer, const Value& }, [&](const std::string& s) { writer.String(s); }, [&](const Color& c) { writer.String(c.stringify()); }, - [&](const VariableAnchorOffsetCollection& v) { writer.String(v.stringify()); }, + [&](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. diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index 17472a27678..edf597bf375 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.hpp +++ b/src/mbgl/style/layers/symbol_layer_properties.hpp @@ -218,7 +218,7 @@ struct TextVariableAnchor : LayoutProperty> struct TextVariableAnchorOffset : DataDrivenLayoutProperty { static constexpr const char *name() { return "text-variable-anchor-offset"; } - static VariableAnchorOffsetCollection defaultValue() { return ; } + static VariableAnchorOffsetCollection defaultValue() { return {}; } }; struct TextWritingMode : LayoutProperty> { diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index f43c6cad88b..03da73ed38e 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -70,6 +70,7 @@ class PlacementContext { std::reference_wrapper bucket; std::reference_wrapper renderTile; std::reference_wrapper state; + std::vector textVariableAnchors; public: PlacementContext(const SymbolBucket& bucket_, @@ -87,7 +88,18 @@ class PlacementContext { collisionGroup(std::move(collisionGroup_)), partiallyEvaluatedTextSize(bucket_.textSizeBinder->evaluateForZoom(placementZoom)), partiallyEvaluatedIconSize(bucket_.iconSizeBinder->evaluateForZoom(placementZoom)), - avoidEdges(std::move(avoidEdges_)) {} + avoidEdges(std::move(avoidEdges_)) { + auto textVariableAnchorOffset = getLayout().get(); + auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); + if (!variableAnchorOffset.empty()) { + for (const auto anchorOffset: variableAnchorOffset.getOffsets()) { + textVariableAnchors.push_back(anchorOffset.first); + } + } + else { + textVariableAnchors = std::move(getLayout().get()); + } + } const SymbolBucket& getBucket() const { return bucket.get(); } const style::SymbolLayoutProperties::PossiblyEvaluated& getLayout() const { return *getBucket().layout; } @@ -98,7 +110,7 @@ class PlacementContext { const TransformState& getTransformState() const { return state; } const std::vector& getVariableTextAnchors() const { - return getLayout().get(); + return textVariableAnchors; } float pixelsToTileUnits; @@ -229,8 +241,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); } @@ -409,11 +420,13 @@ 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 textVariableAnchorOffset = symbolInstance.textVariableAnchorOffset->getOffsets(); + auto variableTextOffset = textVariableAnchorOffset[anchor]; const bool allowOverlap = (i >= anchorsSize); shift = calculateVariableLayoutOffset(anchor, width, height, - symbolInstance.variableTextOffset, + variableTextOffset, textBoxScale, ctx.rotateTextWithMap, ctx.pitchTextWithMap, @@ -478,8 +491,7 @@ JointPlacement Placement::placeSymbol(const SymbolInstance& symbolInstance, cons variableOffsets.insert(std::make_pair( symbolInstance.crossTileID, - VariableOffset{ - symbolInstance.variableTextOffset, width, height, anchor, textBoxScale, prevAnchor})); + VariableOffset{variableTextOffset, width, height, anchor, textBoxScale, prevAnchor})); if (bucket.allowVerticalPlacement) { placedOrientations.emplace(symbolInstance.crossTileID, orientation); @@ -757,9 +769,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; - const 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 @@ -769,7 +780,11 @@ 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(); + auto textVariableAnchorOffset = layout.get(); + auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); + + const bool hasVariableAnchors = (!layout.get().empty() || !variableAnchorOffset.empty()) + && bucket.hasTextData(); const bool updateTextFitIcon = layout.get() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && (bucket.hasIconData() || bucket.hasSdfIconData()); @@ -1522,10 +1537,14 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se if (variableAnchor) { float width = textCollisionBox.x2 - textCollisionBox.x1; float height = textCollisionBox.y2 - textCollisionBox.y1; + + auto textVariableAnchorOffset = symbol.textVariableAnchorOffset->getOffsets(); + auto variableTextOffset = textVariableAnchorOffset[*variableAnchor]; + offset = calculateVariableLayoutOffset(*variableAnchor, width, height, - symbol.variableTextOffset, + variableTextOffset, symbol.textBoxScale, rotateTextWithMap, pitchTextWithMap, @@ -1540,10 +1559,14 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se if (variableAnchor && variableIconPlacement) { float width = iconCollisionBox.x2 - iconCollisionBox.x1; float height = iconCollisionBox.y2 - iconCollisionBox.y1; + + auto textVariableAnchorOffset = symbol.textVariableAnchorOffset->getOffsets(); + auto variableTextOffset = textVariableAnchorOffset[*variableAnchor]; + offset = calculateVariableLayoutOffset(*variableAnchor, width, height, - symbol.variableTextOffset, + variableTextOffset, symbol.textBoxScale, rotateTextWithMap, pitchTextWithMap, diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/util/variable_anchor_offset_collection.cpp index 02664c17c20..82ded0b72b2 100644 --- a/src/mbgl/util/variable_anchor_offset_collection.cpp +++ b/src/mbgl/util/variable_anchor_offset_collection.cpp @@ -1,124 +1,48 @@ #include +#include +#include + +#include +#include namespace mbgl { +using namespace std; using namespace style; -// The radial offset is to the edge of the text box -// In the horizontal direction, the edge of the text box is where glyphs start -// But in the vertical direction, the glyphs appear to "start" at the baseline -// We don't actually load baseline data, but we assume an offset of ONE_EM - 17 -// (see "yOffset" in shaping.js) -static constexpr float baselineOffset = 7.0f; +bool VariableAnchorOffsetCollection::empty() const { + return anchorOffsets.size() == 0; +}; -// static -std::array VariableAnchorOffsetCollection::evaluateVariableOffset(style::SymbolAnchorType anchor, std::array offset) { - return offset[1] == INVALID_OFFSET_VALUE ? evaluateRadialOffset(anchor, offset[0]) : evaluateTextOffset(anchor, offset[0], offset[1]); +AnchorOffsetMap VariableAnchorOffsetCollection::getOffsets() const { + return anchorOffsets; } -std::optional VariableAnchorOffsetCollection::parse(const std::string& s) { - return {}; -} +std::string VariableAnchorOffsetCollection::toString() const { + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + writer.StartArray(); + for (const auto& pair : anchorOffsets) { + writer.String(Enum::toString(pair.first)); + writer.StartArray(); + writer.Double(pair.second[0]); + writer.Double(pair.second[1]); + writer.EndArray(); + } -std::string VariableAnchorOffsetCollection::stringify() const { - return "[]"; + writer.EndArray(); + string stringValue = buffer.GetString(); + return stringValue; } mbgl::Value VariableAnchorOffsetCollection::serialize() const { - return std::vector{}; -} - -bool VariableAnchorOffsetCollection::operator==(const VariableAnchorOffsetCollection& other) const { - return true; -} - -std::array VariableAnchorOffsetCollection::evaluateTextOffset(style::SymbolAnchorType anchor, float offsetX, float offsetY) { - std::array result{{0.0f, 0.0f}}; - offsetX = std::abs(offsetX); - offsetY = std::abs(offsetY); - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::TopLeft: - case SymbolAnchorType::Top: - result[1] = offsetY - baselineOffset; - break; - case SymbolAnchorType::BottomRight: - case SymbolAnchorType::BottomLeft: - case SymbolAnchorType::Bottom: - result[1] = -offsetY + baselineOffset; - break; - case SymbolAnchorType::Center: - case SymbolAnchorType::Left: - case SymbolAnchorType::Right: - break; - } - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::BottomRight: - case SymbolAnchorType::Right: - result[0] = -offsetX; - break; - case SymbolAnchorType::TopLeft: - case SymbolAnchorType::BottomLeft: - case SymbolAnchorType::Left: - result[0] = offsetX; - break; - case SymbolAnchorType::Center: - case SymbolAnchorType::Top: - case SymbolAnchorType::Bottom: - break; - } - - return result; -} - -std::array VariableAnchorOffsetCollection::evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset) { - std::array result{{0.0f, 0.0f}}; - if (radialOffset < 0.0f) radialOffset = 0.0f; // Ignore negative offset. - // solve for r where r^2 + r^2 = radialOffset^2 - const float sqrt2 = 1.41421356237f; - const float hypotenuse = radialOffset / sqrt2; - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::TopLeft: - result[1] = hypotenuse - baselineOffset; - break; - case SymbolAnchorType::BottomRight: - case SymbolAnchorType::BottomLeft: - result[1] = -hypotenuse + baselineOffset; - break; - case SymbolAnchorType::Bottom: - result[1] = -radialOffset + baselineOffset; - break; - case SymbolAnchorType::Top: - result[1] = radialOffset - baselineOffset; - break; - default: - break; - } - - switch (anchor) { - case SymbolAnchorType::TopRight: - case SymbolAnchorType::BottomRight: - result[0] = -hypotenuse; - break; - case SymbolAnchorType::TopLeft: - case SymbolAnchorType::BottomLeft: - result[0] = hypotenuse; - break; - case SymbolAnchorType::Left: - result[0] = radialOffset; - break; - case SymbolAnchorType::Right: - result[0] = -radialOffset; - break; - default: - break; + std::vector serialized; + for (const auto& pair : anchorOffsets) { + serialized.emplace_back(Enum::toString(pair.first)); + std::vector offset { pair.second[0], pair.second[1] }; + serialized.emplace_back(offset); } - - return result; + + return serialized; } } // namespace mbgl diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp index cc79b753383..66e0eea33af 100644 --- a/test/style/conversion/stringify.test.cpp +++ b/test/style/conversion/stringify.test.cpp @@ -58,6 +58,13 @@ TEST(Stringify, Color) { ASSERT_EQ(stringify(Color::blue()), "\"rgba(0,0,255,1)\""); } +TEST(Stringify, VariableAnchorOffsetCollection) { + std::array offset = { 1, 1 }; + std::map> test; + test[SymbolAnchorType::Left] = offset; + ASSERT_EQ(stringify(VariableAnchorOffsetCollection(test)), "[\"left\",[1.0,1.0]]"); +} + TEST(Stringify, Array) { ASSERT_EQ(stringify(std::array{{1, 2}}), "[1.0,2.0]"); } diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index 3f3ccf3d7a8..c83ed4abb5f 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -2,6 +2,7 @@ #include #include #include +#include using namespace mbgl; @@ -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}}; + AnchorOffsetMap anchorOffsets = {{ style::SymbolAnchorType::Left, variableTextOffset }}; + VariableAnchorOffsetCollection variableAnchorOffsetCollection(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); } From f7fe15a4fe414892819f894b326e99653814333c Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Wed, 11 Sep 2024 11:28:27 +0800 Subject: [PATCH 04/35] fix failed render test --- src/mbgl/layout/symbol_layout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 4ca92d4b586..604abcf7e63 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -406,8 +406,8 @@ std::optional SymbolLayout::getTextVariableAncho AnchorOffsetMap anchorOffsets; for (auto anchor : variableTextAnchor) { - variableTextOffset = SymbolLayout::evaluateVariableOffset(anchor, variableTextOffset); - anchorOffsets[anchor] = std::array{ variableTextOffset[0], variableTextOffset[1] }; + auto offset = SymbolLayout::evaluateVariableOffset(anchor, variableTextOffset); + anchorOffsets[anchor] = std::array{ offset[0], offset[1] }; } return VariableAnchorOffsetCollection(anchorOffsets); From 7688166675b6f7a61ffb7962272900c9a4782c1e Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Thu, 19 Sep 2024 10:07:47 +0800 Subject: [PATCH 05/35] change map to vector --- include/mbgl/util/interpolate.hpp | 6 ++-- .../variable_anchor_offset_collection.hpp | 11 ++++---- metrics/cache-style.db | Bin 19214336 -> 19214336 bytes metrics/integration/sprites/icon-offset.json | 9 ++++++ metrics/integration/sprites/icon-offset.png | Bin 0 -> 1010 bytes platform/darwin/src/MLNStyleValue_Private.h | 4 ++- src/mbgl/layout/symbol_layout.cpp | 26 +++++++++++++----- src/mbgl/layout/symbol_layout.hpp | 2 ++ src/mbgl/style/conversion/constant.cpp | 6 ++-- src/mbgl/text/placement.cpp | 17 ++++++------ .../variable_anchor_offset_collection.cpp | 12 +++++++- test/style/conversion/stringify.test.cpp | 4 +-- test/text/cross_tile_symbol_index.test.cpp | 2 +- 13 files changed, 70 insertions(+), 29 deletions(-) create mode 100644 metrics/integration/sprites/icon-offset.json create mode 100644 metrics/integration/sprites/icon-offset.png diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index cfc035280bb..a8c4fa8bac7 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -139,7 +139,7 @@ struct Interpolator { throw std::runtime_error("Cannot interpolate values of different length. from: " + a.toString() + ", to: " + b.toString()); } - AnchorOffsetMap offsetMap; + std::vector offsetMap; for (auto index = 0; index < aOffsets.size(); index++) { auto aPair = std::next(aOffsets.begin(), index); auto bPair = std::next(bOffsets.begin(), index); @@ -147,7 +147,9 @@ struct Interpolator { throw std::runtime_error("Cannot interpolate values containing mismatched anchors. index:" + util::toString(index) + "from: " + Enum::toString(aPair->first) + ", to:" + Enum::toString(bPair->first)); } - offsetMap[aPair->first] = std::array{ interpolate(aPair->second[0], bPair->second[0], t), interpolate(aPair->second[1], bPair->second[1], t) }; + auto offset = std::array{ interpolate(aPair->second[0], bPair->second[0], t), interpolate(aPair->second[1], bPair->second[1], t) }; + AnchorOffsetPair anchorOffset = {aPair->first, offset}; + offsetMap.emplace_back(anchorOffset); } return VariableAnchorOffsetCollection(offsetMap); diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index f5b00ec3df1..f34a4dd51e7 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -5,12 +5,12 @@ #include #include -#include +#include #include namespace mbgl { -using AnchorOffsetMap = std::map>; +using AnchorOffsetPair = std::pair>; class VariableAnchorOffsetCollection { @@ -27,14 +27,15 @@ class VariableAnchorOffsetCollection { anchorOffsets = std::move(other.anchorOffsets); } - VariableAnchorOffsetCollection(const AnchorOffsetMap& values) { + VariableAnchorOffsetCollection(const std::vector& values) { anchorOffsets = std::move(values); } std::string toString() const; mbgl::Value serialize() const; bool empty() const; - AnchorOffsetMap getOffsets() const; + std::vector getOffsets() const; + std::array getOffsetByAnchor(const style::SymbolAnchorType& anchorType) const; // Copy assignment operator VariableAnchorOffsetCollection& operator=(VariableAnchorOffsetCollection& other) { @@ -59,7 +60,7 @@ class VariableAnchorOffsetCollection { } private: - AnchorOffsetMap anchorOffsets; + std::vector anchorOffsets; }; } // namespace mbgl diff --git a/metrics/cache-style.db b/metrics/cache-style.db index b24c05547e149083cfe58def7df6af8fcbba7fe8..80cb35937b15a80b1d5a27f5f9de3f4f48fcdd75 100644 GIT binary patch delta 1660 zcmZwHX;f5I0KoBk=gq*3GXo4VAnULhN`WGUC2DS&gocWiIV~VMD6$#0mob`QQ81)7 z8P#BW7Q)07rWRCY(Mq=O(uVCtW>}>CFLjQ6=)>=S-nsXld(J!WzFT{6i>Vf#SZjk2 z;e|rj%7qY)rZE!@4I;C0w|{wy!&qV+WH3Buvn6q#&N}FCN|PN&la8B%7)*DM>o}Hi zC`tM|`U~Q#wKh{rM{u`O>P_i*d;m6~hfu4?e z`}r5dLec6C_5^bEqBS(rJHrzw)l#*5uYX&>ZmV*+YF4bxEUT%i6z#=&_e`&4YoO3K z_dtp?bxvps3|X}lEpK>j*uQJ5D@%nxPRrH#iap6Ps;knK0d&Q_y`~46MTx# za1ed?9ADr|e1)&kk3;wd-{L!bk00+{@ zzHX1fz(>)Vvz#)zd74vBRxvcUEtQ7)0;g<*icUpS(W@9#f>eT4j4CFT5h`XCi;7hx zL?u)uOvR=Wt};?3Ld7n-3Y?L0*CIm#*X7toOM9dwQ7WTUqE%v4VpZZ);#Cq<94d(_ zNwUk*o-7ahELL7iXO0n}E^`c5Y>3&qX^uO~BJv~?o~hoZl}Dn|PaGnHquyxr%--t~ z+NzSO%8U~;LJnxwq0a5ujsYz?v268}0Zj;XRl6hI<1Hdz?dM)HykFXX4sg)_Z#aCm ry;<3g(Yl=VzM{oa##t83D(_y#F0MX%f18}2BC8vEQ{>LxR9W;l7S17R delta 1425 zcmYM!Yh2S+7{KxWfekj;fPsJr$Y4}pLSYFST~Lyus1cAB>%uLml%TZiibGT?5H>DR zQH|2>DbQA%QH_eIRVvX{yHQ$DT3OMBBItKs_2T<{%<*;pyR|N7 z;E+W)4b~z}N3T!S=ViA2C>f zSi~V73y}aL5|IQGl5qk~#7Rg&Di+~nEJhmAaSBdF2A1G7oQ|c)L>87|InF>f&csZjkpOLun{-o7Hq<;xDB`C4%~^mP>;>9q5)gb zh^^R$?P$W?xCi&587R?cmXfM4G;F>B@E(aynv#jhcoQRd3va`RcknLW!#?cC0gU2(jNt=(h>!3wKEbCrh(q`cpW_RBiLWq@ukj5I z;|RXRcbLE=zQ+$ZievZ@KjCK_$1nI5zhMf$;}86azc7uz@egM3FJ|2}j=B25o(zkK z>B+H(AQ^Q}UnwzLMB4vjGh-WM{AB!PR5EIr0GU7;jf_?%NG4cDC!?1MkqMOvlQGDI z%S6b`lZg~wvn5J+O4JE_gqdx+{wP7BW#-Go$SjbFm5Gyymsu#2AY+tC6kc6_l9+OM XMVU#=)q2BtL|E&nN$eR-7G?hdNc`N{ diff --git a/metrics/integration/sprites/icon-offset.json b/metrics/integration/sprites/icon-offset.json new file mode 100644 index 00000000000..e8e15268e18 --- /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 0000000000000000000000000000000000000000..b112096c180eecca2d6afde217a9fe54eae6f327 GIT binary patch literal 1010 zcmVm{G8B)KoXJFa>pBy66(wY{N1{V$IeF+19SHcT z6u!wx>Kh-Ywd`huNn7=Ohk*=HT|M7$glc?V+76YwcTrt+HGNN~8&5eL(u>;+Am2oF`sBU=Mo2*bi}Ud?l#qhEy>oiS&DPrAXu9LANYbpjS$iC z=2g_qjQ8{N)H5?fi~IJ`oYP6~Mn>poE=RRmlXReI@Ly?%6|^ zBN6h~*Kc*13179f5wY$#>x=+L|K#LFq}&)Vy%DK>Tv(vf?d^FoH4N>kHsZ`C`lHvnlCvw70rk7d}-2OGCW*D&88mdA?;f;6Xy?E;tH z<$FW1S<9of9pD3BaOhnoX71%{sJB>@r2rrJf+J6;q4oXrG?_=J6krP<_!{Ssv?x)_ z&c2C>9TRG{otiJ1BLr^7mzJWRcaS=4U<)7fNg+d&_z1OrnEqBWb?9INTg``xMM$?R zE8i+Vvkyz9-ZMH%uz{^vmmjQfIP9pZsyfKaP(lz!gPF_;!Db7XZ=!)%j7Am~#-6*~ zw-mcwVjqzuttd(^Psn6W+>tEqtrKovcjt1Say1`+ObS+3SR9mZD$x`##@|9n5*! zI5shs>|fmc@Qvnci0*J56TGa@y7niKS;nWPrZz4AzO)gNH1U>54<|%nqID{xj55k7 gql_~COZ*aG0OGQs<%kp{B>(^b07*qoM6N<$f?LhmRsaA1 literal 0 HcmV?d00001 diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index f833b70ace6..1b7362000be 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -218,6 +218,7 @@ class MLNStyleValueTransformer { // Color void getMBGLValue(MLNColor *rawValue, mbgl::Color &mbglValue) { mbglValue = rawValue.mgl_color; } + // TODO (Yingfang) need convert raw value to mbgl value // VariableAnchorOffsetCollection void getMBGLValue(NSString *rawValue, mbgl::VariableAnchorOffsetCollection &mbglValue) { mbgl::VariableAnchorOffsetCollection anchorOffset{}; @@ -301,9 +302,10 @@ class MLNStyleValueTransformer { return [MLNColor mgl_colorWithColor:mbglStopValue]; } + // TODO (Yingfang) need convert mbgl value to NSArray // VariableAnchorOffsetCollection static NSArray *toMLNRawStyleValue(const mbgl::VariableAnchorOffsetCollection mbglStopValue) { - NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.getSize()]; + NSMutableArray *array = [NSMutableArray arrayWithCapacity:0]; return array; } diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 604abcf7e63..b334a951cdf 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -364,11 +364,11 @@ std::optional SymbolLayout::getTextVariableAncho // If style specifies text-variable-anchor-offset, just return it std::array variableTextOffset; if (!textVariableAnchorOffset.isUndefined()) { - AnchorOffsetMap anchorOffsets; + std::vector anchorOffsets; auto variableAnchorOffset = layout->evaluate(zoom, feature, canonicalID); // Convert offsets from EM to PX, and apply baseline shift - for (const auto anchorOffset: variableAnchorOffset.getOffsets()) { + for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { variableTextOffset = {{anchorOffset.second[0] * util::ONE_EM, anchorOffset.second[1] * util::ONE_EM}}; switch (anchorOffset.first) { case SymbolAnchorType::TopRight: @@ -387,7 +387,8 @@ std::optional SymbolLayout::getTextVariableAncho break; } - anchorOffsets[anchorOffset.first] = std::array{ variableTextOffset[0], variableTextOffset[1] }; + AnchorOffsetPair convertedAnchorOffset = {anchorOffset.first, std::array{ variableTextOffset[0], variableTextOffset[1] }}; + anchorOffsets.emplace_back(convertedAnchorOffset); } return VariableAnchorOffsetCollection(anchorOffsets); @@ -404,10 +405,10 @@ std::optional SymbolLayout::getTextVariableAncho layout->evaluate(zoom, feature, canonicalID)[1] * util::ONE_EM}}; } - AnchorOffsetMap anchorOffsets; + std::vector anchorOffsets; for (auto anchor : variableTextAnchor) { auto offset = SymbolLayout::evaluateVariableOffset(anchor, variableTextOffset); - anchorOffsets[anchor] = std::array{ offset[0], offset[1] }; + anchorOffsets.emplace_back(AnchorOffsetPair{anchor, offset}); } return VariableAnchorOffsetCollection(anchorOffsets); @@ -416,6 +417,18 @@ std::optional SymbolLayout::getTextVariableAncho return std::nullopt; } +std::vector SymbolLayout::getTextVariableAnchors(const SymbolFeature& feature) { + std::vector textVariableAnchors; + auto textVariableAnchorOffset = getTextVariableAnchorOffset(feature); + if (textVariableAnchorOffset) { + for (const auto &anchorOffset: textVariableAnchorOffset->getOffsets()) { + textVariableAnchors.push_back(anchorOffset.first); + } + } + + return textVariableAnchors; +} + void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, @@ -466,8 +479,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, return result; }; - const std::vector variableTextAnchor = layout->evaluate( - zoom, feature, canonicalID); + const std::vector variableTextAnchor = getTextVariableAnchors(feature); const SymbolAnchorType textAnchor = layout->evaluate(zoom, feature, canonicalID); if (variableTextAnchor.empty()) { // Layers with variable anchors use the `text-radial-offset` diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 4aa950d27c1..f99fea3b4df 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -115,6 +115,8 @@ class SymbolLayout final : public Layout { // Helper to support both text-variable-anchor and text-variable-anchor-offset. Offset values converted from EMs to PXs std::optional getTextVariableAnchorOffset(const SymbolFeature&); + + std::vector getTextVariableAnchors(const SymbolFeature&); // Stores the layer so that we can hold on to GeometryTileFeature instances // in SymbolFeature, which may reference data from this object. diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 7fc7e4085a3..29346d5bc96 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -124,7 +124,7 @@ std::optional Converter collection; for (size_t index = 0; index < arraySize; index += 2) { Convertible offsetValue = arrayMember(value, index + 1); std::optional anchor = Converter{}(arrayMember(value, index), error); @@ -151,7 +151,9 @@ std::optional Converter{ xOffset.value(), yOffset.value() }; + auto anchorType = anchor.value(); + auto offset = std::array{ xOffset.value(), yOffset.value() }; + collection.emplace_back(AnchorOffsetPair{anchorType, offset}); } return VariableAnchorOffsetCollection(collection); diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 03da73ed38e..6c8d2be18fa 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -92,7 +92,7 @@ class PlacementContext { auto textVariableAnchorOffset = getLayout().get(); auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); if (!variableAnchorOffset.empty()) { - for (const auto anchorOffset: variableAnchorOffset.getOffsets()) { + for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { textVariableAnchors.push_back(anchorOffset.first); } } @@ -421,7 +421,7 @@ JointPlacement Placement::placeSymbol(const SymbolInstance& symbolInstance, cons // NOLINTNEXTLINE(clang-analyzer-core.DivideZero) auto anchor = variableTextAnchors[i % anchorsSize]; auto textVariableAnchorOffset = symbolInstance.textVariableAnchorOffset->getOffsets(); - auto variableTextOffset = textVariableAnchorOffset[anchor]; + auto variableTextOffset = symbolInstance.textVariableAnchorOffset->getOffsetByAnchor(anchor); const bool allowOverlap = (i >= anchorsSize); shift = calculateVariableLayoutOffset(anchor, width, @@ -976,10 +976,13 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices().clear(); const JointOpacityState duplicateOpacityState(false, false, true); - + + auto textVariableAnchorOffset = bucket.layout->get(); + auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); + const bool textAllowOverlap = bucket.layout->get(); const bool iconAllowOverlap = bucket.layout->get(); - const bool variablePlacement = !bucket.layout->get().empty(); + const bool variablePlacement = !bucket.layout->get().empty() || !variableAnchorOffset.empty(); 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; @@ -1538,8 +1541,7 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se float width = textCollisionBox.x2 - textCollisionBox.x1; float height = textCollisionBox.y2 - textCollisionBox.y1; - auto textVariableAnchorOffset = symbol.textVariableAnchorOffset->getOffsets(); - auto variableTextOffset = textVariableAnchorOffset[*variableAnchor]; + auto variableTextOffset = symbol.textVariableAnchorOffset->getOffsetByAnchor(*variableAnchor); offset = calculateVariableLayoutOffset(*variableAnchor, width, @@ -1560,8 +1562,7 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se float width = iconCollisionBox.x2 - iconCollisionBox.x1; float height = iconCollisionBox.y2 - iconCollisionBox.y1; - auto textVariableAnchorOffset = symbol.textVariableAnchorOffset->getOffsets(); - auto variableTextOffset = textVariableAnchorOffset[*variableAnchor]; + auto variableTextOffset = symbol.textVariableAnchorOffset->getOffsetByAnchor(*variableAnchor); offset = calculateVariableLayoutOffset(*variableAnchor, width, diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/util/variable_anchor_offset_collection.cpp index 82ded0b72b2..8baeae4ed70 100644 --- a/src/mbgl/util/variable_anchor_offset_collection.cpp +++ b/src/mbgl/util/variable_anchor_offset_collection.cpp @@ -14,10 +14,20 @@ bool VariableAnchorOffsetCollection::empty() const { return anchorOffsets.size() == 0; }; -AnchorOffsetMap VariableAnchorOffsetCollection::getOffsets() const { +std::vector VariableAnchorOffsetCollection::getOffsets() const { return anchorOffsets; } +std::array VariableAnchorOffsetCollection::getOffsetByAnchor(const SymbolAnchorType& anchorType) const { + for (const auto& pair: anchorOffsets) { + if (anchorType == pair.first) { + return pair.second; + } + } + + return {0, 0}; +} + std::string VariableAnchorOffsetCollection::toString() const { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp index 66e0eea33af..a1f77773a71 100644 --- a/test/style/conversion/stringify.test.cpp +++ b/test/style/conversion/stringify.test.cpp @@ -60,8 +60,8 @@ TEST(Stringify, Color) { TEST(Stringify, VariableAnchorOffsetCollection) { std::array offset = { 1, 1 }; - std::map> test; - test[SymbolAnchorType::Left] = offset; + std::vector test; + test.emplace_back(AnchorOffsetPair{SymbolAnchorType::Left, offset}); ASSERT_EQ(stringify(VariableAnchorOffsetCollection(test)), "[\"left\",[1.0,1.0]]"); } diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index c83ed4abb5f..6674ba897a7 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -16,7 +16,7 @@ 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}}; - AnchorOffsetMap anchorOffsets = {{ style::SymbolAnchorType::Left, variableTextOffset }}; + std::vector anchorOffsets = {{ style::SymbolAnchorType::Left, variableTextOffset }}; VariableAnchorOffsetCollection variableAnchorOffsetCollection(anchorOffsets); style::SymbolPlacementType placementType = style::SymbolPlacementType::Point; From ae701a23840f6ab818c48049da14dfa82875ea0f Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Thu, 19 Sep 2024 10:29:31 +0800 Subject: [PATCH 06/35] add test case --- .../all-anchors-icon-text-fit/expected.png | Bin 0 -> 37537 bytes .../all-anchors-icon-text-fit/style.json | 66 ++++++++++ .../expected.png | Bin 0 -> 29514 bytes .../all-anchors-text-allow-overlap/style.json | 65 ++++++++++ .../all-anchors/expected.png | Bin 0 -> 1989 bytes .../all-anchors/style.json | 122 ++++++++++++++++++ .../icon-image-all-anchors/expected.png | Bin 0 -> 3521 bytes .../icon-image-all-anchors/style.json | 73 +++++++++++ .../icon-image-offset/expected.png | Bin 0 -> 3953 bytes .../icon-image-offset/style.json | 103 +++++++++++++++ .../icon-image/expected.png | Bin 0 -> 3498 bytes .../icon-image/style.json | 67 ++++++++++ .../icon-text-fit-collision-box/expected.png | Bin 0 -> 4022 bytes .../icon-text-fit-collision-box/style.json | 71 ++++++++++ .../no-animate-zoom/expected.png | Bin 0 -> 4476 bytes .../no-animate-zoom/style.json | 89 +++++++++++++ .../pitched-offset/expected.png | Bin 0 -> 59025 bytes .../pitched-offset/style.json | 68 ++++++++++ .../pitched-with-map/expected.png | Bin 0 -> 46657 bytes .../pitched-with-map/style.json | 69 ++++++++++ .../pitched/expected.png | Bin 0 -> 40874 bytes .../pitched/style.json | 65 ++++++++++ .../rotated-offset/expected.png | Bin 0 -> 54011 bytes .../rotated-offset/style.json | 64 +++++++++ .../rotated-with-map/expected.png | Bin 0 -> 53088 bytes .../rotated-with-map/style.json | 66 ++++++++++ .../rotated/expected.png | Bin 0 -> 46302 bytes .../rotated/style.json | 64 +++++++++ .../single-justification/expected.png | Bin 0 -> 38140 bytes .../single-justification/style.json | 63 +++++++++ .../single-line/expected.png | Bin 0 -> 22185 bytes .../single-line/style.json | 64 +++++++++ .../text-allow-overlap/expected.png | Bin 0 -> 1093 bytes .../text-allow-overlap/style.json | 82 ++++++++++++ .../top-bottom-left-right/expected.png | Bin 0 -> 33243 bytes .../top-bottom-left-right/style.json | 74 +++++++++++ 36 files changed, 1335 insertions(+) create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/all-anchors/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-image-all-anchors/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-image-offset/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-image/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-image/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/no-animate-zoom/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/pitched-offset/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/pitched-with-map/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/pitched/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/pitched/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/rotated-offset/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/rotated-with-map/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/rotated/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/rotated/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/single-justification/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/single-justification/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/single-line/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/single-line/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/text-allow-overlap/style.json create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/top-bottom-left-right/style.json 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 0000000000000000000000000000000000000000..38a36fcec4a4e0b7b41b4fea3ed6300dabe5707b GIT binary patch literal 37537 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 OmG!-}&*BTOp7eidzM#th literal 0 HcmV?d00001 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 00000000000..f56251a1407 --- /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 0000000000000000000000000000000000000000..02b933be225f4f0e23efde5213b28461522f7668 GIT binary patch literal 29514 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 literal 0 HcmV?d00001 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 00000000000..ee7b23c34eb --- /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 0000000000000000000000000000000000000000..ed2122a69d281290a5e6062c4f6c4f4853c4e94f GIT binary patch literal 1989 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 Q@z;#O+}PTv$-pz=AJglxod5s; literal 0 HcmV?d00001 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 00000000000..a3b03852b1e --- /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 0000000000000000000000000000000000000000..32caa9ba80d7079c5cf0d035cf2d55cdeda3ffec GIT binary patch literal 3953 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 literal 0 HcmV?d00001 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 00000000000..3f78695bf41 --- /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 0000000000000000000000000000000000000000..aca4083401a61d8eda07b08abd52e58abf50616b GIT binary patch literal 4022 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 F_CJ=w)YAX} literal 0 HcmV?d00001 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 00000000000..0e87f114b03 --- /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 0000000000000000000000000000000000000000..ba66232da36605b79dfe22172125bfa3f41fed7b GIT binary patch literal 4476 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 TX4t~}a)l3Lx9`B|Eqbnein!%si`)Y){V zk@ZhMwcsCr{;6FX{$Kimhs%EYseHbvk)e&(&u>%PuCZx-^Fr~L7n3#*nI32wecDiI zT6<$frOG*qtqu+xds*$5qb&@7o_=tk#fWPA4S#acIlaUC7uPaBR_0XK)<&-X@M6uYM_YIAZdb73^V_=@7iZL!hpnor ztu6H#Heo{On8mlX*1uoargI-7zw|vlYyW$5KIq7iJ5|MLckkR;bmzc;g(+K(Z~ppu zjOWXl`}-#yb^`Sd`RLDR8Ozy7VY{E^y_*+>3RH?6C$uh!VP zbEod|M}IUlY}&6fVOvN@Pd9IGZ~dl*+Lz_!mw3X6h=`{b7q|WP->1bd?;MmTyuGh) z&e?gR&zK+gS2taF)$8E@emNT$7M8iAeYd)r%+d89b1d3->5`F=(Kf;UL1Ai$;}+Af zaliK(yFxjBS=O0b7o5_bUUuy^D_C=YuC8+8>WYVB*1WQOvH8od?+cRC-sZ=9*O!I# z)?Kc+_Vp9PK=p!$CnnEYxKQQ!-)k4&4IJDMSW@DAbnI`p;}#^&G&LQdruI|f;*9;- z7o4VV`1mT74|mVZ%34-clzQaBQrmO$4I^jlW6iHt-|l;PRiWytRjbU_e0Xtuy03yq zRgvM%v@|OX<&^y$(tQp;SUNq}MOEL6g*oI^c6c5uA2};z)Q%lHE^Mmzl;;Z`_3OR8 zy>(s{B8J zPpj0sw_jL5K$mT5i?l=Ab?Wre)J;q79UjrDb?dH5O4H2DI&A*$ zWBBY)?M+|bCBA)nal1mliH}Yhwk)`M^{Qg4pAVbuOi3}=x^=65XJTj8(xpS@Mw=VQ z*_IB;)NZr==d-!@&Yr(+W^dnT(z>@r@mW(Mw|x6=Z=bRLJx1DBncTT^=TuD0ZV3do z!g}DONnwBd@zcGK(OE3J-GxOzpHFF=sI&C`DaVv8o%)XJ6m)mTv~Vx|;mS?FxMT*W zFV}sX8EG@TyW6@e{YH--ea?17q)EV#(W3+UOG_0NJ;;g%Yz z0fa~{>p83J-eJ3h72R2n!NZ69e?K-i|M*n1j_kX|a8M)vu_uBF~4qNJFn?@QK^k*{(@#q|@E9-t=k@x35j=HI- z=`jPJ6D%1Eur$6pY2cti?K^ZR;Ztm4EPr-%bSzjns;7B$xADNG|)YH;nR2PlslxKkDgW?ZFM%+Yr_WXqeS}Z^83XP#uqNBd3pEMrws)JxCsxO znE{wb#+>+%V+l)xAKnTPW!ks zOCKCnnX>6fLBT@%M7KG9ZM�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 BCg}hG literal 0 HcmV?d00001 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 00000000000..81693922776 --- /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 0000000000000000000000000000000000000000..0f9eb6b592d4d7a2174c8b529768556a1f0ce34f GIT binary patch literal 46657 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 literal 0 HcmV?d00001 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 00000000000..3fe64bd749a --- /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 0000000000000000000000000000000000000000..4750b301d9d4b05b2139cc2e7d2ceac1a7f34d39 GIT binary patch literal 40874 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%0Ag9au%e%rcr>!Sb8Eq(HC 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
    AoCSo^C$ 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 literal 0 HcmV?d00001 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 00000000000..86f84359ba9 --- /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 0000000000000000000000000000000000000000..28c2d72b64799395d86a41fd4328d6a0dceec8d0 GIT binary patch literal 38140 zcmdSCcU;f=|NnoSV`R%nLKz`MBnsIog;XkKga%m+8D(XZQ4*Ocs}O}$heD*Ggd`!E zO?xzqkosNkIiKI}uixeO`|Er8e&3hN`{EoYuh(-t9{2lg-5<7@nHn{3qSEBAzy4}& zJYl@WUw{40Ki2z8p&`HA*m-yUUw`dMH6B04(zD)&HTvH_J?}nzct>4b-FJ`9`bS0ebm&9|6 z^3ExC?mXGqSz}9!&STG7Po0;2ctkU`k)iXm4=c85vnf2h`+@}vN=i#(7C!7_ea0sF z(b*ZNZR2{bx_UTne)iI@@2sv>6*Vm?F3!KQQtQyL`u9-!c1~ZdsnT@Ex}N z-JBsI#*-)a=-03LAyXrNrGCy&{_U+2usI`8&Exy0Sr!%+ZYx*LPur^4Ohre*ckG5E zN7OD}yy)oUv}@O{4g2@EKRYAdaGz6szCkIoT1#PLnc<#&`|Nd8Vq#;*2C3UwPM_|V zJZE%xP8Z|WT7#6E9hlVf!NS2CyC}GZwC2w!?=|r?IZ^celw}{wKJ7})`|MTN*rnRm zkk!%&Z0-ncze1A+qzheX3?nk=;8kUQ9n)9QR}w*9y-){`dKCa^ni|oJj>?T<*_Vm zlh%z`^ymyP#%{&0Z%ZDXvE7uvIK8O6IKzhb9d2=Yr&BO**KU9Q;#a$;jO?nTvuEA! zpXGf_L-jUfI)>>_Kf7=Gg@xr8OG``3Z)+u)sqW77xpHNAa&mID){{i9K}o;Abu1mI z640!ZUaQrsSHHN}W8%J@yLXTCnmKFM+x)m*DYdFSHk#ENI&^4xYRge`1}JN2Xv`^0 z@jYV`v$6Nold>!|mksNz)u&INu;a(;ckI}arRZc}V6bP;o};;M%{1EDC=53o9GrAkMR?>BS;rR94!)6_{>u*Y4Z*jUL@aD~%1>9W8 z-9y7|Sc2v=XKrVU_1W9R|M6p+b=BoYcGDIv?9x-JYVy&$drj%7r*|N4dBOF1GiT0JXxg+myP`6CRGiE6VVX-lJTfyg$DFk;E-KpS zJNDR7kJon}KYdy`EH*AKc;wn)S66@U*`>?+{iP)(J9q9Jy>zLz(v%}3Z_F7m$JI5^ zG$J+3?&_*9Z*u-I4)W~WYs%r0h$HLl)3&w3NR`h8SxwQ1w9&?Sh8hcGbLqips zH7hX)R2%i`*XN|yY1`UxTZ(Plj*qsx`sUuTf0Wv5**Rtg^#~oYdS7CqzW#_2+ji`j zS8#p9og<@;JioHC_|+>zN>z;Vh*dhD6DwOdwQbU1!-fqu2?+^DE&K3LEu-x^uUxs( zZrO*&1NUj#rrhvvZ+_bHL8O&`;K-j_ckXPZ*}8S>s<#nG61*yVnw)5@rl$7f!Xl&5 zqyLJVm(^{=h(k-BUUaXna)0*xdGLtULrhIgt9x+9>wZf559DOGV_KEFI-dT7{O_rjD0n_H@x{{HzjSl>&#iSOUxIa{ee zTH4CZG}<ORpp%%tL8V*B31}ZnB^2nA=pEKa7#c9u+`zIz|T3XtqLx&DL z!Y+wxP3n))nC9ZrUu|7gSEC)Bj(JtS(pmg?=f|h?}7ufOWc*8BG@Vq;^=zI{ti$;{j~&Hdej-Xp6D{^6=S4_j97qw=-7y1HBG zt#(6Pp508{(z1h|TNfTOuWJ|Y`|jZpw<}*~vu*WPf7`D8;>8Pju@4vi=>GHj=RjXd z0hNQ@GBs}As&=T3Fqt>6XV

    |6P>VV*dR3n#~&i)2KzKf)Dv|j`Qai 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 VU(D(|`5*jK+N1X+wcUn|{~w@3G=KmA literal 0 HcmV?d00001 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 00000000000..35b3b163ecc --- /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 0000000000000000000000000000000000000000..9559860ee49165f46dbd6e2466e28f3009b2daca GIT binary patch literal 22185 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 TapngTe~DWM4fK$`64 literal 0 HcmV?d00001 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 00000000000..d636697bd48 --- /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 0000000000000000000000000000000000000000..663fa5fb77563cd6128a05692a70a35d0edf9b3c GIT binary patch literal 33243 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 literal 0 HcmV?d00001 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 00000000000..d310fab3684 --- /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 + } + } + ] +} From ccc68bd026a4ded29298b619279197968545b84e Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Mon, 23 Sep 2024 21:33:08 +0800 Subject: [PATCH 07/35] build pass on Android --- CMakeLists.txt | 2 ++ include/mbgl/util/interpolate.hpp | 5 +++-- src/mbgl/layout/symbol_layout.cpp | 11 +++++------ src/mbgl/style/layers/symbol_layer.cpp | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f36cb26dce7..077a079142e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -423,6 +423,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/util/type_list.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/unitbezier.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/util.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/util/variable_anchor_offset_collection.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/variant.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/vectors.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/work_request.hpp @@ -984,6 +985,7 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/util/url.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/url.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/utf.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/util/variable_anchor_offset_collection.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/version.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/version.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/work_request.cpp diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index a8c4fa8bac7..5f20d062f1a 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -131,7 +132,7 @@ struct Interpolator { template <> struct Interpolator { public: - VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const float t) noexcept { + VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const float t) { auto aOffsets = a.getOffsets(); auto bOffsets = b.getOffsets(); if (aOffsets.size() != bOffsets.size()) @@ -140,7 +141,7 @@ struct Interpolator { } std::vector offsetMap; - for (auto index = 0; index < aOffsets.size(); index++) { + for (size_t index = 0; index < aOffsets.size(); index++) { auto aPair = std::next(aOffsets.begin(), index); auto bPair = std::next(bOffsets.begin(), index); if (aPair->first != bPair->first) { diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index b334a951cdf..9b8bac22865 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -395,7 +395,6 @@ std::optional SymbolLayout::getTextVariableAncho } const std::vector variableTextAnchor = layout->evaluate(zoom, feature, canonicalID); - const SymbolAnchorType textAnchor = layout->evaluate(zoom, feature, canonicalID); if (!variableTextAnchor.empty()) { if (!textRadialOffset.isUndefined()) { variableTextOffset = { @@ -419,9 +418,9 @@ std::optional SymbolLayout::getTextVariableAncho std::vector SymbolLayout::getTextVariableAnchors(const SymbolFeature& feature) { std::vector textVariableAnchors; - auto textVariableAnchorOffset = getTextVariableAnchorOffset(feature); - if (textVariableAnchorOffset) { - for (const auto &anchorOffset: textVariableAnchorOffset->getOffsets()) { + auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); + if (variableAnchorOffsets) { + for (const auto &anchorOffset: variableAnchorOffsets->getOffsets()) { textVariableAnchors.push_back(anchorOffset.first); } } @@ -640,7 +639,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); - auto textVariableAnchorOffset = getTextVariableAnchorOffset(feature); + auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); const SymbolPlacementType textPlacement = layout->get() != AlignmentType::Map ? SymbolPlacementType::Point @@ -698,7 +697,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, overscaling, iconRotation, textRotation, - textVariableAnchorOffset, + variableAnchorOffsets, allowVerticalPlacement, iconType); diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 4ace2f0ac18..6c9f5602054 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1806,12 +1806,12 @@ std::optional SymbolLayer::setPropertyInternal(const std::string& name, c if (property == Property::TextVariableAnchorOffset) { Error error; const auto& typedValue = - convert(value, error, false, false); + convert>(value, error, false, false); if (!typedValue) { return error; } - setTextVariableAnchor(*typedValue); + setTextVariableAnchorOffset(*typedValue); return std::nullopt; } if (property == Property::TextWritingMode) { From 38732fe4adcf5c62bd7df6e35152d1e1dde9aba3 Mon Sep 17 00:00:00 2001 From: Alexey Kon <48697757+random3940@users.noreply.github.com> Date: Tue, 24 Sep 2024 19:02:51 -0700 Subject: [PATCH 08/35] WIP: coersion when using data binding --- .../databind/expected.png | Bin 0 -> 5867 bytes .../databind/style.json | 57 ++++++++++++ src/mbgl/layout/symbol_layout.cpp | 57 +++++++----- src/mbgl/style/conversion/function.cpp | 4 +- src/mbgl/style/expression/coercion.cpp | 66 ++++++++++++-- src/mbgl/style/expression/parsing_context.cpp | 2 +- src/mbgl/text/placement.cpp | 82 +++++++++++------- .../variable_anchor_offset_collection.cpp | 10 ++- test/CMakeLists.txt | 1 + ...variable_anchor_offset_collection.test.cpp | 54 ++++++++++++ 10 files changed, 264 insertions(+), 69 deletions(-) create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/databind/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/databind/style.json create mode 100644 test/style/conversion/variable_anchor_offset_collection.test.cpp diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/databind/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/databind/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..a58f55f5c68530b844f0c7170677130b51dd6eb7 GIT binary patch literal 5867 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 BbQb^s literal 0 HcmV?d00001 diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/databind/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/databind/style.json new file mode 100644 index 00000000000..fc4ee7893fd --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/databind/style.json @@ -0,0 +1,57 @@ +{ + "version": 8, + "metadata": { + "test": { + "collisionDebug": true, + "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/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 9b8bac22865..2b13b677074 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -359,8 +359,9 @@ std::array SymbolLayout::evaluateVariableOffset(style::SymbolAnchorTyp return result; } -std::optional SymbolLayout::getTextVariableAnchorOffset(const SymbolFeature& feature) -{ +std::optional SymbolLayout::getTextVariableAnchorOffset(const SymbolFeature& feature) { + std::optional result; + // If style specifies text-variable-anchor-offset, just return it std::array variableTextOffset; if (!textVariableAnchorOffset.isUndefined()) { @@ -390,32 +391,40 @@ std::optional SymbolLayout::getTextVariableAncho AnchorOffsetPair convertedAnchorOffset = {anchorOffset.first, std::array{ variableTextOffset[0], variableTextOffset[1] }}; anchorOffsets.emplace_back(convertedAnchorOffset); } - - return VariableAnchorOffsetCollection(anchorOffsets); - } - - const std::vector variableTextAnchor = layout->evaluate(zoom, feature, canonicalID); - if (!variableTextAnchor.empty()) { - 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 anchorOffsets; - for (auto anchor : variableTextAnchor) { - auto offset = SymbolLayout::evaluateVariableOffset(anchor, variableTextOffset); - anchorOffsets.emplace_back(AnchorOffsetPair{anchor, offset}); + + result = VariableAnchorOffsetCollection(anchorOffsets); + } else { + const std::vector variableTextAnchor = layout->evaluate( + zoom, feature, canonicalID); + // BUGBUG unused + // const SymbolAnchorType textAnchor = layout->evaluate(zoom, feature, canonicalID); + if (!variableTextAnchor.empty()) { + 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 anchorOffsets; + for (auto anchor : variableTextAnchor) { + auto offset = SymbolLayout::evaluateVariableOffset(anchor, variableTextOffset); + anchorOffsets.emplace_back(AnchorOffsetPair{anchor, offset}); + } + + result = VariableAnchorOffsetCollection(anchorOffsets); } - - return VariableAnchorOffsetCollection(anchorOffsets); } - - return std::nullopt; + + if (result.has_value() && result->empty()) { + result.reset(); + } + + return result; } +// BUGBUG why this method is necessary? std::vector SymbolLayout::getTextVariableAnchors(const SymbolFeature& feature) { std::vector textVariableAnchors; auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index e782cd68f7e..f6f9d8e3c55 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -131,7 +131,8 @@ template std::optional> convertFunctionToExpres Error&, bool); template std::optional> convertFunctionToExpression(const Convertible&, Error&, bool); -template std::optional> convertFunctionToExpression(const Convertible&, Error&, bool); +template std::optional> +convertFunctionToExpression(const Convertible&, Error&, bool); template std::optional> convertFunctionToExpression(const Convertible&, Error&, bool); @@ -210,6 +211,7 @@ enum class FunctionType { bool interpolatable(type::Type type) noexcept { return type.match([&](const type::NumberType&) { return true; }, [&](const type::ColorType&) { return true; }, + [&](const type::VariableAnchorOffsetCollectionType&) { return true; }, [&](const type::Array& array) { return array.N && array.itemType == type::Number; }, [&](const auto&) { return false; }); } diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index c0ce181a6ba..0c913275003 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -72,15 +72,62 @@ EvaluationResult toColor(const Value& colorValue) { }); } -// TODO (Yingfang) need evaluate the expression value to mbgl value +//// TODO (Yingfang) need evaluate the expression value to mbgl value EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { return value.match( [&](const VariableAnchorOffsetCollection& anchorOffset) -> EvaluationResult { return anchorOffset; }, + [&](const std::vector& components) -> EvaluationResult { + // BUGBUG move out? Shorten / edit. + if (components.size() % 2 != 0) { + return EvaluationError{"Invalid variableAnchorOffsetCollection 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()) { + return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + + ": expected a string value as the first element of each pair."}; + } + + if (!offsetArray.is>()) { + return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + + ": expected an array value as the second element of each pair."}; + } + + if (offsetArray.get>().size() != 2) { + return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + + ": expected an array value with two elements as the second element of each " + "pair."}; + } + + const std::string& anchorTypeString = anchorTypeValue.get(); + const auto anchorType = Enum::toEnum(anchorTypeString); + if (!anchorType) { + return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + + ": unknown anchor type '" + anchorTypeString + "'"}; + } + + const auto& offsetComponents = offsetArray.get>(); + const float x = offsetComponents[0].template get(); + const float y = offsetComponents[1].template get(); + + anchorOffsets.emplace_back(*anchorType, std::array{{x, y}}); + } + + return VariableAnchorOffsetCollection{anchorOffsets}; + }, + [&](const std::string& anchorOffsetString) -> EvaluationResult { - return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + anchorOffsetString + "'"}; + return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + anchorOffsetString + + "'"}; }, [&](const auto&) -> EvaluationResult { - return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + stringify(value) + "'"}; + return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + stringify(value) + + "'"}; }); } @@ -151,6 +198,9 @@ std::string Coercion::getOperator() const { [](const type::ColorType&) -> std::string_view { return "to-color"; }, [](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-variableanchoroffsetcollection"; + }, [](const auto&) noexcept -> std::string_view { assert(false); return ""; @@ -160,10 +210,12 @@ std::string Coercion::getOperator() const { 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-number", type::Number}, - {"to-string", type::String}}; + static std::unordered_map types{ + {"to-boolean", type::Boolean}, + {"to-color", type::Color}, + {"to-number", type::Number}, + {"to-string", type::String}, + {"to-variableanchoroffsetcollection", type::VariableAnchorOffsetCollection}}; std::size_t length = arrayLength(value); diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 7b4189dd63e..6b16c843545 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -209,7 +209,7 @@ ParseResult ParsingContext::parse(const Convertible& value, parsed = {annotate( std::move(*parsed), std::move(*expected), typeAnnotationOption.value_or(TypeAnnotationOption::coerce))}; } else if (*expected == type::VariableAnchorOffsetCollection && - (actual == type::Value || expected->is())) { + (actual == type::Value || actual.is())) { parsed = {annotate( std::move(*parsed), std::move(*expected), typeAnnotationOption.value_or(TypeAnnotationOption::coerce))}; } else { diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 6c8d2be18fa..b323d652e69 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -65,12 +65,34 @@ const CollisionGroups::CollisionGroup& CollisionGroups::get(const std::string& s using namespace style; +// BUGBUG move functions somewhere? +bool hasVariableTextAnchors(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) { + if (layout.get().empty()) { + const auto tvao = layout.get(); + return !tvao.isConstant() || tvao.constant() != std::nullopt; + } + + return true; +} + +std::vector getAnchors( + const std::optional& variableAnchorOffset) { + std::vector result; + if (variableAnchorOffset) { + for (const auto& anchorOffset : variableAnchorOffset->getOffsets()) { + result.push_back(anchorOffset.first); + } + } + + return result; +} + // PlacementContext implemenation class PlacementContext { std::reference_wrapper bucket; std::reference_wrapper renderTile; std::reference_wrapper state; - std::vector textVariableAnchors; + // std::vector textVariableAnchors; public: PlacementContext(const SymbolBucket& bucket_, @@ -89,17 +111,17 @@ class PlacementContext { partiallyEvaluatedTextSize(bucket_.textSizeBinder->evaluateForZoom(placementZoom)), partiallyEvaluatedIconSize(bucket_.iconSizeBinder->evaluateForZoom(placementZoom)), avoidEdges(std::move(avoidEdges_)) { - auto textVariableAnchorOffset = getLayout().get(); - auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); - if (!variableAnchorOffset.empty()) { - for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { - textVariableAnchors.push_back(anchorOffset.first); - } - } - else { - textVariableAnchors = std::move(getLayout().get()); - } - } + // auto textVariableAnchorOffset = getLayout().get(); + // auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); + // if (!variableAnchorOffset.empty()) { + // for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { + // textVariableAnchors.push_back(anchorOffset.first); + // } + // } + // else { + // textVariableAnchors = std::move(getLayout().get()); + // } + } const SymbolBucket& getBucket() const { return bucket.get(); } const style::SymbolLayoutProperties::PossiblyEvaluated& getLayout() const { return *getBucket().layout; } @@ -109,9 +131,9 @@ class PlacementContext { const TransformState& getTransformState() const { return state; } - const std::vector& getVariableTextAnchors() const { - return textVariableAnchors; - } + // const std::vector& getVariableTextAnchors() const { + // return textVariableAnchors; + // } float pixelsToTileUnits; float scale; @@ -293,7 +315,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 = getAnchors(symbolInstance.textVariableAnchorOffset); textBoxes.clear(); iconBoxes.clear(); @@ -780,11 +802,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, using namespace style; const auto& layout = *bucket.layout; const bool alongLine = layout.get() != SymbolPlacementType::Point; - auto textVariableAnchorOffset = layout.get(); - auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); - - const bool hasVariableAnchors = (!layout.get().empty() || !variableAnchorOffset.empty()) - && bucket.hasTextData(); + const bool hasVariableAnchors = hasVariableTextAnchors(layout) && bucket.hasTextData(); const bool updateTextFitIcon = layout.get() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && (bucket.hasIconData() || bucket.hasSdfIconData()); @@ -976,13 +994,10 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices().clear(); const JointOpacityState duplicateOpacityState(false, false, true); - - auto textVariableAnchorOffset = bucket.layout->get(); - auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); - + const bool textAllowOverlap = bucket.layout->get(); const bool iconAllowOverlap = bucket.layout->get(); - const bool variablePlacement = !bucket.layout->get().empty() || !variableAnchorOffset.empty(); + const bool variablePlacement = hasVariableTextAnchors(*bucket.layout); 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; @@ -1475,7 +1490,10 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se collisionGroups.get(params.sourceId), getAvoidEdges(bucket, renderTile.matrix)}; - const auto& variableTextAnchors = ctx.getVariableTextAnchors(); + // BUGBUG not sure I understand the logic here + // const auto& variableTextAnchors = ctx.getVariableTextAnchors(); + const auto& variableTextAnchors = std::vector{}; + // 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. @@ -1540,9 +1558,9 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se if (variableAnchor) { float width = textCollisionBox.x2 - textCollisionBox.x1; float height = textCollisionBox.y2 - textCollisionBox.y1; - + auto variableTextOffset = symbol.textVariableAnchorOffset->getOffsetByAnchor(*variableAnchor); - + offset = calculateVariableLayoutOffset(*variableAnchor, width, height, @@ -1561,9 +1579,9 @@ 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 = symbol.textVariableAnchorOffset->getOffsetByAnchor(*variableAnchor); - + offset = calculateVariableLayoutOffset(*variableAnchor, width, height, @@ -1652,7 +1670,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() && !hasVariableTextAnchors(ctx.getLayout()); } // static diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/util/variable_anchor_offset_collection.cpp index 8baeae4ed70..66a3202f5e1 100644 --- a/src/mbgl/util/variable_anchor_offset_collection.cpp +++ b/src/mbgl/util/variable_anchor_offset_collection.cpp @@ -19,15 +19,17 @@ std::vector VariableAnchorOffsetCollection::getOffsets() const } std::array VariableAnchorOffsetCollection::getOffsetByAnchor(const SymbolAnchorType& anchorType) const { - for (const auto& pair: anchorOffsets) { + for (const auto& pair : anchorOffsets) { if (anchorType == pair.first) { return pair.second; } } - + return {0, 0}; } +// BUGBUG check why we need both toString() and serialize() + std::string VariableAnchorOffsetCollection::toString() const { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -49,10 +51,10 @@ mbgl::Value VariableAnchorOffsetCollection::serialize() const { std::vector serialized; for (const auto& pair : anchorOffsets) { serialized.emplace_back(Enum::toString(pair.first)); - std::vector offset { pair.second[0], pair.second[1] }; + std::vector offset{pair.second[0], pair.second[1]}; serialized.emplace_back(offset); } - + return serialized; } } // namespace mbgl diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2c0ba3f7241..8ed753f8faa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -51,6 +51,7 @@ add_library( ${PROJECT_SOURCE_DIR}/test/style/conversion/property_value.test.cpp ${PROJECT_SOURCE_DIR}/test/style/conversion/stringify.test.cpp ${PROJECT_SOURCE_DIR}/test/style/conversion/tileset.test.cpp + ${PROJECT_SOURCE_DIR}/test/style/conversion/variable_anchor_offset_collection.test.cpp ${PROJECT_SOURCE_DIR}/test/style/expression/dependency.test.cpp ${PROJECT_SOURCE_DIR}/test/style/expression/expression.test.cpp ${PROJECT_SOURCE_DIR}/test/style/expression/util.test.cpp diff --git a/test/style/conversion/variable_anchor_offset_collection.test.cpp b/test/style/conversion/variable_anchor_offset_collection.test.cpp new file mode 100644 index 00000000000..bbbcc80db12 --- /dev/null +++ b/test/style/conversion/variable_anchor_offset_collection.test.cpp @@ -0,0 +1,54 @@ +#include + +#include +#include +#include +#include + +// BUGBUG check headers +#include +#include +#include + +#include + +using namespace mbgl; +using namespace mbgl::style; +using namespace mbgl::style::conversion; + +// BUGBUG check if need both +using namespace style::expression; +using namespace style::expression::dsl; + +TEST(StyleConversion, VariableAnchorOffsetCollection) { + Error error; + auto fromFunction = [](const char* json) { + conversion::Error error; + auto function = conversion::convertJSON>( + json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); + return function->asExpression(); + }; + + // BUGBUG + // exponential + { + auto expr = fromFunction( + R"({"type": "exponential", "stops": [[1, ["left", [0, 0]]], [11, ["left", [10, 20]]]]})"); + auto val = expr.evaluate(5); + auto val1 = expr.evaluate(11); + EXPECT_EQ(VariableAnchorOffsetCollection({{{SymbolAnchorType::Left}, {{0, 0}}}}), expr.evaluate(0)); + EXPECT_EQ(VariableAnchorOffsetCollection({{{SymbolAnchorType::Left}, {{4, 8}}}}), val); // BUGBUG check value + EXPECT_EQ(VariableAnchorOffsetCollection({{{SymbolAnchorType::Left}, {{10, 20}}}}), val1); + } + + // // BUGBUG + // { + // auto json = + // R"(["interpolate", ["linear"], ["zoom"], 0, ["literal", ["left", [0, 0]]], 1, ["literal",["left", + // [10, 20]]]])"; + // PropertyExpression expr(createExpression(json)); + // + // auto result = expr.evaluate(0.5f); + // EXPECT_EQ(VariableAnchorOffsetCollection(), result); + // } +} From ebf2f585275af51056ae3fbd0e76b134465e5643 Mon Sep 17 00:00:00 2001 From: Alexey Kon <48697757+random3940@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:45:46 -0700 Subject: [PATCH 09/35] WIP: NSExpressions --- .../variable_anchor_offset_collection.hpp | 22 ++++----- .../darwin/scripts/generate-style-code.js | 9 ++-- platform/darwin/src/MLNStyleValue_Private.h | 45 ++++++++++++++++--- src/mbgl/style/expression/coercion.cpp | 7 +-- src/mbgl/text/placement.cpp | 6 ++- 5 files changed, 62 insertions(+), 27 deletions(-) diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index f34a4dd51e7..0860f8b7ef0 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -12,24 +12,22 @@ namespace mbgl { using AnchorOffsetPair = std::pair>; +// BUGBUG consider changing data types here. Current impl using extra +// heap allocs due to vector class VariableAnchorOffsetCollection { - public: VariableAnchorOffsetCollection() = default; // Copy constructor - VariableAnchorOffsetCollection(const VariableAnchorOffsetCollection& other) { - anchorOffsets = other.anchorOffsets; - } + VariableAnchorOffsetCollection(const VariableAnchorOffsetCollection& other) { anchorOffsets = other.anchorOffsets; } // Move constructor VariableAnchorOffsetCollection(VariableAnchorOffsetCollection&& other) noexcept { anchorOffsets = std::move(other.anchorOffsets); } - - VariableAnchorOffsetCollection(const std::vector& values) { - anchorOffsets = std::move(values); - } + + // BUGBUG add overload to take advantage of std::move. + VariableAnchorOffsetCollection(const std::vector& values) { anchorOffsets = values; } std::string toString() const; mbgl::Value serialize() const; @@ -42,7 +40,7 @@ class VariableAnchorOffsetCollection { if (this != &other) { anchorOffsets = other.anchorOffsets; } - + return *this; } @@ -51,13 +49,11 @@ class VariableAnchorOffsetCollection { if (this != &other) { anchorOffsets = std::move(other.anchorOffsets); } - + return *this; } - bool operator==(const VariableAnchorOffsetCollection& other) const { - return anchorOffsets == other.anchorOffsets; - } + bool operator==(const VariableAnchorOffsetCollection& other) const { return anchorOffsets == other.anchorOffsets; } private: std::vector anchorOffsets; diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index 94eb5614b1e..c3095875d25 100644 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -499,7 +499,6 @@ global.describeType = function (property) { case 'formatted': case 'string': case 'resolvedImage': - case 'variableAnchorOffsetCollection': return 'string'; case 'enum': return '`MLN' + camelize(property.name) + '`'; @@ -522,6 +521,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}`); } @@ -549,7 +550,6 @@ global.describeValue = function (value, property, layerType) { case 'formatted': case 'string': case 'resolvedImage': - case 'variableAnchorOffsetCollection': if (value === '') { return 'the empty string'; } @@ -603,6 +603,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}`); } @@ -637,7 +639,6 @@ global.propertyType = function (property) { case 'formatted': case 'string': case 'resolvedImage': - case 'variableAnchorOffsetCollection': return 'NSString *'; case 'enum': return 'NSValue *'; @@ -660,6 +661,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}`); } diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index 1b7362000be..f5c062de2ad 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -220,9 +220,35 @@ class MLNStyleValueTransformer { // TODO (Yingfang) need convert raw value to mbgl value // VariableAnchorOffsetCollection - void getMBGLValue(NSString *rawValue, mbgl::VariableAnchorOffsetCollection &mbglValue) { - mbgl::VariableAnchorOffsetCollection anchorOffset{}; - mbglValue = anchorOffset; + void getMBGLValue(id rawValue, mbgl::VariableAnchorOffsetCollection &mbglValue) { + // BUGBUG + // mbgl::style::SymbolAnchorType x {0}; + // getMBGLValue(rawValue, x); + + if ([rawValue isKindOfClass:[NSArray class]]) { + NSArray *array = (NSArray *)rawValue; + if (array.count % 2 != 0) { + [NSException raise:NSInvalidArgumentException + format:@"VariableTextAnchorOffset array should have even number of elements."]; + } + + std::vector anchorOffsets; + for (NSUInteger i = 0; i < array.count; i += 2) { + if (![array[i] isKindOfClass:[NSString class]]) { + [NSException raise:NSInvalidArgumentException + format:@"VariableTextAnchorOffset array should specify valid anchor values."]; + } + + auto anchor = + *mbgl::Enum::toEnum([(NSString *)array[i] UTF8String]); + std::array offsetArray; + getMBGLValue(array[i + 1], offsetArray); + + anchorOffsets.emplace_back(anchor, offsetArray); + } + + mbglValue = mbgl::VariableAnchorOffsetCollection(std::move(anchorOffsets)); + } } // Image @@ -304,11 +330,20 @@ class MLNStyleValueTransformer { // TODO (Yingfang) need convert mbgl value to NSArray // VariableAnchorOffsetCollection - static NSArray *toMLNRawStyleValue(const mbgl::VariableAnchorOffsetCollection mbglStopValue) { + static NSArray *toMLNRawStyleValue( + const mbgl::VariableAnchorOffsetCollection mbglStopValue) { NSMutableArray *array = [NSMutableArray arrayWithCapacity:0]; + for (const auto &anchorOffset : mbglStopValue.getOffsets()) { + NSString *anchor = toMLNRawStyleValue(anchorOffset.first); + NSValue *offset = [NSValue mgl_valueWithOffsetArray:anchorOffset.second]; + + // BUGBUG inline + [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/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index 0c913275003..ec07d484b8b 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -76,6 +76,8 @@ EvaluationResult toColor(const Value& colorValue) { EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { return value.match( [&](const VariableAnchorOffsetCollection& anchorOffset) -> EvaluationResult { return anchorOffset; }, + // BUGBUG handle Value? It is also annotated w/ coerse in ParsingContext::parse(). See how other cases handle + // it. [&](const std::vector& components) -> EvaluationResult { // BUGBUG move out? Shorten / edit. if (components.size() % 2 != 0) { @@ -120,11 +122,6 @@ EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { return VariableAnchorOffsetCollection{anchorOffsets}; }, - - [&](const std::string& anchorOffsetString) -> EvaluationResult { - return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + anchorOffsetString + - "'"}; - }, [&](const auto&) -> EvaluationResult { return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + stringify(value) + "'"}; diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index b323d652e69..5a7fd65165b 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -69,7 +69,11 @@ using namespace style; bool hasVariableTextAnchors(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) { if (layout.get().empty()) { const auto tvao = layout.get(); - return !tvao.isConstant() || tvao.constant() != std::nullopt; + if (!tvao.isConstant()) { + return true; + } + const auto constValue = tvao.constant(); + return constValue && !constValue->empty(); } return true; From 108002baca353fba1561a8fba869108fd914e2c9 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Sat, 28 Sep 2024 00:42:41 +0800 Subject: [PATCH 10/35] update code to pass render test --- src/mbgl/layout/symbol_instance.cpp | 11 +++ src/mbgl/layout/symbol_instance.hpp | 2 + src/mbgl/layout/symbol_layout.cpp | 81 ++++++++----------- src/mbgl/layout/symbol_layout.hpp | 2 - src/mbgl/renderer/buckets/symbol_bucket.cpp | 21 +++++ src/mbgl/renderer/buckets/symbol_bucket.hpp | 1 + src/mbgl/text/placement.cpp | 61 +++----------- .../variable_anchor_offset_collection.cpp | 3 +- 8 files changed, 77 insertions(+), 105 deletions(-) diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index 5ab92097d79..c27c906cab4 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -204,6 +204,17 @@ bool SymbolInstance::hasSdfIcon() const { return static_cast(symbolContent & SymbolContent::IconSDF); } +std::vector SymbolInstance::getTextAnchors() const { + std::vector result; + if (textVariableAnchorOffset) { + for (const auto& anchorOffset : textVariableAnchorOffset->getOffsets()) { + result.push_back(anchorOffset.first); + } + } + + 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 05d8848c433..f23d734211b 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -90,6 +90,8 @@ class SymbolInstance { const std::optional& verticalIconQuads() const; void releaseSharedData(); + std::vector getTextAnchors() const; + private: std::shared_ptr sharedData; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 2b13b677074..f54224b48bb 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -363,42 +363,41 @@ std::optional SymbolLayout::getTextVariableAncho std::optional result; // If style specifies text-variable-anchor-offset, just return it - std::array variableTextOffset; if (!textVariableAnchorOffset.isUndefined()) { std::vector anchorOffsets; auto variableAnchorOffset = layout->evaluate(zoom, feature, canonicalID); - - // Convert offsets from EM to PX, and apply baseline shift - for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { - variableTextOffset = {{anchorOffset.second[0] * util::ONE_EM, anchorOffset.second[1] * util::ONE_EM}}; - switch (anchorOffset.first) { - 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; + if (!variableAnchorOffset.empty()) { + // Convert offsets from EM to PX, and apply baseline shift + for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { + std::array variableTextOffset = {{anchorOffset.second[0] * util::ONE_EM, anchorOffset.second[1] * util::ONE_EM}}; + switch (anchorOffset.first) { + 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.emplace_back(AnchorOffsetPair{anchorOffset.first, variableTextOffset}); } + + result = VariableAnchorOffsetCollection(anchorOffsets); - AnchorOffsetPair convertedAnchorOffset = {anchorOffset.first, std::array{ variableTextOffset[0], variableTextOffset[1] }}; - anchorOffsets.emplace_back(convertedAnchorOffset); } - - result = VariableAnchorOffsetCollection(anchorOffsets); } else { const std::vector variableTextAnchor = layout->evaluate( zoom, feature, canonicalID); - // BUGBUG unused - // const SymbolAnchorType textAnchor = 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}}; @@ -409,7 +408,8 @@ std::optional SymbolLayout::getTextVariableAncho std::vector anchorOffsets; for (auto anchor : variableTextAnchor) { - auto offset = SymbolLayout::evaluateVariableOffset(anchor, variableTextOffset); + auto offset = variableTextOffset; + offset = SymbolLayout::evaluateVariableOffset(anchor, offset); anchorOffsets.emplace_back(AnchorOffsetPair{anchor, offset}); } @@ -417,26 +417,9 @@ std::optional SymbolLayout::getTextVariableAncho } } - if (result.has_value() && result->empty()) { - result.reset(); - } - return result; } -// BUGBUG why this method is necessary? -std::vector SymbolLayout::getTextVariableAnchors(const SymbolFeature& feature) { - std::vector textVariableAnchors; - auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); - if (variableAnchorOffsets) { - for (const auto &anchorOffset: variableAnchorOffsets->getOffsets()) { - textVariableAnchors.push_back(anchorOffset.first); - } - } - - return textVariableAnchors; -} - void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, @@ -487,9 +470,9 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, return result; }; - const std::vector variableTextAnchor = getTextVariableAnchors(feature); + 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 @@ -523,13 +506,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->getOffsets()) { + justifications.push_back(getAnchorJustification(anchorOffset.first)); } } for (TextJustifyType justification : justifications) { diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index f99fea3b4df..4aa950d27c1 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -115,8 +115,6 @@ class SymbolLayout final : public Layout { // Helper to support both text-variable-anchor and text-variable-anchor-offset. Offset values converted from EMs to PXs std::optional getTextVariableAnchorOffset(const SymbolFeature&); - - std::vector getTextVariableAnchors(const SymbolFeature&); // Stores the layer so that we can hold on to GeometryTileFeature instances // in SymbolFeature, which may reference data from this object. diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 2ee04965307..2207c5d2aaf 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -327,6 +327,27 @@ bool SymbolBucket::hasFormatSectionOverrides() const { return *hasFormatSectionOverrides_; } +bool SymbolBucket::hasVariableTextAnchors() const { + auto hasTextVariableAnchorOffset = [&]() -> bool { + auto tvao = layout->get(); + const bool hasAnchorOffset = tvao.match([](const auto&) { return true; }); + if (hasAnchorOffset) { + if (tvao.isConstant()) { + const auto constValue = tvao.constant(); + return constValue && !constValue->empty(); + } + // return true for expression + else { + 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 896eee45e24..2aa30647c93 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -96,6 +96,7 @@ class SymbolBucket final : public Bucket { 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/text/placement.cpp b/src/mbgl/text/placement.cpp index 5a7fd65165b..7bd3f310d92 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -65,38 +65,11 @@ const CollisionGroups::CollisionGroup& CollisionGroups::get(const std::string& s using namespace style; -// BUGBUG move functions somewhere? -bool hasVariableTextAnchors(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) { - if (layout.get().empty()) { - const auto tvao = layout.get(); - if (!tvao.isConstant()) { - return true; - } - const auto constValue = tvao.constant(); - return constValue && !constValue->empty(); - } - - return true; -} - -std::vector getAnchors( - const std::optional& variableAnchorOffset) { - std::vector result; - if (variableAnchorOffset) { - for (const auto& anchorOffset : variableAnchorOffset->getOffsets()) { - result.push_back(anchorOffset.first); - } - } - - return result; -} - // PlacementContext implemenation class PlacementContext { std::reference_wrapper bucket; std::reference_wrapper renderTile; std::reference_wrapper state; - // std::vector textVariableAnchors; public: PlacementContext(const SymbolBucket& bucket_, @@ -115,16 +88,6 @@ class PlacementContext { partiallyEvaluatedTextSize(bucket_.textSizeBinder->evaluateForZoom(placementZoom)), partiallyEvaluatedIconSize(bucket_.iconSizeBinder->evaluateForZoom(placementZoom)), avoidEdges(std::move(avoidEdges_)) { - // auto textVariableAnchorOffset = getLayout().get(); - // auto variableAnchorOffset = textVariableAnchorOffset.evaluate(placementZoom); - // if (!variableAnchorOffset.empty()) { - // for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { - // textVariableAnchors.push_back(anchorOffset.first); - // } - // } - // else { - // textVariableAnchors = std::move(getLayout().get()); - // } } const SymbolBucket& getBucket() const { return bucket.get(); } @@ -135,10 +98,6 @@ class PlacementContext { const TransformState& getTransformState() const { return state; } - // const std::vector& getVariableTextAnchors() const { - // return textVariableAnchors; - // } - float pixelsToTileUnits; float scale; float pixelRatio; @@ -319,7 +278,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 = getAnchors(symbolInstance.textVariableAnchorOffset); + auto variableTextAnchors = symbolInstance.getTextAnchors(); textBoxes.clear(); iconBoxes.clear(); @@ -806,7 +765,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, using namespace style; const auto& layout = *bucket.layout; const bool alongLine = layout.get() != SymbolPlacementType::Point; - const bool hasVariableAnchors = hasVariableTextAnchors(layout) && bucket.hasTextData(); + const bool hasVariableAnchors = bucket.hasVariableTextAnchors() && bucket.hasTextData(); const bool updateTextFitIcon = layout.get() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && (bucket.hasIconData() || bucket.hasSdfIconData()); @@ -1001,7 +960,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const bool textAllowOverlap = bucket.layout->get(); const bool iconAllowOverlap = bucket.layout->get(); - const bool variablePlacement = hasVariableTextAnchors(*bucket.layout); + 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; @@ -1494,17 +1453,11 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se collisionGroups.get(params.sourceId), getAvoidEdges(bucket, renderTile.matrix)}; - // BUGBUG not sure I understand the logic here - // const auto& variableTextAnchors = ctx.getVariableTextAnchors(); - const auto& variableTextAnchors = std::vector{}; - // 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 { @@ -1548,13 +1501,17 @@ 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; + if (symbol.textVariableAnchorOffset && !symbol.textVariableAnchorOffset->empty()) { + variableAnchor = symbol.textVariableAnchorOffset->getOffsets().front().first; + } + if (!symbol.textCollisionFeature.boxes.empty()) { const auto& textCollisionBox = symbol.textCollisionFeature.boxes.front(); @@ -1674,7 +1631,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() && !hasVariableTextAnchors(ctx.getLayout()); + return populateIntersections && !placement.placed() && ctx.getBucket().hasVariableTextAnchors(); } // static diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/util/variable_anchor_offset_collection.cpp index 66a3202f5e1..aabbb6eebb8 100644 --- a/src/mbgl/util/variable_anchor_offset_collection.cpp +++ b/src/mbgl/util/variable_anchor_offset_collection.cpp @@ -28,8 +28,7 @@ std::array VariableAnchorOffsetCollection::getOffsetByAnchor(const Sym return {0, 0}; } -// BUGBUG check why we need both toString() and serialize() - +// Avoid quoting when convert to string in expression std::string VariableAnchorOffsetCollection::toString() const { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); From 1dd1ec3414a5556e78984ce8f017aa312ed91d91 Mon Sep 17 00:00:00 2001 From: Alexey Kon <48697757+random3940@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:34:36 -0700 Subject: [PATCH 11/35] WIP: More NSExpressions --- .../variable_anchor_offset_collection.hpp | 2 +- .../expected.png | Bin .../databind-coalesce/style.json | 57 ++++++++++++++++++ .../style.json | 8 +-- platform/darwin/src/MLNStyleValue_Private.h | 16 ++--- scripts/style-spec-reference/v8.json | 4 +- src/mbgl/layout/symbol_layout.hpp | 8 ++- src/mbgl/style/layers/symbol_layer.cpp | 3 +- 8 files changed, 74 insertions(+), 24 deletions(-) rename metrics/integration/render-tests/text-variable-anchor-offset/{databind => databind-coalesce}/expected.png (100%) create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/style.json rename metrics/integration/render-tests/text-variable-anchor-offset/{databind => databind-interpolate}/style.json (79%) diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index 0860f8b7ef0..b9606dcfbd7 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -36,7 +36,7 @@ class VariableAnchorOffsetCollection { std::array getOffsetByAnchor(const style::SymbolAnchorType& anchorType) const; // Copy assignment operator - VariableAnchorOffsetCollection& operator=(VariableAnchorOffsetCollection& other) { + VariableAnchorOffsetCollection& operator=(const VariableAnchorOffsetCollection& other) { if (this != &other) { anchorOffsets = other.anchorOffsets; } diff --git a/metrics/integration/render-tests/text-variable-anchor-offset/databind/expected.png b/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png similarity index 100% rename from metrics/integration/render-tests/text-variable-anchor-offset/databind/expected.png rename to metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png 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 00000000000..9dd5b874549 --- /dev/null +++ b/metrics/integration/render-tests/text-variable-anchor-offset/databind-coalesce/style.json @@ -0,0 +1,57 @@ +{ + "version": 8, + "metadata": { + "test": { + "collisionDebug": true, + "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/style.json b/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/style.json similarity index 79% rename from metrics/integration/render-tests/text-variable-anchor-offset/databind/style.json rename to metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/style.json index fc4ee7893fd..5381971883e 100644 --- a/metrics/integration/render-tests/text-variable-anchor-offset/databind/style.json +++ b/metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/style.json @@ -14,15 +14,15 @@ "type": "FeatureCollection", "features": [{ "type": "Feature", - "properties": { }, + "properties": { "x": 0}, "geometry": { "type": "Point", "coordinates": [-30, 0] } }, { "type": "Feature", - "properties": { "tvao": ["top", [0, -4.5]] }, + "properties": { "tvao": ["top", [0, -4.5]], "x": 5}, "geometry": { "type": "Point", "coordinates": [0, 0] } }, { "type": "Feature", - "properties": { "tvao": ["right", [4.5, 0]] }, + "properties": { "tvao": ["right", [4.5, 0]], "x": 10}, "geometry": { "type": "Point", "coordinates": [30, 0] } } ] @@ -46,7 +46,7 @@ "text-field": "Label", "text-size": 10, "text-justify": "auto", - "text-variable-anchor-offset": ["coalesce", ["get", "tvao"], ["literal", ["left", [-4.5, 0]]]], + "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" diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index f5c062de2ad..d73f6608ac0 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 @@ -221,10 +222,6 @@ class MLNStyleValueTransformer { // TODO (Yingfang) need convert raw value to mbgl value // VariableAnchorOffsetCollection void getMBGLValue(id rawValue, mbgl::VariableAnchorOffsetCollection &mbglValue) { - // BUGBUG - // mbgl::style::SymbolAnchorType x {0}; - // getMBGLValue(rawValue, x); - if ([rawValue isKindOfClass:[NSArray class]]) { NSArray *array = (NSArray *)rawValue; if (array.count % 2 != 0) { @@ -234,13 +231,9 @@ class MLNStyleValueTransformer { std::vector anchorOffsets; for (NSUInteger i = 0; i < array.count; i += 2) { - if (![array[i] isKindOfClass:[NSString class]]) { - [NSException raise:NSInvalidArgumentException - format:@"VariableTextAnchorOffset array should specify valid anchor values."]; - } + mbgl::style::SymbolAnchorType anchor{0}; + getMBGLValue(array[i], anchor); - auto anchor = - *mbgl::Enum::toEnum([(NSString *)array[i] UTF8String]); std::array offsetArray; getMBGLValue(array[i + 1], offsetArray); @@ -278,9 +271,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]]) { diff --git a/scripts/style-spec-reference/v8.json b/scripts/style-spec-reference/v8.json index 7ca0ea9fc3f..0cb39af65d1 100644 --- a/scripts/style-spec-reference/v8.json +++ b/scripts/style-spec-reference/v8.json @@ -1961,8 +1961,8 @@ }, "data-driven styling": { "js": "3.3.0", - "ios": "https://github.com/maplibre/maplibre-native/issues/2358", - "android": "https://github.com/maplibre/maplibre-native/issues/2358" + "ios": "0.999", + "android": "0.999" } }, "expression": { diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 4aa950d27c1..43b30f2ea2c 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -112,8 +112,9 @@ class SymbolLayout final : public Layout { const SymbolFeature&, 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 + + // 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 @@ -138,7 +139,8 @@ class SymbolLayout final : public Layout { style::TextSize::UnevaluatedType textSize; style::IconSize::UnevaluatedType iconSize; style::TextRadialOffset::UnevaluatedType textRadialOffset; - style::TextVariableAnchorOffset::UnevaluatedType textVariableAnchorOffset; + style::TextVariableAnchorOffset::UnevaluatedType + textVariableAnchorOffset; // BUGBUG Why copy it here? it's not really doing anything. Immutable layout; std::vector features; diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 6c9f5602054..f4af0d262dc 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1805,8 +1805,7 @@ std::optional SymbolLayer::setPropertyInternal(const std::string& name, c } if (property == Property::TextVariableAnchorOffset) { Error error; - const auto& typedValue = - convert>(value, error, false, false); + const auto& typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } From f6334d1627e96e55a82ea2617cf0af7a934dd1be Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Sun, 29 Sep 2024 14:20:08 +0800 Subject: [PATCH 12/35] update expected images --- .../databind-coalesce/expected.png | Bin 0 -> 4326 bytes .../databind-interpolate/expected.png | Bin 0 -> 4356 bytes .../databind-coalesce/expected.png | Bin 5867 -> 4478 bytes .../databind-interpolate/expected.png | Bin 0 -> 4498 bytes .../icon-text-fit-collision-box/expected.png | Bin 4022 -> 3015 bytes .../pitched-offset/expected.png | Bin 59025 -> 35112 bytes .../pitched-with-map/expected.png | Bin 46657 -> 29202 bytes .../rotated-with-map/expected.png | Bin 53088 -> 51785 bytes platform/darwin/src/MLNStyleValue_Private.h | 4 ---- src/mbgl/layout/symbol_layout.hpp | 4 ++-- src/mbgl/style/expression/coercion.cpp | 1 - 11 files changed, 2 insertions(+), 7 deletions(-) create mode 100644 metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png create mode 100644 metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png create mode 100644 metrics/integration/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png diff --git a/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png b/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..6c5f10054605f69c93f526561af041e2b0cfc3b0 GIT binary patch literal 4326 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 K=38}S$bSHP5H_6v literal 0 HcmV?d00001 diff --git a/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png b/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..6efc0b63826195c5bd49f001ec2ad0c7498f8d2f GIT binary patch literal 4356 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 literal 0 HcmV?d00001 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 index a58f55f5c68530b844f0c7170677130b51dd6eb7..9a4f29883ffdf5c6a9f4520f973f0c6fff4a287d 100644 GIT binary patch literal 4478 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 DFO8UX literal 5867 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 BbQb^s 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 0000000000000000000000000000000000000000..1df18b8b66951e23be5dd350c694b345c9219b21 GIT binary patch literal 4498 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 r_}$qqGn@geoA2AWy0h2?4|cND+8+ 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 F_CJ=w)YAX} 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 index 6d2267d9c3c2cd8af3d243f4ff3a4aeb967ab012..6b5d702378b5562c55ff770cca9470a9e9fbd75e 100644 GIT binary patch literal 35112 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

      AoCSo^C$ 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 *toMLNRawStyleValue( const mbgl::VariableAnchorOffsetCollection mbglStopValue) { NSMutableArray *array = [NSMutableArray arrayWithCapacity:0]; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 43b30f2ea2c..4eb97f924c8 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -139,8 +139,8 @@ class SymbolLayout final : public Layout { style::TextSize::UnevaluatedType textSize; style::IconSize::UnevaluatedType iconSize; style::TextRadialOffset::UnevaluatedType textRadialOffset; - style::TextVariableAnchorOffset::UnevaluatedType - textVariableAnchorOffset; // BUGBUG Why copy it here? it's not really doing anything. + // Use this to check if there is text-variable-anchor-offset in the layout + style::TextVariableAnchorOffset::UnevaluatedType textVariableAnchorOffset; Immutable layout; std::vector features; diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index ec07d484b8b..96b4767fa71 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -72,7 +72,6 @@ EvaluationResult toColor(const Value& colorValue) { }); } -//// TODO (Yingfang) need evaluate the expression value to mbgl value EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { return value.match( [&](const VariableAnchorOffsetCollection& anchorOffset) -> EvaluationResult { return anchorOffset; }, From f48fc2112a31afec1ece0b2cb46a2435378f4ce8 Mon Sep 17 00:00:00 2001 From: Alexey Kon <48697757+random3940@users.noreply.github.com> Date: Sun, 29 Sep 2024 08:35:06 -0700 Subject: [PATCH 13/35] WIP --- include/mbgl/style/expression/dsl.hpp | 3 +- include/mbgl/util/interpolate.hpp | 12 +-- .../variable_anchor_offset_collection.hpp | 5 +- .../databind-coalesce/expected.png | Bin 4478 -> 3845 bytes .../databind-coalesce/style.json | 1 - .../databind-interpolate/style.json | 5 +- platform/darwin/src/MLNStyleValue_Private.h | 2 + src/mbgl/layout/symbol_layout.cpp | 7 +- src/mbgl/layout/symbol_layout.hpp | 4 +- src/mbgl/style/conversion/constant.cpp | 17 +++-- src/mbgl/style/conversion/function.cpp | 2 +- src/mbgl/style/expression/coercion.cpp | 71 +++++++----------- src/mbgl/style/expression/dsl.cpp | 2 +- .../variable_anchor_offset_collection.cpp | 5 +- 14 files changed, 61 insertions(+), 75 deletions(-) diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp index 2596cfbf4b8..24e271eb0ce 100644 --- a/include/mbgl/style/expression/dsl.hpp +++ b/include/mbgl/style/expression/dsl.hpp @@ -42,7 +42,8 @@ std::unique_ptr string(std::unique_ptr, std::unique_ptr< std::unique_ptr boolean(std::unique_ptr, std::unique_ptr def = nullptr); std::unique_ptr toColor(std::unique_ptr, std::unique_ptr def = nullptr); -std::unique_ptr toVariableAnchorOffsetCollection(std::unique_ptr, 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/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index 5f20d062f1a..c6afc80d33d 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -147,13 +147,13 @@ struct Interpolator { if (aPair->first != bPair->first) { throw std::runtime_error("Cannot interpolate values containing mismatched anchors. index:" + util::toString(index) + "from: " + Enum::toString(aPair->first) + ", to:" + Enum::toString(bPair->first)); } - - auto offset = std::array{ interpolate(aPair->second[0], bPair->second[0], t), interpolate(aPair->second[1], bPair->second[1], t) }; - AnchorOffsetPair anchorOffset = {aPair->first, offset}; - offsetMap.emplace_back(anchorOffset); + + auto offset = std::array{interpolate(aPair->second[0], bPair->second[0], t), + interpolate(aPair->second[1], bPair->second[1], t)}; + offsetMap.emplace_back(aPair->first, offset); } - - return VariableAnchorOffsetCollection(offsetMap); + + return VariableAnchorOffsetCollection(std::move(offsetMap)); } }; diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index b9606dcfbd7..c87fd718328 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -26,8 +26,7 @@ class VariableAnchorOffsetCollection { anchorOffsets = std::move(other.anchorOffsets); } - // BUGBUG add overload to take advantage of std::move. - VariableAnchorOffsetCollection(const std::vector& values) { anchorOffsets = values; } + VariableAnchorOffsetCollection(std::vector&& values) { anchorOffsets = std::move(values); } std::string toString() const; mbgl::Value serialize() const; @@ -40,7 +39,6 @@ class VariableAnchorOffsetCollection { if (this != &other) { anchorOffsets = other.anchorOffsets; } - return *this; } @@ -49,7 +47,6 @@ class VariableAnchorOffsetCollection { if (this != &other) { anchorOffsets = std::move(other.anchorOffsets); } - return *this; } 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 index 9a4f29883ffdf5c6a9f4520f973f0c6fff4a287d..309c9039a3dc9f9f0a9e21b4da9056f9297ba059 100644 GIT binary patch literal 3845 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 JvqB3Q{$C~XQ(gc7 literal 4478 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 DFO8UX 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 index 9dd5b874549..ea7a2e13c47 100644 --- 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 @@ -2,7 +2,6 @@ "version": 8, "metadata": { "test": { - "collisionDebug": true, "width": 240, "height": 100 } 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 index 5381971883e..f18f9fff714 100644 --- 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 @@ -2,7 +2,6 @@ "version": 8, "metadata": { "test": { - "collisionDebug": true, "width": 240, "height": 100 } @@ -18,11 +17,11 @@ "geometry": { "type": "Point", "coordinates": [-30, 0] } }, { "type": "Feature", - "properties": { "tvao": ["top", [0, -4.5]], "x": 5}, + "properties": { "x": 5}, "geometry": { "type": "Point", "coordinates": [0, 0] } }, { "type": "Feature", - "properties": { "tvao": ["right", [4.5, 0]], "x": 10}, + "properties": { "x": 10}, "geometry": { "type": "Point", "coordinates": [30, 0] } } ] diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index 3188f545815..7df46b7f509 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -219,6 +219,7 @@ 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; @@ -318,6 +319,7 @@ class MLNStyleValueTransformer { return [MLNColor mgl_colorWithColor:mbglStopValue]; } + // VariableAnchorOffsetCollection static NSArray *toMLNRawStyleValue( const mbgl::VariableAnchorOffsetCollection mbglStopValue) { NSMutableArray *array = [NSMutableArray arrayWithCapacity:0]; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index f54224b48bb..d7c597cb4e9 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -390,8 +390,7 @@ std::optional SymbolLayout::getTextVariableAncho anchorOffsets.emplace_back(AnchorOffsetPair{anchorOffset.first, variableTextOffset}); } - result = VariableAnchorOffsetCollection(anchorOffsets); - + result = VariableAnchorOffsetCollection(std::move(anchorOffsets)); } } else { const std::vector variableTextAnchor = layout->evaluate( @@ -413,7 +412,7 @@ std::optional SymbolLayout::getTextVariableAncho anchorOffsets.emplace_back(AnchorOffsetPair{anchor, offset}); } - result = VariableAnchorOffsetCollection(anchorOffsets); + result = VariableAnchorOffsetCollection(std::move(anchorOffsets)); } } @@ -631,7 +630,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); - auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); + const auto variableAnchorOffsets = getTextVariableAnchorOffset(feature); const SymbolPlacementType textPlacement = layout->get() != AlignmentType::Map ? SymbolPlacementType::Point diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 4eb97f924c8..3c3e83b4e72 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -113,8 +113,8 @@ class SymbolLayout final : public Layout { 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 + // 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 diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 29346d5bc96..384462b89f7 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -113,17 +113,18 @@ std::optional Converter::operator()(const Convertible& value, Erro return *color; } -std::optional Converter::operator()(const Convertible& value, Error& error) const { +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) { return std::nullopt; } - + std::vector collection; for (size_t index = 0; index < arraySize; index += 2) { Convertible offsetValue = arrayMember(value, index + 1); @@ -133,7 +134,7 @@ std::optional Converter Converter{ xOffset.value(), yOffset.value() }; + auto offset = std::array{xOffset.value(), yOffset.value()}; collection.emplace_back(AnchorOffsetPair{anchorType, offset}); } - - return VariableAnchorOffsetCollection(collection); + + return VariableAnchorOffsetCollection(std::move(collection)); } template diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index f6f9d8e3c55..1e454ec1be0 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -790,7 +790,7 @@ std::optional> convertFunctionToExpression(type::Typ return toColor(get(literal(*property)), defaultExpr()); }, [&](const type::VariableAnchorOffsetCollectionType&) -> std::optional> { - return toVariableAnchorOffsetCollection(get(literal(*property)), defaultExpr()); + 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/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index 96b4767fa71..15eadd80474 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -72,15 +72,12 @@ EvaluationResult toColor(const Value& colorValue) { }); } -EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { +EvaluationResult toVariableAnchorOffset(const Value& value) { return value.match( [&](const VariableAnchorOffsetCollection& anchorOffset) -> EvaluationResult { return anchorOffset; }, - // BUGBUG handle Value? It is also annotated w/ coerse in ParsingContext::parse(). See how other cases handle - // it. [&](const std::vector& components) -> EvaluationResult { - // BUGBUG move out? Shorten / edit. if (components.size() % 2 != 0) { - return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + + return EvaluationError{"Invalid variableAnchorOffset value " + stringify(components) + ": expected an array containing an even number of values."}; } @@ -89,41 +86,30 @@ EvaluationResult toVariableAnchorOffsetCollection(const Value& value) { const auto& anchorTypeValue = components[i]; const auto& offsetArray = components[i + 1]; - if (!anchorTypeValue.is()) { - return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + - ": expected a string value as the first element of each pair."}; - } - - if (!offsetArray.is>()) { - return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + - ": expected an array value as the second element of each pair."}; + 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."}; } - if (offsetArray.get>().size() != 2) { + const auto anchor = Enum::toEnum(anchorTypeValue.get()); + if (!anchor) { return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + - ": expected an array value with two elements as the second element of each " - "pair."}; + ": unknown anchor type '" + anchorTypeValue.get() + "'"}; } - const std::string& anchorTypeString = anchorTypeValue.get(); - const auto anchorType = Enum::toEnum(anchorTypeString); - if (!anchorType) { - return EvaluationError{"Invalid variableAnchorOffsetCollection value " + stringify(components) + - ": unknown anchor type '" + anchorTypeString + "'"}; - } + const auto& offset = offsetArray.get>(); + const auto x = static_cast(offset[0].template get()); + const auto y = static_cast(offset[1].template get()); - const auto& offsetComponents = offsetArray.get>(); - const float x = offsetComponents[0].template get(); - const float y = offsetComponents[1].template get(); - - anchorOffsets.emplace_back(*anchorType, std::array{{x, y}}); + anchorOffsets.emplace_back(*anchor, std::array{{x, y}}); } - return VariableAnchorOffsetCollection{anchorOffsets}; + return VariableAnchorOffsetCollection(std::move(anchorOffsets)); }, [&](const auto&) -> EvaluationResult { - return EvaluationError{"Could not parse variableAnchorOffsetCollection from value '" + stringify(value) + - "'"}; + return EvaluationError{"Could not parse variableAnchorOffset from '" + stringify(value) + "'"}; }); } @@ -145,7 +131,7 @@ CoerceFunction getCoerceFunction(const type::Type& t) { } else if (t.is()) { return toColor; } else if (t.is()) { - return toVariableAnchorOffsetCollection; + return toVariableAnchorOffset; } else if (t.is()) { return toNumber; } else if (t.is()) { @@ -190,17 +176,16 @@ 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::NumberType&) -> std::string_view { return "to-number"; }, - [](const type::StringType&) -> std::string_view { return "to-string"; }, - [](const type::VariableAnchorOffsetCollectionType&) -> std::string_view { - return "to-variableanchoroffsetcollection"; - }, - [](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::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); } @@ -211,7 +196,7 @@ ParseResult Coercion::parse(const Convertible& value, ParsingContext& ctx) { {"to-color", type::Color}, {"to-number", type::Number}, {"to-string", type::String}, - {"to-variableanchoroffsetcollection", type::VariableAnchorOffsetCollection}}; + {"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 e6d194df45c..6dfb73d3a53 100644 --- a/src/mbgl/style/expression/dsl.cpp +++ b/src/mbgl/style/expression/dsl.cpp @@ -117,7 +117,7 @@ std::unique_ptr toColor(std::unique_ptr value, std::uniq return coercion(type::Color, std::move(value), std::move(def)); } -std::unique_ptr toVariableAnchorOffsetCollection(std::unique_ptr value, std::unique_ptr def) { +std::unique_ptr toVariableAnchorOffset(std::unique_ptr value, std::unique_ptr def) { return coercion(type::VariableAnchorOffsetCollection, std::move(value), std::move(def)); } diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/util/variable_anchor_offset_collection.cpp index aabbb6eebb8..3066683968f 100644 --- a/src/mbgl/util/variable_anchor_offset_collection.cpp +++ b/src/mbgl/util/variable_anchor_offset_collection.cpp @@ -1,6 +1,7 @@ #include -#include #include +#include +#include #include #include @@ -9,6 +10,7 @@ namespace mbgl { using namespace std; using namespace style; +using namespace style::expression; bool VariableAnchorOffsetCollection::empty() const { return anchorOffsets.size() == 0; @@ -56,4 +58,5 @@ mbgl::Value VariableAnchorOffsetCollection::serialize() const { return serialized; } + } // namespace mbgl From 228239651b89e42f282fd11586de24e190a32a6b Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Mon, 30 Sep 2024 22:43:59 +0800 Subject: [PATCH 14/35] fix unit build and update expected images --- .../variable_anchor_offset_collection.hpp | 1 + .../databind-coalesce/expected.png | Bin 4326 -> 0 bytes .../databind-interpolate/expected.png | Bin 4356 -> 0 bytes .../databind-interpolate/expected.png | Bin 4498 -> 4022 bytes .../variable_anchor_offset_collection.cpp | 1 - test/style/conversion/stringify.test.cpp | 2 +- test/text/cross_tile_symbol_index.test.cpp | 2 +- 7 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png delete mode 100644 metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index c87fd718328..929b1c73e5e 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -28,6 +28,7 @@ class VariableAnchorOffsetCollection { VariableAnchorOffsetCollection(std::vector&& values) { anchorOffsets = std::move(values); } + // Avoid quoting when convert to string in expression std::string toString() const; mbgl::Value serialize() const; bool empty() const; diff --git a/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png b/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-coalesce/expected.png deleted file mode 100644 index 6c5f10054605f69c93f526561af041e2b0cfc3b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4326 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 K=38}S$bSHP5H_6v diff --git a/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png b/metrics/expectations/platform-ios-metal/render-tests/text-variable-anchor-offset/databind-interpolate/expected.png deleted file mode 100644 index 6efc0b63826195c5bd49f001ec2ad0c7498f8d2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4356 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 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 index 1df18b8b66951e23be5dd350c694b345c9219b21..819011015e592d5798f1d23834fd701f6ea6d801 100644 GIT binary patch literal 4022 zcmcgv`9Bn1+m^{#2T^v)62fRi_90uo_U!vkhKv}pW@;jmhQ?CJGGm>{R`xN-T9z7P z$-YKn>|0sid7k(E1KuB=&-24M=lbP7_kFH&U-vn8!aY-c5ECC04Gj&*;2&KJ>bgZ8 zUJO9$+>lS~p`l@mHqh0w3eR58Sqrw(-Ydef8DC8TxSz6LyS~ zN<6(UkseB7cUb)>1;@$N#4QKB9lZDo5*QFrA>-QOL>?OQK0VqekB%0D)Poju$E)09 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 r_ VariableAnchorOffsetCollection::getOffsetByAnchor(const Sym return {0, 0}; } -// Avoid quoting when convert to string in expression std::string VariableAnchorOffsetCollection::toString() const { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp index a1f77773a71..e7d5725e655 100644 --- a/test/style/conversion/stringify.test.cpp +++ b/test/style/conversion/stringify.test.cpp @@ -62,7 +62,7 @@ TEST(Stringify, VariableAnchorOffsetCollection) { std::array offset = { 1, 1 }; std::vector test; test.emplace_back(AnchorOffsetPair{SymbolAnchorType::Left, offset}); - ASSERT_EQ(stringify(VariableAnchorOffsetCollection(test)), "[\"left\",[1.0,1.0]]"); + ASSERT_EQ(stringify(VariableAnchorOffsetCollection(std::move(test))), "[\"left\",[1.0,1.0]]"); } TEST(Stringify, Array) { diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index 6674ba897a7..de956b07360 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -17,7 +17,7 @@ SymbolInstance makeSymbolInstance(float x, float y, std::u16string key) { std::array iconOffset{{0.0f, 0.0f}}; std::array variableTextOffset{{0.0f, 0.0f}}; std::vector anchorOffsets = {{ style::SymbolAnchorType::Left, variableTextOffset }}; - VariableAnchorOffsetCollection variableAnchorOffsetCollection(anchorOffsets); + VariableAnchorOffsetCollection variableAnchorOffsetCollection(std::move(anchorOffsets)); style::SymbolPlacementType placementType = style::SymbolPlacementType::Point; auto sharedData = std::make_shared(std::move(line), From 4c4a61ea04ce428ef50661b89c9c7757c847f7ca Mon Sep 17 00:00:00 2001 From: Alexey Kon <48697757+random3940@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:03:29 -0700 Subject: [PATCH 15/35] Minor clean-up --- platform/darwin/src/MLNStyleValue_Private.h | 5 +- src/mbgl/layout/symbol_layout.hpp | 1 - test/style/conversion/stringify.test.cpp | 5 +- ...variable_anchor_offset_collection.test.cpp | 52 +++++++------------ test/text/cross_tile_symbol_index.test.cpp | 2 +- 5 files changed, 25 insertions(+), 40 deletions(-) diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index 7df46b7f509..3ca40300c6a 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -322,12 +322,11 @@ class MLNStyleValueTransformer { // VariableAnchorOffsetCollection static NSArray *toMLNRawStyleValue( const mbgl::VariableAnchorOffsetCollection mbglStopValue) { - NSMutableArray *array = [NSMutableArray arrayWithCapacity:0]; + NSMutableArray *array = + [NSMutableArray arrayWithCapacity:mbglStopValue.getOffsets().size() * 2]; for (const auto &anchorOffset : mbglStopValue.getOffsets()) { NSString *anchor = toMLNRawStyleValue(anchorOffset.first); NSValue *offset = [NSValue mgl_valueWithOffsetArray:anchorOffset.second]; - - // BUGBUG inline [array addObject:[NSExpression expressionForConstantValue:anchor]]; [array addObject:[NSExpression expressionForConstantValue:offset]]; } diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 3c3e83b4e72..7f0f27e5adb 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -139,7 +139,6 @@ class SymbolLayout final : public Layout { style::TextSize::UnevaluatedType textSize; style::IconSize::UnevaluatedType iconSize; style::TextRadialOffset::UnevaluatedType textRadialOffset; - // Use this to check if there is text-variable-anchor-offset in the layout style::TextVariableAnchorOffset::UnevaluatedType textVariableAnchorOffset; Immutable layout; std::vector features; diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp index e7d5725e655..76aa3535988 100644 --- a/test/style/conversion/stringify.test.cpp +++ b/test/style/conversion/stringify.test.cpp @@ -59,9 +59,8 @@ TEST(Stringify, Color) { } TEST(Stringify, VariableAnchorOffsetCollection) { - std::array offset = { 1, 1 }; - std::vector test; - test.emplace_back(AnchorOffsetPair{SymbolAnchorType::Left, offset}); + std::array offset = {1, 1}; + std::vector test{{AnchorOffsetPair{SymbolAnchorType::Left, offset}}}; ASSERT_EQ(stringify(VariableAnchorOffsetCollection(std::move(test))), "[\"left\",[1.0,1.0]]"); } diff --git a/test/style/conversion/variable_anchor_offset_collection.test.cpp b/test/style/conversion/variable_anchor_offset_collection.test.cpp index bbbcc80db12..9d8cace038e 100644 --- a/test/style/conversion/variable_anchor_offset_collection.test.cpp +++ b/test/style/conversion/variable_anchor_offset_collection.test.cpp @@ -3,12 +3,8 @@ #include #include #include -#include - -// BUGBUG check headers -#include -#include #include +#include #include @@ -16,39 +12,31 @@ using namespace mbgl; using namespace mbgl::style; using namespace mbgl::style::conversion; -// BUGBUG check if need both -using namespace style::expression; -using namespace style::expression::dsl; - TEST(StyleConversion, VariableAnchorOffsetCollection) { - Error error; - auto fromFunction = [](const char* json) { + auto jsonToExpression = [](const char* json) { conversion::Error error; - auto function = conversion::convertJSON>( + auto propertyValue = conversion::convertJSON>( json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); - return function->asExpression(); + return propertyValue->asExpression(); }; - // BUGBUG - // exponential + // interval function { - auto expr = fromFunction( - R"({"type": "exponential", "stops": [[1, ["left", [0, 0]]], [11, ["left", [10, 20]]]]})"); - auto val = expr.evaluate(5); - auto val1 = expr.evaluate(11); + 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}, {{4, 8}}}}), val); // BUGBUG check value - EXPECT_EQ(VariableAnchorOffsetCollection({{{SymbolAnchorType::Left}, {{10, 20}}}}), val1); + 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); } - - // // BUGBUG - // { - // auto json = - // R"(["interpolate", ["linear"], ["zoom"], 0, ["literal", ["left", [0, 0]]], 1, ["literal",["left", - // [10, 20]]]])"; - // PropertyExpression expr(createExpression(json)); - // - // auto result = expr.evaluate(0.5f); - // EXPECT_EQ(VariableAnchorOffsetCollection(), result); - // } } diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index de956b07360..f566b2bdf4d 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -16,7 +16,7 @@ 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 }}; + std::vector anchorOffsets = {{style::SymbolAnchorType::Left, variableTextOffset}}; VariableAnchorOffsetCollection variableAnchorOffsetCollection(std::move(anchorOffsets)); style::SymbolPlacementType placementType = style::SymbolPlacementType::Point; From 2464724385c4452c2070a41555785cad77c6c270 Mon Sep 17 00:00:00 2001 From: Alexey Kon <48697757+random3940@users.noreply.github.com> Date: Wed, 2 Oct 2024 20:04:27 -0700 Subject: [PATCH 16/35] Fix node.js build --- platform/node/src/node_expression.cpp | 32 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index efd03370cf2..039bc34c2d6 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -40,15 +40,17 @@ 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}, - {"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}, + {"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)); @@ -227,6 +229,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.getOffsets().size() * 2); + for (const auto& variableAnchorOffset : variableAnchorOffsets.getOffsets()) { + components.emplace_back( + std::string(mbgl::Enum::toString(variableAnchorOffset.first))); + components.emplace_back(std::vector{static_cast(variableAnchorOffset.second[0]), + static_cast(variableAnchorOffset.second[1])}); + } + return operator()(components); + } }; v8::Local toJS(const Value& value) { From 3156ef589daad1de8bb3534f251e260d13be5cd5 Mon Sep 17 00:00:00 2001 From: Alexey Kon <48697757+random3940@users.noreply.github.com> Date: Wed, 2 Oct 2024 22:09:53 -0700 Subject: [PATCH 17/35] Streamline VariableAnchorOffsetCollection API --- include/mbgl/util/interpolate.hpp | 31 +++++----- .../variable_anchor_offset_collection.hpp | 61 ++++++++++--------- platform/darwin/src/MLNStyleValue_Private.h | 9 ++- platform/node/src/node_expression.cpp | 10 +-- src/mbgl/layout/symbol_instance.cpp | 4 +- src/mbgl/layout/symbol_layout.cpp | 15 ++--- src/mbgl/style/conversion/stringify.hpp | 12 ++-- src/mbgl/text/placement.cpp | 3 +- .../variable_anchor_offset_collection.cpp | 28 +++------ ...variable_anchor_offset_collection.test.cpp | 6 +- 10 files changed, 87 insertions(+), 92 deletions(-) diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index c6afc80d33d..b86da9768d0 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -132,25 +132,28 @@ struct Interpolator { template <> struct Interpolator { public: - VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const float t) { - auto aOffsets = a.getOffsets(); - auto bOffsets = b.getOffsets(); - if (aOffsets.size() != bOffsets.size()) - { - throw std::runtime_error("Cannot interpolate values of different length. from: " + a.toString() + ", to: " + b.toString()); + VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, + const VariableAnchorOffsetCollection& b, + const float t) { + if (a.size() != b.size()) { + throw std::runtime_error("Cannot interpolate values of different length. from: " + a.toString() + + ", to: " + b.toString()); } std::vector offsetMap; - for (size_t index = 0; index < aOffsets.size(); index++) { - auto aPair = std::next(aOffsets.begin(), index); - auto bPair = std::next(bOffsets.begin(), index); - if (aPair->first != bPair->first) { - throw std::runtime_error("Cannot interpolate values containing mismatched anchors. index:" + util::toString(index) + "from: " + Enum::toString(aPair->first) + ", to:" + Enum::toString(bPair->first)); + 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->second[0], bPair->second[0], t), - interpolate(aPair->second[1], bPair->second[1], t)}; - offsetMap.emplace_back(aPair->first, offset); + 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)); diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index 929b1c73e5e..38035f7b31a 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -10,51 +10,52 @@ namespace mbgl { -using AnchorOffsetPair = std::pair>; +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; +}; -// BUGBUG consider changing data types here. Current impl using extra -// heap allocs due to vector class VariableAnchorOffsetCollection { +private: + using CollectionType = std::vector; + CollectionType anchorOffsets; + public: VariableAnchorOffsetCollection() = default; - // Copy constructor - VariableAnchorOffsetCollection(const VariableAnchorOffsetCollection& other) { anchorOffsets = other.anchorOffsets; } + VariableAnchorOffsetCollection(const VariableAnchorOffsetCollection& other) = default; - // Move constructor - VariableAnchorOffsetCollection(VariableAnchorOffsetCollection&& other) noexcept { - anchorOffsets = std::move(other.anchorOffsets); - } + VariableAnchorOffsetCollection(VariableAnchorOffsetCollection&& other) noexcept = default; VariableAnchorOffsetCollection(std::vector&& values) { anchorOffsets = std::move(values); } - // Avoid quoting when convert to string in expression + std::array getOffsetByAnchor(const style::SymbolAnchorType& anchorType) const; + std::string toString() const; + mbgl::Value serialize() const; - bool empty() const; - std::vector getOffsets() const; - std::array getOffsetByAnchor(const style::SymbolAnchorType& anchorType) const; - // Copy assignment operator - VariableAnchorOffsetCollection& operator=(const VariableAnchorOffsetCollection& other) { - if (this != &other) { - anchorOffsets = other.anchorOffsets; - } - return *this; - } + bool empty() const { return anchorOffsets.size() == 0; } - // Move assignment operator - VariableAnchorOffsetCollection& operator=(VariableAnchorOffsetCollection&& other) noexcept { - if (this != &other) { - anchorOffsets = std::move(other.anchorOffsets); - } - return *this; - } + CollectionType::size_type size() const { return anchorOffsets.size(); } - bool operator==(const VariableAnchorOffsetCollection& other) const { return anchorOffsets == other.anchorOffsets; } + CollectionType::const_iterator begin() const { return anchorOffsets.begin(); } -private: - std::vector anchorOffsets; + 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/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index 3ca40300c6a..bd9e9591599 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -322,11 +322,10 @@ class MLNStyleValueTransformer { // VariableAnchorOffsetCollection static NSArray *toMLNRawStyleValue( const mbgl::VariableAnchorOffsetCollection mbglStopValue) { - NSMutableArray *array = - [NSMutableArray arrayWithCapacity:mbglStopValue.getOffsets().size() * 2]; - for (const auto &anchorOffset : mbglStopValue.getOffsets()) { - NSString *anchor = toMLNRawStyleValue(anchorOffset.first); - NSValue *offset = [NSValue mgl_valueWithOffsetArray:anchorOffset.second]; + 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]]; } diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index 039bc34c2d6..4c27e49d66e 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -232,12 +232,12 @@ struct ToValue { v8::Local operator()(const mbgl::VariableAnchorOffsetCollection& variableAnchorOffsets) { std::vector components; - components.reserve(variableAnchorOffsets.getOffsets().size() * 2); - for (const auto& variableAnchorOffset : variableAnchorOffsets.getOffsets()) { + components.reserve(variableAnchorOffsets.size() * 2); + for (const auto& variableAnchorOffset : variableAnchorOffsets) { components.emplace_back( - std::string(mbgl::Enum::toString(variableAnchorOffset.first))); - components.emplace_back(std::vector{static_cast(variableAnchorOffset.second[0]), - static_cast(variableAnchorOffset.second[1])}); + 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); } diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index c27c906cab4..43bc94f8ac2 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -207,8 +207,8 @@ bool SymbolInstance::hasSdfIcon() const { std::vector SymbolInstance::getTextAnchors() const { std::vector result; if (textVariableAnchorOffset) { - for (const auto& anchorOffset : textVariableAnchorOffset->getOffsets()) { - result.push_back(anchorOffset.first); + for (const auto& anchorOffset : *textVariableAnchorOffset) { + result.push_back(anchorOffset.anchorType); } } diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index d7c597cb4e9..019c61e7935 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -368,9 +368,10 @@ std::optional SymbolLayout::getTextVariableAncho auto variableAnchorOffset = layout->evaluate(zoom, feature, canonicalID); if (!variableAnchorOffset.empty()) { // Convert offsets from EM to PX, and apply baseline shift - for (const auto& anchorOffset: variableAnchorOffset.getOffsets()) { - std::array variableTextOffset = {{anchorOffset.second[0] * util::ONE_EM, anchorOffset.second[1] * util::ONE_EM}}; - switch (anchorOffset.first) { + 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: @@ -386,8 +387,8 @@ std::optional SymbolLayout::getTextVariableAncho case SymbolAnchorType::Right: break; } - - anchorOffsets.emplace_back(AnchorOffsetPair{anchorOffset.first, variableTextOffset}); + + anchorOffsets.emplace_back(AnchorOffsetPair{anchorOffset.anchorType, variableTextOffset}); } result = VariableAnchorOffsetCollection(std::move(anchorOffsets)); @@ -510,8 +511,8 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, if (textJustify != TextJustifyType::Auto) { justifications.push_back(textJustify); } else { - for (const auto& anchorOffset : variableAnchorOffsets->getOffsets()) { - justifications.push_back(getAnchorJustification(anchorOffset.first)); + for (const auto& anchorOffset : *variableAnchorOffsets) { + justifications.push_back(getAnchorJustification(anchorOffset.anchorType)); } } for (TextJustifyType justification : justifications) { diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index eff69de0f16..01a82b23ead 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -62,15 +62,15 @@ void stringify(Writer& writer, const Color& v) { template void stringify(Writer& writer, const VariableAnchorOffsetCollection& v) { writer.StartArray(); - - for (const auto& pair : v.getOffsets()) { - writer.String(Enum::toString(pair.first)); + + for (const auto& pair : v) { + writer.String(Enum::toString(pair.anchorType)); writer.StartArray(); - writer.Double(pair.second[0]); - writer.Double(pair.second[1]); + writer.Double(pair.offset[0]); + writer.Double(pair.offset[1]); writer.EndArray(); } - + writer.EndArray(); } diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 7bd3f310d92..f6abf0d3c27 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -405,7 +405,6 @@ 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 textVariableAnchorOffset = symbolInstance.textVariableAnchorOffset->getOffsets(); auto variableTextOffset = symbolInstance.textVariableAnchorOffset->getOffsetByAnchor(anchor); const bool allowOverlap = (i >= anchorsSize); shift = calculateVariableLayoutOffset(anchor, @@ -1509,7 +1508,7 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se IntersectStatus result; std::optional variableAnchor; if (symbol.textVariableAnchorOffset && !symbol.textVariableAnchorOffset->empty()) { - variableAnchor = symbol.textVariableAnchorOffset->getOffsets().front().first; + variableAnchor = symbol.textVariableAnchorOffset->begin()->anchorType; } if (!symbol.textCollisionFeature.boxes.empty()) { diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/util/variable_anchor_offset_collection.cpp index 426cbf87966..a8597514913 100644 --- a/src/mbgl/util/variable_anchor_offset_collection.cpp +++ b/src/mbgl/util/variable_anchor_offset_collection.cpp @@ -12,18 +12,10 @@ using namespace std; using namespace style; using namespace style::expression; -bool VariableAnchorOffsetCollection::empty() const { - return anchorOffsets.size() == 0; -}; - -std::vector VariableAnchorOffsetCollection::getOffsets() const { - return anchorOffsets; -} - std::array VariableAnchorOffsetCollection::getOffsetByAnchor(const SymbolAnchorType& anchorType) const { - for (const auto& pair : anchorOffsets) { - if (anchorType == pair.first) { - return pair.second; + for (const auto& entry : anchorOffsets) { + if (anchorType == entry.anchorType) { + return entry.offset; } } @@ -34,11 +26,11 @@ std::string VariableAnchorOffsetCollection::toString() const { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); writer.StartArray(); - for (const auto& pair : anchorOffsets) { - writer.String(Enum::toString(pair.first)); + for (const auto& entry : anchorOffsets) { + writer.String(Enum::toString(entry.anchorType)); writer.StartArray(); - writer.Double(pair.second[0]); - writer.Double(pair.second[1]); + writer.Double(entry.offset[0]); + writer.Double(entry.offset[1]); writer.EndArray(); } @@ -49,9 +41,9 @@ std::string VariableAnchorOffsetCollection::toString() const { mbgl::Value VariableAnchorOffsetCollection::serialize() const { std::vector serialized; - for (const auto& pair : anchorOffsets) { - serialized.emplace_back(Enum::toString(pair.first)); - std::vector offset{pair.second[0], pair.second[1]}; + 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); } diff --git a/test/style/conversion/variable_anchor_offset_collection.test.cpp b/test/style/conversion/variable_anchor_offset_collection.test.cpp index 9d8cace038e..f63f331923e 100644 --- a/test/style/conversion/variable_anchor_offset_collection.test.cpp +++ b/test/style/conversion/variable_anchor_offset_collection.test.cpp @@ -25,9 +25,9 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { 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)); + 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 { From d23b90d1476436f6c8f699a4049a5fe648595b9b Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Thu, 10 Oct 2024 00:26:15 +0800 Subject: [PATCH 18/35] update cache style db --- metrics/cache-style.db | Bin 19214336 -> 19214336 bytes scripts/style-spec.mjs | 5 +---- src/mbgl/style/layers/symbol_layer.cpp | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/metrics/cache-style.db b/metrics/cache-style.db index 7fbe6a9aaad37639bbed9ccd6192e4e0c3819977..2368b94aa20ef0e49965e724e0dc49699702d325 100644 GIT binary patch delta 2691 zcmZwJd3Y4%9S884o!Q-)J!TS)0NGt~a%2O!?{I095D^d}5E7sXSGW@(*ib=pke4GV z$vTo(3$m|Our*vE69Q38s0B%dRwyb^u0k6WS}k~BdSHkG`O6N9M>zC;{um*95>K6G?i~`E_^fAVN&;EqSs*cjJmfaAZ~{$a-97s zT1WLzW0a!>Cb+aoDe8eS-74SOa$}OGRA`aQTdbXPc~P#yD6qmN^^pb9RBT}rxz-;? zUQVyB>)KG)#e)e15Wx%ZN@Io{UgW(VZu@DFGkN}C01j&#BsgMTgkO7%60!G3p7!70K zF?bxZ;0bsV#zHoXgB*AY#>3Mv0VcvEcm^iJ6v%~VVJb|6>5vCAARh`~Cd`7_@G~fc zBA5enVIItf1yBqNVG%5bC9o8h!Ez{pQdj{iVHK3YYIqKQ4&|^0egV(JT381!z>81; zl~4uMupVlFzy{a|n_x54LLK}Pwm>~JfDc{*4PJ(=&fmh*Iuno4uYp?_Sz~FWG zHM{|D!cN!)Z^3Wix9~PJ!EV?Cdto2!hh{j?R@c?C`rwP$DLLXAPQ9caQD0NnsRil? z)ver9&MEE6cBNdIs6;xycYfsD+)f_UY;*!%7M}i>4>CBi=@#~U+XRFQ7g4Bvu0TbSiZCzvuvAX zSz*bxc+6j!yUc#`YV&w=n0Qw_CB7l95hsa*gnPni;VogEkSj!)9+^HiHJK_+(@n!o z0)L+0$Jg)$d^~UEE^%DAkZoF6R#uu38(TcTWbvw!<*~&pn|<2_?N*#iTa@9Y?@nn_ z=u4HlTg#7+*2ZK+X>svh`dz86Xno>6bYG<&MTf1|Rpal0PRJXfXb~B1I_vf+g*H~{ zF1jSFQ>6>5b(eNCJ(@mRkDs^CxvA1`HtTLWy?chDRj0Z&Pg)cWsMWn%XL__&pXsIj z&C3+6HQ7zCR(+<>otsdpBCB1c0qZf^u|bcfcL`!&HR?V0^+kooZa}?Z4jgqQ*+acG zn7>~WrSNWg6wA==C41?S&3cqpo)S$5U%Q~tq8i;p2Yy=M)Mli*=-L`oyI6&z@&|XS z{9HPrR)37XFfCivhNQdc((V{V%gJHnbJbYvpp+=BG|j7hfr&U{C1Z|d zsr30xSc$#yv_kt=VKmz)+P&gQRhx`L!LMNcam;JS(!8`iAzINs$aJf5>FEi>6XFw+ zQe#TzEC}vdGd)FgFHL>;p+Y;2LLL==MwaQv$&9lZ>Mau=tehab8v?N$0^JTMc z-fS*3rwi_mIght znH~~^2qA|yzpD3jlq^`VYJOQv>GEQ(6@3*<3%7=;e2_8J0y4eY9(3ULdVO9`&spmK z(|m1L>hu;~E6a4z^AX1tzPN2S)$^>98pD~nNMU?W>A)XL8yADq)eSzJ9};$wuv3Knk+44z_7P#H z2|GjBp9wol*vEu@LfEH-og?f#VHXJd3t<-tyF}P!!mbc@m9W1Oc8##>g#C@MzZ2F? z*bTxyBkXg+ZW4BjuzwKtPr|++>`TJ_Mc8e^?hy7BVP6yW4PoCBc9*d42>Ul--xGF^ zu=|8PAnf5m_GnwX*^G-J*0OxQ9*i&1UPkmbqK^@M`3{yJ#1~KHJ$`9_5MRO%tuMzXqMs4{jTm4=un{gJ+(vke7-&R@ z5utoX`Tj6|qkoDGXD~=A|ZWyn$ZSd(g1hGi0%%YC1danQJGZDOO;&#*JTlM4A@7IgO0&xG?2V&7{B=lRaw@?FkiZsL?Z&ML=Bd%msH+|=x&X6MFn zmB|h+hsOyvjH14U-}dwVv|r32wUTru)>6y~i{_RrAO6!f9Dhe}-fw$7G31UA5W0BD z$U6eZ^}MKYT$j&x%vl*!ndIQc8+9x5dg>1Ougzll|Al+@5sgm_8DvVS@)u6!dADQo Z6H7bipbCn6>+=gD_>TO7NPgGZ9{?~9Z9D(~ delta 2138 zcmYM#dw3Mp8OQNCJF`2px0wWz5E2ryOF$r$5RC;1O2i976)aR55-t&>hC(n(w6tOg zC@)D^a$$`}3$m{_Y%LJTj$kQ}&>|(RmWyDiMT6853@x;_)uNX6cjW2QKR(}mcIM2x zv$MOib!VUU*Fj5mxK-2o&D6BirJAMYOl2k||@hI6lw4 z#_FN|_=m;026jw|r(T~GPbo?1C_V3pWU_a9PL00HA4{5D3q>-uC2Bnx>s}Y@7T^IL z4Df;vOt8QY0SH0}!eD~~DUb^Npg*KRI%L2A$b^BA1=%nNav&E5LmosR3PT_thQcto z4u-=B7zqV13cd!Tp%BJE5nK;9Kr!41Ux%?U4sL?+Py!R+X1E0=LMhw|li)VE9qxcT zVKUqWQ(!851MY@Zz^d*Pcf17^av;69iI--a@n4dqY)b6_sagZWSi_rn5M2oJy_ z_zpY>Rj?So3rk=rRKqfO2x{PAcm$S1Ej$X3!S`SVd>?)QkHboM0)7aqpbl2U8h8?( zg0(=f4(g!+8eu)eU;{KkGqgY}Y=k&G4Q=oYNO%^WgCD^r*bL9Z7DxcY3-BVm1TVuY zuoYf~AHz@JHTWrPgYB>b+F>W`f{s10?&PDpSBYM2o_0jHH`=co`;56piSfMgL};>h z#2N3T2R{i_g*N)?J<`_^$_Q?;Uh@p}5BJDEbWmM@_1w?>(#%^kr!>uT^G zeX-}DcY!&^JI*&R@S^u@@QBy;?lygT+;_%&O7Hcr^u~g<{;h#eEst3qcqR1D3xTb4SQ9VO!q@w?JNq9JXa;Bi3z}ZpyVICaWb&B3+KWld$9Q#{cc$ zq64;D#OD;(S)o$R5;z0-FuAu&(SX+(cJ4h} zo@;P(!wIH`l~x^409Uc=FYKb$ijs_`dN4a>}ezww&MQ z76bxVGehgp9YYqkxZ`9^i<>*zj5(vV4zt>vW)_+KeV2X5d^>$DzG5fgeaE{@JK?pA zUB)bD;I|Y*ZMl$0k-{@yO1$c~Nn*ke$-Cyfw=n)Lz=NO}b@fylO(0tZa)oA|ug*+4*ut z!p+eO_51%nG}Wi=s5DmJdTmmo=1N2qd9>}sF7fNcyNUM@zd`&n;=RN_C*DWApZEZA zCvg|?LE>K!|C0C+@teeliGM|Wgt(jd*Tlaeev9~R;@=V>2cD|SXieWG1d4iTjXTB1U9IrthH!E(*s b9$piABv_7r`l-R@@`@p%v%Df-Y(4p34FAMM diff --git a/scripts/style-spec.mjs b/scripts/style-spec.mjs index fc1abe9895b..aec25a0300c 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/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 621bcfa1f7e..6aec283b0a0 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1371,8 +1371,8 @@ StyleProperty getLayerProperty(const SymbolLayer& layer, Property property) { return makeStyleProperty(layer.getTextTransform()); case Property::TextVariableAnchor: return makeStyleProperty(layer.getTextVariableAnchor()); - case Property::TextVariableAnchorOffset: - return makeStyleProperty(layer.getTextVariableAnchorOffset()); + case Property::TextVariableAnchorOffset: + return makeStyleProperty(layer.getTextVariableAnchorOffset()); case Property::TextWritingMode: return makeStyleProperty(layer.getTextWritingMode()); } From 7f19db224384365e32e85073cd7907c812185dd2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:41:36 +0000 Subject: [PATCH 19/35] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- include/mbgl/style/conversion_impl.hpp | 8 ++- src/mbgl/renderer/buckets/symbol_bucket.cpp | 4 +- src/mbgl/style/conversion/property_value.cpp | 9 +-- src/mbgl/style/expression/interpolate.cpp | 4 +- src/mbgl/style/expression/value.cpp | 61 ++++++++++---------- src/mbgl/text/placement.cpp | 10 +--- 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 5004ba5145e..cf425b09d55 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -322,7 +322,9 @@ struct ValueFactory { template <> struct ValueFactory { - static Value make(const VariableAnchorOffsetCollection& variableAnchorOffset) { return variableAnchorOffset.serialize(); } + static Value make(const VariableAnchorOffsetCollection& variableAnchorOffset) { + return variableAnchorOffset.serialize(); + } }; template @@ -375,7 +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 VariableAnchorOffsetCollection& v) -> StyleProperty { + return {makeValue(v), StyleProperty::Kind::Expression}; + }, [](const PropertyExpression& fn) -> StyleProperty { return {fn.getExpression().serialize(), StyleProperty::Kind::Expression}; }, diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 4b7072ce870..c099df3526f 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -370,10 +370,10 @@ bool SymbolBucket::hasVariableTextAnchors() const { return true; } } - + return false; }; - + return hasTextVariableAnchorOffset() || !layout->get().empty(); } diff --git a/src/mbgl/style/conversion/property_value.cpp b/src/mbgl/style/conversion/property_value.cpp index 413c8106f59..811a5cf1f30 100644 --- a/src/mbgl/style/conversion/property_value.cpp +++ b/src/mbgl/style/conversion/property_value.cpp @@ -80,10 +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> Converter>::operator()( conversion::Convertible const&, conversion::Error&, bool, bool) const; template std::optional>> diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 99337fe324f..c404aa28334 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -237,8 +237,8 @@ ParseResult createInterpolate(type::Type type, 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))); + 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) { diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index c2794d19127..afd691f2ad4 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -8,38 +8,39 @@ 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 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 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()); + }); } 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(); }, @@ -57,9 +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 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. diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 817599d11b2..b13c1b1612f 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -474,13 +474,9 @@ JointPlacement Placement::placeSymbol(const SymbolInstance& symbolInstance, cons } } - variableOffsets.insert(std::make_pair(symbolInstance.getCrossTileID(), - VariableOffset{variableTextOffset, - 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); From c61ea7b4be329e7f8b445ae10260229234d79eec Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Thu, 10 Oct 2024 16:25:45 +0800 Subject: [PATCH 20/35] fix comments --- include/mbgl/style/layers/layer.hpp.ejs | 1 + include/mbgl/style/layers/symbol_layer.hpp | 2 +- .../variable_anchor_offset_collection.hpp | 1 + scripts/generate-style-code.mjs | 30 +++++++++---------- src/mbgl/layout/symbol_instance.cpp | 1 + src/mbgl/layout/symbol_instance.hpp | 4 ++- src/mbgl/layout/symbol_layout.cpp | 2 ++ src/mbgl/renderer/buckets/symbol_bucket.cpp | 16 ++++------ .../possibly_evaluated_property_value.hpp | 2 ++ src/mbgl/text/placement.cpp | 4 +-- 10 files changed, 34 insertions(+), 29 deletions(-) mode change 100755 => 100644 scripts/generate-style-code.mjs diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs index 9fcb08ac7ef..a60d50e6e2b 100644 --- a/include/mbgl/style/layers/layer.hpp.ejs +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -20,6 +20,7 @@ <% } -%> <% 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 df873b0fb32..d70126df456 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index 38035f7b31a..f63fed524e2 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/scripts/generate-style-code.mjs b/scripts/generate-style-code.mjs old mode 100755 new mode 100644 index bc22b257d0f..9f1c6826f48 --- a/scripts/generate-style-code.mjs +++ b/scripts/generate-style-code.mjs @@ -26,7 +26,7 @@ function parseCSSColor(/** @type {string} **/ str) { } /** - * @param {any} property + * @param {any} property */ function isLightProperty(property) { return property['light-property'] === true; @@ -40,7 +40,7 @@ function isOverridable(property) { }; /** - * @param {any} property + * @param {any} property * @returns {string} */ function expressionType(property) { @@ -69,8 +69,8 @@ function expressionType(property) { }; /** - * - * @param {any} property + * + * @param {any} property * @returns {string} */ function evaluatedType(property) { @@ -124,8 +124,8 @@ function evaluatedType(property) { }; /** - * @param {any} property - * @param {any} type + * @param {any} property + * @param {any} type */ function attributeUniformType(property, type) { /** @type {Record} **/ @@ -156,7 +156,7 @@ function attributeUniformType(property, type) { } /** - * @param {any} property + * @param {any} property */ function layoutPropertyType(property) { switch (property['property-type']) { @@ -169,10 +169,10 @@ function layoutPropertyType(property) { }; /** - * - * @param {any} property - * @param {any} type - * @returns + * + * @param {any} property + * @param {any} type + * @returns */ function paintPropertyType(property, type) { switch (property['property-type']) { @@ -190,7 +190,7 @@ function paintPropertyType(property, type) { }; /** - * @param {any} property + * @param {any} property */ function propertyValueType(property) { switch (property['property-type']) { @@ -202,8 +202,8 @@ function propertyValueType(property) { }; /** - * @param {any} property - * @param {number} num + * @param {any} property + * @param {number} num * @returns {string} */ function formatNumber(property, num = 0) { @@ -215,7 +215,7 @@ function formatNumber(property, num = 0) { } /** - * @param {any} property + * @param {any} property */ function defaultValue(property) { // https://github.com/mapbox/mapbox-gl-native/issues/5258 diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index c40d224b9b2..6ca7c6f2ff8 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -209,6 +209,7 @@ bool SymbolInstance::hasSdfIcon() const { std::vector SymbolInstance::getTextAnchors() const { std::vector result; if (textVariableAnchorOffset) { + result.reserve(textVariableAnchorOffset->size()); for (const auto& anchorOffset : *textVariableAnchorOffset) { result.push_back(anchorOffset.anchorType); } diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 7196f0a2735..1520ebff986 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -184,7 +184,9 @@ class SymbolInstance { std::optional getPlacedIconIndex() const { return placedIconIndex; } std::optional getPlacedVerticalIconIndex() const { return placedVerticalIconIndex; } float getTextBoxScale() const { return textBoxScale; } - std::optional getTextVariableTextOffset() const { return textVariableAnchorOffset; } + std::optional getTextVariableAnchorOffset() const { + return textVariableAnchorOffset; + } bool getSingleLine() const { return singleLine; } uint32_t getCrossTileID() const { return crossTileID; } diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index b33c2c21c93..a22a35934fc 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -367,6 +367,7 @@ std::optional SymbolLayout::getTextVariableAncho std::vector anchorOffsets; auto variableAnchorOffset = layout->evaluate(zoom, feature, canonicalID); if (!variableAnchorOffset.empty()) { + anchorOffsets.reserve(variableAnchorOffset.size()); // Convert offsets from EM to PX, and apply baseline shift for (const auto& anchorOffset : variableAnchorOffset) { std::array variableTextOffset = { @@ -407,6 +408,7 @@ std::optional SymbolLayout::getTextVariableAncho } std::vector anchorOffsets; + anchorOffsets.reserve(variableTextAnchor.size()); for (auto anchor : variableTextAnchor) { auto offset = variableTextOffset; offset = SymbolLayout::evaluateVariableOffset(anchor, offset); diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 4b7072ce870..451c7beb219 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -359,16 +359,12 @@ bool SymbolBucket::hasFormatSectionOverrides() const { bool SymbolBucket::hasVariableTextAnchors() const { auto hasTextVariableAnchorOffset = [&]() -> bool { auto tvao = layout->get(); - const bool hasAnchorOffset = tvao.match([](const auto&) { return true; }); - if (hasAnchorOffset) { - if (tvao.isConstant()) { - const auto constValue = tvao.constant(); - return constValue && !constValue->empty(); - } - // return true for expression - else { - return true; - } + if (tvao.isConstant()) { + const auto constValue = tvao.constant(); + return constValue && !constValue->empty(); + } + else if (tvao.isExpression()) { + return true; } return false; diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp index 18997b3bab7..59b2a84f69a 100644 --- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp +++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp @@ -22,6 +22,8 @@ class PossiblyEvaluatedPropertyValue { : value(std::move(v)) {} 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/text/placement.cpp b/src/mbgl/text/placement.cpp index 817599d11b2..d05aae6d7f1 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -406,7 +406,7 @@ 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.getTextVariableTextOffset()->getOffsetByAnchor(anchor); + auto variableTextOffset = symbolInstance.getTextVariableAnchorOffset()->getOffsetByAnchor(anchor); const bool allowOverlap = (i >= anchorsSize); shift = calculateVariableLayoutOffset(anchor, width, @@ -1542,7 +1542,7 @@ void TilePlacement::placeSymbolBucket(const BucketPlacementData& params, std::se const SymbolInstance& symbol) noexcept -> IntersectStatus { IntersectStatus result; std::optional variableAnchor; - auto textVariableAnchorOffset = symbol.getTextVariableTextOffset(); + auto textVariableAnchorOffset = symbol.getTextVariableAnchorOffset(); if (textVariableAnchorOffset && !textVariableAnchorOffset->empty()) { variableAnchor = textVariableAnchorOffset->begin()->anchorType; } From a58bf3d6200e1f3ad4732264e454e74884acc25e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:45:03 +0000 Subject: [PATCH 21/35] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/mbgl/renderer/buckets/symbol_bucket.cpp | 3 +-- src/mbgl/renderer/possibly_evaluated_property_value.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 9da31d5b74c..cad15241793 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -362,8 +362,7 @@ bool SymbolBucket::hasVariableTextAnchors() const { if (tvao.isConstant()) { const auto constValue = tvao.constant(); return constValue && !constValue->empty(); - } - else if (tvao.isExpression()) { + } else if (tvao.isExpression()) { return true; } diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp index 59b2a84f69a..8d3a365c74b 100644 --- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp +++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp @@ -22,7 +22,7 @@ class PossiblyEvaluatedPropertyValue { : value(std::move(v)) {} bool isConstant() const noexcept { return value.template is(); } - + bool isExpression() const noexcept { return value.template is>(); } std::optional constant() const { From 768bc29834ee5867f0f8e0177721e3e911366d80 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Fri, 11 Oct 2024 19:52:22 +0800 Subject: [PATCH 22/35] update mjs --- include/mbgl/style/layers/symbol_layer.hpp | 8 ++++---- .../MapLibreAndroid/src/cpp/conversion/constant.cpp | 5 +++++ .../MapLibreAndroid/src/cpp/conversion/constant.hpp | 6 ++++++ platform/android/scripts/generate-style-code.mjs | 7 ++++++- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index d70126df456..79c5bda486b 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -185,14 +185,14 @@ class SymbolLayer final : public Layer { const PropertyValue>& getTextVariableAnchor() const; void setTextVariableAnchor(const PropertyValue>&); - static PropertyValue> getDefaultTextWritingMode(); - const PropertyValue>& getTextWritingMode() const; - void setTextWritingMode(const PropertyValue>&); - static PropertyValue getDefaultTextVariableAnchorOffset(); const PropertyValue& getTextVariableAnchorOffset() const; void setTextVariableAnchorOffset(const PropertyValue&); + static PropertyValue> getDefaultTextWritingMode(); + const PropertyValue>& getTextWritingMode() const; + void setTextWritingMode(const PropertyValue>&); + // Paint properties static PropertyValue getDefaultIconColor(); diff --git a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp index 915bc6dc753..6b790af4e4c 100644 --- a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp @@ -44,6 +44,11 @@ Result>> Converter>, Padding>: return result; } +Result>> Converter>, VariableAnchorOffsetCollection>::operator()( + jni::JNIEnv& env, const VariableAnchorOffsetCollection& value) const { + return jni::Make(env, value.toString()); +} + 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 9a4e05e8e56..66d174a82d7 100644 --- a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp @@ -5,6 +5,7 @@ #include #include #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/scripts/generate-style-code.mjs b/platform/android/scripts/generate-style-code.mjs index 4afd01a804f..5da7f57894d 100644 --- a/platform/android/scripts/generate-style-code.mjs +++ b/platform/android/scripts/generate-style-code.mjs @@ -114,13 +114,14 @@ global.propertyType = function propertyType(property) { return 'Formatted'; case 'string': case 'resolvedImage': + case 'variableAnchorOffsetCollection': return 'String'; case 'enum': return 'String'; case 'color': return 'String'; case 'padding': - return 'Float[]' + return 'Float[]'; case 'array': return `${propertyType({type:property.value, name: property.name})}[]`; default: @@ -197,6 +198,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 +272,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 `@"{"top": [1, 2]}"`; case 'array': switch (property.value) { case 'string': From 28e879554a9771c33b27bff6d8620625bbe4ea1e Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Sat, 12 Oct 2024 18:26:04 +0800 Subject: [PATCH 23/35] add jni for text-variable-anchor-offset on Anroid --- .../variable_anchor_offset_collection.hpp | 1 - .../all-anchors-icon-text-fit/metrics.json | 35 ++++++++ .../metrics.json | 35 ++++++++ .../all-anchors/metrics.json | 35 ++++++++ .../databind-coalesce/metrics.json | 35 ++++++++ .../databind-interpolate/metrics.json | 35 ++++++++ .../icon-image-all-anchors/metrics.json | 35 ++++++++ .../icon-image-offset/metrics.json | 35 ++++++++ .../icon-image/metrics.json | 35 ++++++++ .../icon-text-fit-collision-box/metrics.json | 35 ++++++++ .../no-animate-zoom/metrics.json | 35 ++++++++ .../pitched-offset/metrics.json | 35 ++++++++ .../pitched-with-map/metrics.json | 35 ++++++++ .../pitched/metrics.json | 35 ++++++++ .../rotated-offset/metrics.json | 35 ++++++++ .../rotated-with-map/metrics.json | 35 ++++++++ .../rotated/metrics.json | 35 ++++++++ .../single-justification/metrics.json | 35 ++++++++ .../single-line/metrics.json | 35 ++++++++ .../text-allow-overlap/metrics.json | 35 ++++++++ .../top-bottom-left-right/metrics.json | 35 ++++++++ .../MapLibreAndroid/src/cpp/CMakeLists.txt | 4 + .../src/cpp/conversion/constant.cpp | 3 +- .../MapLibreAndroid/src/cpp/jni_native.cpp | 4 + .../src/cpp/style/anchor_offset.cpp | 11 +++ .../src/cpp/style/anchor_offset.hpp | 18 +++++ .../src/cpp/style/layers/symbol_layer.cpp | 6 ++ .../src/cpp/style/layers/symbol_layer.hpp | 2 + .../src/cpp/style/variable_anchor_offset.cpp | 36 +++++++++ .../src/cpp/style/variable_anchor_offset.hpp | 22 +++++ .../maplibre/android/style/layers/Layer.java | 6 +- .../android/style/layers/PropertyFactory.java | 45 +++++++++++ .../android/style/layers/SymbolLayer.java | 17 ++++ .../android/style/layers/layer.java.ejs | 1 + .../style/layers/property_factory.java.ejs | 2 + .../android/style/types/AnchorOffset.kt | 33 ++++++++ .../style/types/VariableAnchorOffset.kt | 81 +++++++++++++++++++ .../testapp/style/SymbolLayerTest.java | 15 ++++ .../android/testapp/style/layer.junit.ejs | 2 + .../android/scripts/generate-style-code.mjs | 7 +- src/mbgl/style/expression/value.cpp | 2 +- 41 files changed, 1012 insertions(+), 6 deletions(-) create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json create mode 100644 metrics/linux-gcc8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json create mode 100644 platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp create mode 100644 platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp create mode 100644 platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp create mode 100644 platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp create mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt create mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/util/variable_anchor_offset_collection.hpp index f63fed524e2..5a0948adb24 100644 --- a/include/mbgl/util/variable_anchor_offset_collection.hpp +++ b/include/mbgl/util/variable_anchor_offset_collection.hpp @@ -6,7 +6,6 @@ #include #include -#include #include namespace mbgl { 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 00000000000..9953c2ea9e9 --- /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 00000000000..dca033517bc --- /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 00000000000..806d886e75c --- /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", + 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/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 00000000000..806d886e75c --- /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", + 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/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 00000000000..806d886e75c --- /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", + 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/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 00000000000..031fe71047b --- /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 00000000000..806d886e75c --- /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", + 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/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 00000000000..031fe71047b --- /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 00000000000..9f778921724 --- /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 00000000000..2a7b3b9cd61 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..9dca847cbba --- /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 00000000000..a8acd89723c --- /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 00000000000..40b67f14452 --- /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 00000000000..74f5df99b33 --- /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/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt b/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt index 05902547e94..31383e4ac8d 100644 --- a/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt +++ b/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt @@ -139,6 +139,10 @@ add_library(maplibre SHARED ${PROJECT_SOURCE_DIR}/style/formatted.hpp ${PROJECT_SOURCE_DIR}/style/formatted_section.cpp ${PROJECT_SOURCE_DIR}/style/formatted_section.hpp + ${PROJECT_SOURCE_DIR}/style/anchor_offset.cpp + ${PROJECT_SOURCE_DIR}/style/anchor_offset.hpp + ${PROJECT_SOURCE_DIR}/style/variable_anchor_offset.cpp + ${PROJECT_SOURCE_DIR}/style/variable_anchor_offset.hpp ${PROJECT_SOURCE_DIR}/style/layers/background_layer.cpp ${PROJECT_SOURCE_DIR}/style/layers/background_layer.hpp ${PROJECT_SOURCE_DIR}/style/layers/circle_layer.cpp diff --git a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp index 6b790af4e4c..f9bf15c57ba 100644 --- a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp @@ -1,6 +1,7 @@ #include "constant.hpp" #include "collection.hpp" #include "../style/formatted.hpp" +#include "../style/variable_anchor_offset.hpp" #include #include @@ -46,7 +47,7 @@ Result>> Converter>, Padding>: Result>> Converter>, VariableAnchorOffsetCollection>::operator()( jni::JNIEnv& env, const VariableAnchorOffsetCollection& value) const { - return jni::Make(env, value.toString()); + return VariableAnchorOffset::New(env, value); } Result>> Converter>, style::expression::Formatted>::operator()( diff --git a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp index ce343c48d23..31ef233ab0d 100644 --- a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp @@ -48,6 +48,8 @@ #include "style/light.hpp" #include "style/formatted.hpp" #include "style/formatted_section.hpp" +#include "style/anchor_offset.hpp" +#include "style/variable_anchor_offset.hpp" #ifndef MBGL_MODULE_SNAPSHOT_DISABLE #include "snapshotter/map_snapshotter.hpp" #include "snapshotter/map_snapshot.hpp" @@ -125,6 +127,8 @@ void registerNatives(JavaVM* vm) { Position::registerNative(env); Formatted::registerNative(env); FormattedSection::registerNative(env); + AnchorOffset::registerNative(env); + VariableAnchorOffset::registerNative(env); // Map CameraPosition::registerNative(env); diff --git a/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp b/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp new file mode 100644 index 00000000000..e4a5ac56886 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp @@ -0,0 +1,11 @@ +#include "anchor_offset.hpp" + +namespace mbgl { +namespace android { + +void AnchorOffset::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp b/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp new file mode 100644 index 00000000000..666717d72c7 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class AnchorOffset : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "org/maplibre/android/style/types/AnchorOffset"; }; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file 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 2068aa4c209..7038fc3eca5 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 fc181d1859c..d7333784ce2 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 @@ class SymbolLayer : public Layer { 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/cpp/style/variable_anchor_offset.cpp b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp new file mode 100644 index 00000000000..2f36a186570 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp @@ -0,0 +1,36 @@ +#include "variable_anchor_offset.hpp" +#include "anchor_offset.hpp" +#include "../conversion/conversion.hpp" +#include "../conversion/constant.hpp" + +namespace mbgl { +namespace android { + +void VariableAnchorOffset::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> VariableAnchorOffset::New(jni::JNIEnv& env, const VariableAnchorOffsetCollection & value) { + static auto& variableAnchorOffsetClass = jni::Class::Singleton(env); + static auto& anchorOffsetClass = jni::Class::Singleton(env); + static auto variableAnchorOffsetConstructor = variableAnchorOffsetClass.GetConstructor>>(env); + static auto anchorOffsetConstructor = anchorOffsetClass.GetConstructor>(env); + + auto variableAnchorOffsets = jni::Array>::New(env, value.size()); + 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])); + } + + auto anchorOffset = anchorOffsetClass.New(env, anchorOffsetConstructor, anchorType, offset); + variableAnchorOffsets.Set(env, i, anchorOffset); + } + + return variableAnchorOffsetClass.New(env, variableAnchorOffsetConstructor, variableAnchorOffsets); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp new file mode 100644 index 00000000000..fc57a448165 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include +#include + +namespace mbgl { +namespace android { + +using SuperTag = jni::ObjectTag; +class VariableAnchorOffset : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "org/maplibre/android/style/types/VariableAnchorOffset"; }; + + static jni::Local> New(jni::JNIEnv &, const VariableAnchorOffsetCollection &value); + + static void registerNative(jni::JNIEnv &); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java index 20f34471f9a..e8f6898c309 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java @@ -8,6 +8,7 @@ import org.maplibre.android.LibraryLoader; import org.maplibre.android.style.expressions.Expression; import org.maplibre.android.style.types.Formatted; +import org.maplibre.android.style.types.VariableAnchorOffset; import org.maplibre.android.utils.ThreadUtils; import org.maplibre.android.style.types.Formatted; @@ -155,7 +156,10 @@ private Object convertValue(@Nullable Object value) { return ((Expression) value).toArray(); } else if (value instanceof Formatted) { return ((Formatted) value).toArray(); - } else { + } else if (value instanceof VariableAnchorOffset) { + return ((VariableAnchorOffset) value).toArray(); + } + else { return value; } } 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 6bb73c6ddfb..dd49eae4fd7 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 @@ -7,6 +7,7 @@ import org.maplibre.android.style.expressions.Expression; import org.maplibre.android.style.types.Formatted; import static org.maplibre.android.utils.ColorUtils.colorToRgbaString; +import org.maplibre.android.style.types.VariableAnchorOffset; /** * Constructs paint/layout properties for Layers @@ -2387,6 +2388,50 @@ public static PropertyValue textVariableAnchor(Expression value) { 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 VariableAnchorOffset value + * @return property wrapper around VariableAnchorOffset + */ + public static PropertyValue textVariableAnchorOffset(VariableAnchorOffset 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 VariableAnchorOffset value + * @return property wrapper around VariableAnchorOffset + */ + 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 adc8148e5cf..df160ff6b1f 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 @@ -16,6 +16,7 @@ import org.maplibre.android.style.layers.TransitionOptions; import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; +import org.maplibre.android.style.types.VariableAnchorOffset; /** * An icon or a text label. @@ -505,6 +506,18 @@ public PropertyValue getTextVariableAnchor() { return (PropertyValue) new PropertyValue("text-variable-anchor", nativeGetTextVariableAnchor()); } + /** + * Get the TextVariableAnchorOffset property + * + * @return property wrapper value around VariableAnchorOffset + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getTextVariableAnchorOffset() { + checkThread(); + return (PropertyValue) new PropertyValue("text-variable-anchor-offset", nativeGetTextVariableAnchorOffset()); + } + /** * Get the TextAnchor property * @@ -1245,6 +1258,10 @@ public PropertyValue getTextTranslateAnchor() { @Keep private native Object nativeGetTextVariableAnchor(); + @NonNull + @Keep + private native Object nativeGetTextVariableAnchorOffset(); + @NonNull @Keep private native Object nativeGetTextAnchor(); diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs index 12304dd2d4b..108dea0fe17 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs @@ -26,6 +26,7 @@ import org.maplibre.android.style.layers.TransitionOptions; <% if (type === 'symbol') { -%> import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; +import org.maplibre.android.style.types.VariableAnchorOffset; <% } -%> <% if (type === 'location-indicator') { -%> import org.maplibre.android.style.layers.Layer; diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs index 6730ff5834e..346fc34f772 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs @@ -21,6 +21,8 @@ import org.maplibre.android.style.layers.LayoutPropertyValue; import org.maplibre.android.style.layers.PaintPropertyValue; import org.maplibre.android.style.layers.Property; import org.maplibre.android.style.layers.PropertyValue; +<% } else { -%> +import org.maplibre.android.style.types.VariableAnchorOffset; <% } -%> /** diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt new file mode 100644 index 00000000000..b71d3db9899 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt @@ -0,0 +1,33 @@ +package org.maplibre.android.style.types + +import androidx.annotation.Keep + +/** + * Data class representing an anchor offset in the MapLibre Android SDK. + * + * @property anchorType The type of anchor. + * @property offset An array of floats representing the offset values. + */ +@Keep +data class AnchorOffset( + val anchorType: String, + val offset: Array +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as AnchorOffset + + if (anchorType != other.anchorType) return false + if (!offset.contentEquals(other.offset)) return false + + return true + } + + override fun hashCode(): Int { + var result = anchorType.hashCode() + result = 31 * result + offset.contentHashCode() + return result + } +} diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt new file mode 100644 index 00000000000..d9ae8c5607b --- /dev/null +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt @@ -0,0 +1,81 @@ +package org.maplibre.android.style.types + +import org.json.JSONArray +import org.json.JSONObject + +/** + * Represents a collection of anchor offsets. + */ +class VariableAnchorOffset(values: Array) { + private val anchorOffsets: Array + + init { + values.copyOf().also { anchorOffsets = it } + } + + /** + * Converts the collection to a JSON string representation. + * + * @return The JSON string representation of the collection. + */ + override fun toString(): String { + val jsonArray = JSONArray() + for (entry in anchorOffsets) { + val entryArray = JSONArray() + entryArray.put(entry.offset[0]) + entryArray.put(entry.offset[1]) + + val entryObject = JSONObject() + entryObject.put(entry.anchorType, entryArray) + + jsonArray.put(entryObject) + } + + return jsonArray.toString() + } + + /** + * Converts the collection to an array. + * + * @return An array containing the anchor types and their offsets. + */ + fun toArray(): Array { + val anchorOffsetArray = arrayOfNulls(anchorOffsets.size * 2) + for (i in anchorOffsets.indices) { + anchorOffsetArray[i] = anchorOffsets[i].anchorType; + anchorOffsetArray[i + 1] = anchorOffsets[i].offset; + } + + return anchorOffsetArray + } + + fun isEmpty(): Boolean { + return anchorOffsets.isEmpty() + } + + fun size(): Int { + return anchorOffsets.size + } + + fun begin(): Iterator { + return anchorOffsets.iterator() + } + + fun end(): Iterator { + return anchorOffsets.iterator() + } + + operator fun get(index: Int): AnchorOffset { + return anchorOffsets[index] + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is VariableAnchorOffset) return false + return anchorOffsets.contentEquals(other.anchorOffsets) + } + + override fun hashCode(): Int { + return anchorOffsets.contentHashCode() + } +} \ No newline at end of file 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 425038418d1..119f07512f1 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 @@ -20,6 +20,8 @@ import org.maplibre.android.style.layers.SymbolLayer; import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; +import org.maplibre.android.style.types.AnchorOffset; +import org.maplibre.android.style.types.VariableAnchorOffset; import org.junit.Test; import org.junit.runner.RunWith; @@ -722,6 +724,19 @@ public void testTextVariableAnchorAsConstant() { 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 + VariableAnchorOffset propertyValue = new VariableAnchorOffset(new AnchorOffset[]{new AnchorOffset("top", new Float[]{1f, 2f})}); + layer.setProperties(textVariableAnchorOffset(propertyValue)); + assertEquals(layer.getTextVariableAnchorOffset().getValue(), propertyValue); + } + @Test @UiThreadTest public void testTextAnchorAsConstant() { diff --git a/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs b/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs index 6d53209a1c3..a1ac138b8d4 100644 --- a/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs +++ b/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs @@ -31,6 +31,8 @@ import org.maplibre.android.style.layers.<%- camelize(type) %>Layer; <% if (type === 'symbol') { -%> import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; +import org.maplibre.android.style.types.AnchorOffset; +import org.maplibre.android.style.types.VariableAnchorOffset; <% } -%> import org.junit.Test; diff --git a/platform/android/scripts/generate-style-code.mjs b/platform/android/scripts/generate-style-code.mjs index 5da7f57894d..eab6d15c2e5 100644 --- a/platform/android/scripts/generate-style-code.mjs +++ b/platform/android/scripts/generate-style-code.mjs @@ -114,7 +114,6 @@ global.propertyType = function propertyType(property) { return 'Formatted'; case 'string': case 'resolvedImage': - case 'variableAnchorOffsetCollection': return 'String'; case 'enum': return 'String'; @@ -122,6 +121,8 @@ global.propertyType = function propertyType(property) { return 'String'; case 'padding': return 'Float[]'; + case 'variableAnchorOffsetCollection': + return 'VariableAnchorOffset'; case 'array': return `${propertyType({type:property.value, name: property.name})}[]`; default: @@ -144,6 +145,8 @@ global.propertyJavaType = function propertyType(property) { return 'String'; case 'color': return 'String'; + case 'variableAnchorOffsetCollection': + return 'VariableAnchorOffset'; case 'array': return `${propertyJavaType({type:property.value})}[]`; default: @@ -273,7 +276,7 @@ global.defaultValueJava = function(property) { case 'padding': return '{2.0f, 2.0f, 2.0f, 2.0f}'; case 'variableAnchorOffsetCollection': - return `@"{"top": [1, 2]}"`; + return 'new VariableAnchorOffset(new AnchorOffset[]{new AnchorOffset("top", new Float[]{1f, 2f})})'; case 'array': switch (property.value) { case 'string': diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index afd691f2ad4..9d6a2c88883 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -40,7 +40,7 @@ type::Type typeOf(const Value& value) { 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(); }, From 58417d9a799be12604236fc3fd06710d5db8cd33 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Sat, 12 Oct 2024 20:23:24 +0800 Subject: [PATCH 24/35] update size in metric --- .../all-anchors/metrics.json | 20 +++++++++---------- .../databind-coalesce/metrics.json | 18 ++++++++--------- .../databind-interpolate/metrics.json | 18 ++++++++--------- .../icon-image-offset/metrics.json | 20 +++++++++---------- 4 files changed, 38 insertions(+), 38 deletions(-) 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 index 806d886e75c..dfa75209163 100644 --- 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 @@ -2,8 +2,8 @@ "network": [ [ "probeNetwork - default - end", - 7, - 1778473 + 1, + 84942 ], [ "probeNetwork - default - start", @@ -14,21 +14,21 @@ "gfx": [ [ "probeGFX - default - end", + 2, 4, - 13, - 21, + 11, 1, [ - 143312, - 143312 + 33209, + 33209 ], [ - 97654, - 97654 + 238, + 238 ], [ - 1301824, - 1301824 + 1648, + 1648 ] ] ] 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 index 806d886e75c..d4202bfa226 100644 --- 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 @@ -2,8 +2,8 @@ "network": [ [ "probeNetwork - default - end", - 7, - 1778473 + 3, + 87036 ], [ "probeNetwork - default - start", @@ -14,21 +14,21 @@ "gfx": [ [ "probeGFX - default - end", + 2, 4, 13, - 21, 1, [ - 143312, - 143312 + 38722, + 38722 ], [ - 97654, - 97654 + 238, + 238 ], [ - 1301824, - 1301824 + 2944, + 2944 ] ] ] 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 index 806d886e75c..d4202bfa226 100644 --- 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 @@ -2,8 +2,8 @@ "network": [ [ "probeNetwork - default - end", - 7, - 1778473 + 3, + 87036 ], [ "probeNetwork - default - start", @@ -14,21 +14,21 @@ "gfx": [ [ "probeGFX - default - end", + 2, 4, 13, - 21, 1, [ - 143312, - 143312 + 38722, + 38722 ], [ - 97654, - 97654 + 238, + 238 ], [ - 1301824, - 1301824 + 2944, + 2944 ] ] ] 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 index 806d886e75c..7bbece367a2 100644 --- 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 @@ -2,8 +2,8 @@ "network": [ [ "probeNetwork - default - end", - 7, - 1778473 + 3, + 86050 ], [ "probeNetwork - default - start", @@ -14,21 +14,21 @@ "gfx": [ [ "probeGFX - default - end", - 4, + 2, + 6, 13, - 21, 1, [ - 143312, - 143312 + 42916, + 42916 ], [ - 97654, - 97654 + 322, + 322 ], [ - 1301824, - 1301824 + 4064, + 4064 ] ] ] From 4b43f8e8f6d39d9665b574b07e6ed132f5eb2334 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Sat, 12 Oct 2024 20:58:11 +0800 Subject: [PATCH 25/35] add more metrics --- .../all-anchors-icon-text-fit/metrics.json | 35 +++++++++++++++++++ .../metrics.json | 35 +++++++++++++++++++ .../all-anchors/metrics.json | 35 +++++++++++++++++++ .../databind-coalesce/metrics.json | 35 +++++++++++++++++++ .../databind-interpolate/metrics.json | 35 +++++++++++++++++++ .../icon-image-all-anchors/metrics.json | 35 +++++++++++++++++++ .../icon-image-offset/metrics.json | 35 +++++++++++++++++++ .../icon-image/metrics.json | 35 +++++++++++++++++++ .../icon-text-fit-collision-box/metrics.json | 35 +++++++++++++++++++ .../no-animate-zoom/metrics.json | 35 +++++++++++++++++++ .../pitched-offset/metrics.json | 35 +++++++++++++++++++ .../pitched-with-map/metrics.json | 35 +++++++++++++++++++ .../pitched/metrics.json | 35 +++++++++++++++++++ .../rotated-offset/metrics.json | 35 +++++++++++++++++++ .../rotated-with-map/metrics.json | 35 +++++++++++++++++++ .../rotated/metrics.json | 35 +++++++++++++++++++ .../single-justification/metrics.json | 35 +++++++++++++++++++ .../single-line/metrics.json | 35 +++++++++++++++++++ .../text-allow-overlap/metrics.json | 35 +++++++++++++++++++ .../top-bottom-left-right/metrics.json | 35 +++++++++++++++++++ .../all-anchors-icon-text-fit/metrics.json | 35 +++++++++++++++++++ .../metrics.json | 35 +++++++++++++++++++ .../all-anchors/metrics.json | 35 +++++++++++++++++++ .../databind-coalesce/metrics.json | 35 +++++++++++++++++++ .../databind-interpolate/metrics.json | 35 +++++++++++++++++++ .../icon-image-all-anchors/metrics.json | 35 +++++++++++++++++++ .../icon-image-offset/metrics.json | 35 +++++++++++++++++++ .../icon-image/metrics.json | 35 +++++++++++++++++++ .../icon-text-fit-collision-box/metrics.json | 35 +++++++++++++++++++ .../no-animate-zoom/metrics.json | 35 +++++++++++++++++++ .../pitched-offset/metrics.json | 35 +++++++++++++++++++ .../pitched-with-map/metrics.json | 35 +++++++++++++++++++ .../pitched/metrics.json | 35 +++++++++++++++++++ .../rotated-offset/metrics.json | 35 +++++++++++++++++++ .../rotated-with-map/metrics.json | 35 +++++++++++++++++++ .../rotated/metrics.json | 35 +++++++++++++++++++ .../single-justification/metrics.json | 35 +++++++++++++++++++ .../single-line/metrics.json | 35 +++++++++++++++++++ .../text-allow-overlap/metrics.json | 35 +++++++++++++++++++ .../top-bottom-left-right/metrics.json | 35 +++++++++++++++++++ .../all-anchors-icon-text-fit/metrics.json | 35 +++++++++++++++++++ .../metrics.json | 35 +++++++++++++++++++ .../all-anchors/metrics.json | 35 +++++++++++++++++++ .../databind-coalesce/metrics.json | 35 +++++++++++++++++++ .../databind-interpolate/metrics.json | 35 +++++++++++++++++++ .../icon-image-all-anchors/metrics.json | 35 +++++++++++++++++++ .../icon-image-offset/metrics.json | 35 +++++++++++++++++++ .../icon-image/metrics.json | 35 +++++++++++++++++++ .../icon-text-fit-collision-box/metrics.json | 35 +++++++++++++++++++ .../no-animate-zoom/metrics.json | 35 +++++++++++++++++++ .../pitched-offset/metrics.json | 35 +++++++++++++++++++ .../pitched-with-map/metrics.json | 35 +++++++++++++++++++ .../pitched/metrics.json | 35 +++++++++++++++++++ .../rotated-offset/metrics.json | 35 +++++++++++++++++++ .../rotated-with-map/metrics.json | 35 +++++++++++++++++++ .../rotated/metrics.json | 35 +++++++++++++++++++ .../single-justification/metrics.json | 35 +++++++++++++++++++ .../single-line/metrics.json | 35 +++++++++++++++++++ .../text-allow-overlap/metrics.json | 35 +++++++++++++++++++ .../top-bottom-left-right/metrics.json | 35 +++++++++++++++++++ .../all-anchors-icon-text-fit/metrics.json | 35 +++++++++++++++++++ .../metrics.json | 35 +++++++++++++++++++ .../all-anchors/metrics.json | 35 +++++++++++++++++++ .../databind-coalesce/metrics.json | 35 +++++++++++++++++++ .../databind-interpolate/metrics.json | 35 +++++++++++++++++++ .../icon-image-all-anchors/metrics.json | 35 +++++++++++++++++++ .../icon-image-offset/metrics.json | 35 +++++++++++++++++++ .../icon-image/metrics.json | 35 +++++++++++++++++++ .../icon-text-fit-collision-box/metrics.json | 35 +++++++++++++++++++ .../no-animate-zoom/metrics.json | 35 +++++++++++++++++++ .../pitched-offset/metrics.json | 35 +++++++++++++++++++ .../pitched-with-map/metrics.json | 35 +++++++++++++++++++ .../pitched/metrics.json | 35 +++++++++++++++++++ .../rotated-offset/metrics.json | 35 +++++++++++++++++++ .../rotated-with-map/metrics.json | 35 +++++++++++++++++++ .../rotated/metrics.json | 35 +++++++++++++++++++ .../single-justification/metrics.json | 35 +++++++++++++++++++ .../single-line/metrics.json | 35 +++++++++++++++++++ .../text-allow-overlap/metrics.json | 35 +++++++++++++++++++ .../top-bottom-left-right/metrics.json | 35 +++++++++++++++++++ 80 files changed, 2800 insertions(+) create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json create mode 100644 metrics/android-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/all-anchors/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-image/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/pitched/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/rotated/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-justification/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/single-line/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json create mode 100644 metrics/ios-render-test-runner/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/pitched/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/rotated/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/single-line/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json create mode 100644 metrics/linux-clang8-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-icon-text-fit/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors-text-allow-overlap/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/all-anchors/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-coalesce/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/databind-interpolate/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-all-anchors/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image-offset/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-image/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/icon-text-fit-collision-box/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/no-animate-zoom/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-offset/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched-with-map/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/pitched/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-offset/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated-with-map/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/rotated/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-justification/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/single-line/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/text-allow-overlap/metrics.json create mode 100644 metrics/macos-xcode11-release/render-tests/text-variable-anchor-offset/top-bottom-left-right/metrics.json 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 00000000000..9953c2ea9e9 --- /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 00000000000..dca033517bc --- /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 00000000000..806d886e75c --- /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 00000000000..806d886e75c --- /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 00000000000..806d886e75c --- /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 00000000000..031fe71047b --- /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 00000000000..806d886e75c --- /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 00000000000..031fe71047b --- /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 00000000000..9f778921724 --- /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 00000000000..2a7b3b9cd61 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..9dca847cbba --- /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 00000000000..a8acd89723c --- /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 00000000000..40b67f14452 --- /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 00000000000..74f5df99b33 --- /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/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 00000000000..9953c2ea9e9 --- /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 00000000000..dca033517bc --- /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 00000000000..dfa75209163 --- /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 00000000000..d4202bfa226 --- /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 00000000000..d4202bfa226 --- /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 00000000000..031fe71047b --- /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 00000000000..7bbece367a2 --- /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 00000000000..031fe71047b --- /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 00000000000..9f778921724 --- /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 00000000000..2a7b3b9cd61 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..9dca847cbba --- /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 00000000000..a8acd89723c --- /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 00000000000..40b67f14452 --- /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 00000000000..74f5df99b33 --- /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 00000000000..9953c2ea9e9 --- /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 00000000000..dca033517bc --- /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 00000000000..dfa75209163 --- /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 00000000000..d4202bfa226 --- /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 00000000000..d4202bfa226 --- /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 00000000000..031fe71047b --- /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 00000000000..7bbece367a2 --- /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 00000000000..031fe71047b --- /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 00000000000..9f778921724 --- /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 00000000000..2a7b3b9cd61 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..9dca847cbba --- /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 00000000000..a8acd89723c --- /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 00000000000..40b67f14452 --- /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 00000000000..74f5df99b33 --- /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/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 00000000000..9953c2ea9e9 --- /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 00000000000..dca033517bc --- /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 00000000000..dfa75209163 --- /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 00000000000..d4202bfa226 --- /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 00000000000..d4202bfa226 --- /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 00000000000..031fe71047b --- /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 00000000000..7bbece367a2 --- /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 00000000000..031fe71047b --- /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 00000000000..9f778921724 --- /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 00000000000..2a7b3b9cd61 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..b06ed0feb28 --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..33eed36df4c --- /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 00000000000..9dca847cbba --- /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 00000000000..a8acd89723c --- /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 00000000000..40b67f14452 --- /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 00000000000..74f5df99b33 --- /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 From 518d98f58b28f3afbcf8309beda64bee7952e090 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Mon, 14 Oct 2024 16:20:10 +0800 Subject: [PATCH 26/35] fix clang format --- .../src/cpp/style/variable_anchor_offset.cpp | 9 ++++++--- .../src/cpp/style/variable_anchor_offset.hpp | 3 ++- src/mbgl/style/expression/value.cpp | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp index 2f36a186570..68fc094d641 100644 --- a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp @@ -10,16 +10,19 @@ void VariableAnchorOffset::registerNative(jni::JNIEnv& env) { jni::Class::Singleton(env); } -jni::Local> VariableAnchorOffset::New(jni::JNIEnv& env, const VariableAnchorOffsetCollection & value) { +jni::Local> VariableAnchorOffset::New(jni::JNIEnv& env, + const VariableAnchorOffsetCollection& value) { static auto& variableAnchorOffsetClass = jni::Class::Singleton(env); static auto& anchorOffsetClass = jni::Class::Singleton(env); - static auto variableAnchorOffsetConstructor = variableAnchorOffsetClass.GetConstructor>>(env); + static auto variableAnchorOffsetConstructor = + variableAnchorOffsetClass.GetConstructor>>(env); static auto anchorOffsetConstructor = anchorOffsetClass.GetConstructor>(env); auto variableAnchorOffsets = jni::Array>::New(env, value.size()); for (std::size_t i = 0; i < value.size(); i++) { auto anchorOffsetPair = value[i]; - auto anchorType = jni::Make(env, Enum::toString(anchorOffsetPair.anchorType)); + 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])); diff --git a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp index fc57a448165..e69e2193e68 100644 --- a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp @@ -13,7 +13,8 @@ class VariableAnchorOffset : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "org/maplibre/android/style/types/VariableAnchorOffset"; }; - static jni::Local> New(jni::JNIEnv &, const VariableAnchorOffsetCollection &value); + static jni::Local> New(jni::JNIEnv &, + const VariableAnchorOffsetCollection &value); static void registerNative(jni::JNIEnv &); }; diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index 9d6a2c88883..afd691f2ad4 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -40,7 +40,7 @@ type::Type typeOf(const Value& value) { 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(); }, From 8d83c75f12bf5448a480e0ddadd96ff76513b739 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Tue, 15 Oct 2024 14:16:45 +0800 Subject: [PATCH 27/35] resolve comments --- .../MapLibreAndroid/src/cpp/CMakeLists.txt | 4 - .../src/cpp/conversion/constant.cpp | 17 +++- .../MapLibreAndroid/src/cpp/jni_native.cpp | 4 - .../src/cpp/style/anchor_offset.cpp | 11 --- .../src/cpp/style/anchor_offset.hpp | 18 ----- .../src/cpp/style/variable_anchor_offset.cpp | 39 --------- .../src/cpp/style/variable_anchor_offset.hpp | 23 ------ .../maplibre/android/style/layers/Layer.java | 3 - .../android/style/layers/PropertyFactory.java | 11 ++- .../android/style/layers/SymbolLayer.java | 7 +- .../android/style/layers/layer.java.ejs | 1 - .../style/layers/property_factory.java.ejs | 2 - .../android/style/types/AnchorOffset.kt | 33 -------- .../style/types/VariableAnchorOffset.kt | 81 ------------------- .../testapp/style/SymbolLayerTest.java | 4 +- .../android/testapp/style/layer.junit.ejs | 2 - .../android/scripts/generate-style-code.mjs | 6 +- 17 files changed, 26 insertions(+), 240 deletions(-) delete mode 100644 platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp delete mode 100644 platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp delete mode 100644 platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp delete mode 100644 platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp delete mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt delete mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt diff --git a/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt b/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt index 31383e4ac8d..05902547e94 100644 --- a/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt +++ b/platform/android/MapLibreAndroid/src/cpp/CMakeLists.txt @@ -139,10 +139,6 @@ add_library(maplibre SHARED ${PROJECT_SOURCE_DIR}/style/formatted.hpp ${PROJECT_SOURCE_DIR}/style/formatted_section.cpp ${PROJECT_SOURCE_DIR}/style/formatted_section.hpp - ${PROJECT_SOURCE_DIR}/style/anchor_offset.cpp - ${PROJECT_SOURCE_DIR}/style/anchor_offset.hpp - ${PROJECT_SOURCE_DIR}/style/variable_anchor_offset.cpp - ${PROJECT_SOURCE_DIR}/style/variable_anchor_offset.hpp ${PROJECT_SOURCE_DIR}/style/layers/background_layer.cpp ${PROJECT_SOURCE_DIR}/style/layers/background_layer.hpp ${PROJECT_SOURCE_DIR}/style/layers/circle_layer.cpp diff --git a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp index f9bf15c57ba..44321e48888 100644 --- a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.cpp @@ -1,7 +1,6 @@ #include "constant.hpp" #include "collection.hpp" #include "../style/formatted.hpp" -#include "../style/variable_anchor_offset.hpp" #include #include @@ -47,7 +46,21 @@ Result>> Converter>, Padding>: Result>> Converter>, VariableAnchorOffsetCollection>::operator()( jni::JNIEnv& env, const VariableAnchorOffsetCollection& value) const { - return VariableAnchorOffset::New(env, value); + 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()( diff --git a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp index 31ef233ab0d..ce343c48d23 100644 --- a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp @@ -48,8 +48,6 @@ #include "style/light.hpp" #include "style/formatted.hpp" #include "style/formatted_section.hpp" -#include "style/anchor_offset.hpp" -#include "style/variable_anchor_offset.hpp" #ifndef MBGL_MODULE_SNAPSHOT_DISABLE #include "snapshotter/map_snapshotter.hpp" #include "snapshotter/map_snapshot.hpp" @@ -127,8 +125,6 @@ void registerNatives(JavaVM* vm) { Position::registerNative(env); Formatted::registerNative(env); FormattedSection::registerNative(env); - AnchorOffset::registerNative(env); - VariableAnchorOffset::registerNative(env); // Map CameraPosition::registerNative(env); diff --git a/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp b/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp deleted file mode 100644 index e4a5ac56886..00000000000 --- a/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "anchor_offset.hpp" - -namespace mbgl { -namespace android { - -void AnchorOffset::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp b/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp deleted file mode 100644 index 666717d72c7..00000000000 --- a/platform/android/MapLibreAndroid/src/cpp/style/anchor_offset.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class AnchorOffset : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "org/maplibre/android/style/types/AnchorOffset"; }; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp deleted file mode 100644 index 68fc094d641..00000000000 --- a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "variable_anchor_offset.hpp" -#include "anchor_offset.hpp" -#include "../conversion/conversion.hpp" -#include "../conversion/constant.hpp" - -namespace mbgl { -namespace android { - -void VariableAnchorOffset::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> VariableAnchorOffset::New(jni::JNIEnv& env, - const VariableAnchorOffsetCollection& value) { - static auto& variableAnchorOffsetClass = jni::Class::Singleton(env); - static auto& anchorOffsetClass = jni::Class::Singleton(env); - static auto variableAnchorOffsetConstructor = - variableAnchorOffsetClass.GetConstructor>>(env); - static auto anchorOffsetConstructor = anchorOffsetClass.GetConstructor>(env); - - auto variableAnchorOffsets = jni::Array>::New(env, value.size()); - 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])); - } - - auto anchorOffset = anchorOffsetClass.New(env, anchorOffsetConstructor, anchorType, offset); - variableAnchorOffsets.Set(env, i, anchorOffset); - } - - return variableAnchorOffsetClass.New(env, variableAnchorOffsetConstructor, variableAnchorOffsets); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp b/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp deleted file mode 100644 index e69e2193e68..00000000000 --- a/platform/android/MapLibreAndroid/src/cpp/style/variable_anchor_offset.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace mbgl { -namespace android { - -using SuperTag = jni::ObjectTag; -class VariableAnchorOffset : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "org/maplibre/android/style/types/VariableAnchorOffset"; }; - - static jni::Local> New(jni::JNIEnv &, - const VariableAnchorOffsetCollection &value); - - static void registerNative(jni::JNIEnv &); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java index e8f6898c309..f60793b0432 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java @@ -8,7 +8,6 @@ import org.maplibre.android.LibraryLoader; import org.maplibre.android.style.expressions.Expression; import org.maplibre.android.style.types.Formatted; -import org.maplibre.android.style.types.VariableAnchorOffset; import org.maplibre.android.utils.ThreadUtils; import org.maplibre.android.style.types.Formatted; @@ -156,8 +155,6 @@ private Object convertValue(@Nullable Object value) { return ((Expression) value).toArray(); } else if (value instanceof Formatted) { return ((Formatted) value).toArray(); - } else if (value instanceof VariableAnchorOffset) { - return ((VariableAnchorOffset) value).toArray(); } else { return value; 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 dd49eae4fd7..e845ca276c0 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 @@ -7,7 +7,6 @@ import org.maplibre.android.style.expressions.Expression; import org.maplibre.android.style.types.Formatted; import static org.maplibre.android.utils.ColorUtils.colorToRgbaString; -import org.maplibre.android.style.types.VariableAnchorOffset; /** * Constructs paint/layout properties for Layers @@ -2403,10 +2402,10 @@ public static PropertyValue textVariableAnchor(Expression value) { 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 VariableAnchorOffset value - * @return property wrapper around VariableAnchorOffset + * @param value a Object[] value + * @return property wrapper around Object[] */ - public static PropertyValue textVariableAnchorOffset(VariableAnchorOffset value) { + public static PropertyValue textVariableAnchorOffset(Object[] value) { return new LayoutPropertyValue<>("text-variable-anchor-offset", value); } @@ -2425,8 +2424,8 @@ public static PropertyValue textVariableAnchorOffset(Varia 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 VariableAnchorOffset value - * @return property wrapper around VariableAnchorOffset + * @param value a Object[] value + * @return property wrapper around Object[] */ public static PropertyValue textVariableAnchorOffset(Expression value) { return new LayoutPropertyValue<>("text-variable-anchor-offset", value); 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 df160ff6b1f..8d521277652 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 @@ -16,7 +16,6 @@ import org.maplibre.android.style.layers.TransitionOptions; import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; -import org.maplibre.android.style.types.VariableAnchorOffset; /** * An icon or a text label. @@ -509,13 +508,13 @@ public PropertyValue getTextVariableAnchor() { /** * Get the TextVariableAnchorOffset property * - * @return property wrapper value around VariableAnchorOffset + * @return property wrapper value around Object[] */ @NonNull @SuppressWarnings("unchecked") - public PropertyValue getTextVariableAnchorOffset() { + public PropertyValue getTextVariableAnchorOffset() { checkThread(); - return (PropertyValue) new PropertyValue("text-variable-anchor-offset", nativeGetTextVariableAnchorOffset()); + return (PropertyValue) new PropertyValue("text-variable-anchor-offset", nativeGetTextVariableAnchorOffset()); } /** diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs index 108dea0fe17..12304dd2d4b 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/layer.java.ejs @@ -26,7 +26,6 @@ import org.maplibre.android.style.layers.TransitionOptions; <% if (type === 'symbol') { -%> import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; -import org.maplibre.android.style.types.VariableAnchorOffset; <% } -%> <% if (type === 'location-indicator') { -%> import org.maplibre.android.style.layers.Layer; diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs index 346fc34f772..6730ff5834e 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/property_factory.java.ejs @@ -21,8 +21,6 @@ import org.maplibre.android.style.layers.LayoutPropertyValue; import org.maplibre.android.style.layers.PaintPropertyValue; import org.maplibre.android.style.layers.Property; import org.maplibre.android.style.layers.PropertyValue; -<% } else { -%> -import org.maplibre.android.style.types.VariableAnchorOffset; <% } -%> /** diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt deleted file mode 100644 index b71d3db9899..00000000000 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/AnchorOffset.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.maplibre.android.style.types - -import androidx.annotation.Keep - -/** - * Data class representing an anchor offset in the MapLibre Android SDK. - * - * @property anchorType The type of anchor. - * @property offset An array of floats representing the offset values. - */ -@Keep -data class AnchorOffset( - val anchorType: String, - val offset: Array -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as AnchorOffset - - if (anchorType != other.anchorType) return false - if (!offset.contentEquals(other.offset)) return false - - return true - } - - override fun hashCode(): Int { - var result = anchorType.hashCode() - result = 31 * result + offset.contentHashCode() - return result - } -} diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt deleted file mode 100644 index d9ae8c5607b..00000000000 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/types/VariableAnchorOffset.kt +++ /dev/null @@ -1,81 +0,0 @@ -package org.maplibre.android.style.types - -import org.json.JSONArray -import org.json.JSONObject - -/** - * Represents a collection of anchor offsets. - */ -class VariableAnchorOffset(values: Array) { - private val anchorOffsets: Array - - init { - values.copyOf().also { anchorOffsets = it } - } - - /** - * Converts the collection to a JSON string representation. - * - * @return The JSON string representation of the collection. - */ - override fun toString(): String { - val jsonArray = JSONArray() - for (entry in anchorOffsets) { - val entryArray = JSONArray() - entryArray.put(entry.offset[0]) - entryArray.put(entry.offset[1]) - - val entryObject = JSONObject() - entryObject.put(entry.anchorType, entryArray) - - jsonArray.put(entryObject) - } - - return jsonArray.toString() - } - - /** - * Converts the collection to an array. - * - * @return An array containing the anchor types and their offsets. - */ - fun toArray(): Array { - val anchorOffsetArray = arrayOfNulls(anchorOffsets.size * 2) - for (i in anchorOffsets.indices) { - anchorOffsetArray[i] = anchorOffsets[i].anchorType; - anchorOffsetArray[i + 1] = anchorOffsets[i].offset; - } - - return anchorOffsetArray - } - - fun isEmpty(): Boolean { - return anchorOffsets.isEmpty() - } - - fun size(): Int { - return anchorOffsets.size - } - - fun begin(): Iterator { - return anchorOffsets.iterator() - } - - fun end(): Iterator { - return anchorOffsets.iterator() - } - - operator fun get(index: Int): AnchorOffset { - return anchorOffsets[index] - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is VariableAnchorOffset) return false - return anchorOffsets.contentEquals(other.anchorOffsets) - } - - override fun hashCode(): Int { - return anchorOffsets.contentHashCode() - } -} \ No newline at end of file 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 119f07512f1..cd1ed59fe4b 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 @@ -20,8 +20,6 @@ import org.maplibre.android.style.layers.SymbolLayer; import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; -import org.maplibre.android.style.types.AnchorOffset; -import org.maplibre.android.style.types.VariableAnchorOffset; import org.junit.Test; import org.junit.runner.RunWith; @@ -732,7 +730,7 @@ public void testTextVariableAnchorOffsetAsConstant() { assertNull(layer.getTextVariableAnchorOffset().getValue()); // Set and Get - VariableAnchorOffset propertyValue = new VariableAnchorOffset(new AnchorOffset[]{new AnchorOffset("top", new Float[]{1f, 2f})}); + Object[] propertyValue = new Object[] {"top", new Float[]{1f, 2f}}; layer.setProperties(textVariableAnchorOffset(propertyValue)); assertEquals(layer.getTextVariableAnchorOffset().getValue(), propertyValue); } diff --git a/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs b/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs index a1ac138b8d4..6d53209a1c3 100644 --- a/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs +++ b/platform/android/MapLibreAndroidTestApp/src/androidTest/java/org/maplibre/android/testapp/style/layer.junit.ejs @@ -31,8 +31,6 @@ import org.maplibre.android.style.layers.<%- camelize(type) %>Layer; <% if (type === 'symbol') { -%> import org.maplibre.android.style.types.Formatted; import org.maplibre.android.style.types.FormattedSection; -import org.maplibre.android.style.types.AnchorOffset; -import org.maplibre.android.style.types.VariableAnchorOffset; <% } -%> import org.junit.Test; diff --git a/platform/android/scripts/generate-style-code.mjs b/platform/android/scripts/generate-style-code.mjs index eab6d15c2e5..53b65babb73 100644 --- a/platform/android/scripts/generate-style-code.mjs +++ b/platform/android/scripts/generate-style-code.mjs @@ -122,7 +122,7 @@ global.propertyType = function propertyType(property) { case 'padding': return 'Float[]'; case 'variableAnchorOffsetCollection': - return 'VariableAnchorOffset'; + return 'Object[]'; case 'array': return `${propertyType({type:property.value, name: property.name})}[]`; default: @@ -145,8 +145,6 @@ global.propertyJavaType = function propertyType(property) { return 'String'; case 'color': return 'String'; - case 'variableAnchorOffsetCollection': - return 'VariableAnchorOffset'; case 'array': return `${propertyJavaType({type:property.value})}[]`; default: @@ -276,7 +274,7 @@ global.defaultValueJava = function(property) { case 'padding': return '{2.0f, 2.0f, 2.0f, 2.0f}'; case 'variableAnchorOffsetCollection': - return 'new VariableAnchorOffset(new AnchorOffset[]{new AnchorOffset("top", new Float[]{1f, 2f})})'; + return 'new Object[] {"top", new Float[]{1f, 2f}}'; case 'array': switch (property.value) { case 'string': From 6438b59e0a060724fc5efa7f095cf502189abb0b Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Tue, 15 Oct 2024 14:24:28 +0800 Subject: [PATCH 28/35] revert bad changes --- .../src/main/java/org/maplibre/android/style/layers/Layer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java index f60793b0432..20f34471f9a 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/style/layers/Layer.java @@ -155,8 +155,7 @@ private Object convertValue(@Nullable Object value) { return ((Expression) value).toArray(); } else if (value instanceof Formatted) { return ((Formatted) value).toArray(); - } - else { + } else { return value; } } From ead66a89ac692f8daa114b53d45d6c38400e6eff Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Wed, 16 Oct 2024 13:21:57 +0800 Subject: [PATCH 29/35] resolve comments --- include/mbgl/util/interpolate.hpp | 2 +- platform/darwin/src/MLNStyleValue_Private.h | 1 + src/mbgl/style/conversion/constant.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index b2432fc5395..3433fda8a4c 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -152,7 +152,7 @@ struct Interpolator { public: VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, - const float t) { + const float t) const noexcept { if (a.size() != b.size()) { throw std::runtime_error("Cannot interpolate values of different length. from: " + a.toString() + ", to: " + b.toString()); diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index 5dd009d7998..812a5c126d7 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -250,6 +250,7 @@ class MLNStyleValueTransformer { } 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); diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 5bad3832c1a..317a9823271 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -149,6 +149,7 @@ std::optional Converter 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); From 7b269ed9914f1a6115f2c2042d0bfa5cb84dca97 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Wed, 16 Oct 2024 22:15:39 +0800 Subject: [PATCH 30/35] fix build error --- include/mbgl/util/interpolate.hpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index 3433fda8a4c..3e59480b55e 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -153,22 +153,12 @@ struct Interpolator { VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, const float t) const noexcept { - if (a.size() != b.size()) { - throw std::runtime_error("Cannot interpolate values of different length. from: " + a.toString() + - ", to: " + b.toString()); - } - + assert(a.size() == b.size()); std::vector offsetMap; 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)); - } - + assert(aPair.anchorType == 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); From 7b265f9893c4790e5d3499244da479e289696f24 Mon Sep 17 00:00:00 2001 From: yingfang wang Date: Fri, 18 Oct 2024 12:15:57 +0800 Subject: [PATCH 31/35] add more unit tests --- src/mbgl/style/conversion/constant.cpp | 1 + ...variable_anchor_offset_collection.test.cpp | 127 +++++++++++++++++- test/style/expression/dependency.test.cpp | 1 + 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 317a9823271..8cedb663a36 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -145,6 +145,7 @@ std::optional Converter #include #include +#include #include #include @@ -13,7 +14,93 @@ using namespace mbgl::style; using namespace mbgl::style::conversion; TEST(StyleConversion, VariableAnchorOffsetCollection) { - auto jsonToExpression = [](const char* json) { + 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 containing an even number"; + 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()); + } + + auto jsonToExpression = [](const std::string& json) { conversion::Error error; auto propertyValue = conversion::convertJSON>( json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); @@ -29,6 +116,7 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { 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( @@ -39,4 +127,41 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { {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/style/expression/dependency.test.cpp b/test/style/expression/dependency.test.cpp index 2e0fce7f625..e71b978325c 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); From d40ff2961a4fd2ad4fdd8697aec606578577cd20 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:05:35 +0000 Subject: [PATCH 32/35] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../style/conversion/variable_anchor_offset_collection.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/style/conversion/variable_anchor_offset_collection.test.cpp b/test/style/conversion/variable_anchor_offset_collection.test.cpp index 7a4da2663d4..b10dbd5efbb 100644 --- a/test/style/conversion/variable_anchor_offset_collection.test.cpp +++ b/test/style/conversion/variable_anchor_offset_collection.test.cpp @@ -130,7 +130,7 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { auto jsonToPropertyValue = [&](const std::string& json) { return conversion::convertJSON>( - json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); + json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); }; // invalid expressions From 5a35f8030ab8c674f8c1bce4fa6759073314f915 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Mon, 21 Oct 2024 15:40:56 +0800 Subject: [PATCH 33/35] fix comments and fix build error --- CMakeLists.txt | 4 ++-- bazel/core.bzl | 4 ++-- include/mbgl/style/conversion/constant.hpp | 2 +- include/mbgl/style/expression/value.hpp | 2 +- include/mbgl/style/layers/layer.hpp.ejs | 2 +- include/mbgl/style/layers/symbol_layer.hpp | 2 +- .../{util => style}/variable_anchor_offset_collection.hpp | 0 include/mbgl/util/interpolate.hpp | 2 +- .../MapLibreAndroid/src/cpp/conversion/constant.hpp | 2 +- platform/darwin/src/MLNStyleValue_Private.h | 5 +++-- src/mbgl/layout/symbol_layout.hpp | 2 +- src/mbgl/style/conversion/constant.cpp | 2 +- src/mbgl/style/conversion/stringify.hpp | 2 +- .../{util => style}/variable_anchor_offset_collection.cpp | 2 +- .../conversion/variable_anchor_offset_collection.test.cpp | 7 +++---- test/text/cross_tile_symbol_index.test.cpp | 2 +- 16 files changed, 21 insertions(+), 21 deletions(-) rename include/mbgl/{util => style}/variable_anchor_offset_collection.hpp (100%) rename src/mbgl/{util => style}/variable_anchor_offset_collection.cpp (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31908dddfb7..b5a5a2792dd 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 @@ -435,7 +436,6 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/util/type_list.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/unitbezier.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/util.hpp - ${PROJECT_SOURCE_DIR}/include/mbgl/util/variable_anchor_offset_collection.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/variant.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/vectors.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/work_request.hpp @@ -865,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 @@ -1004,7 +1005,6 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/util/url.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/url.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/utf.hpp - ${PROJECT_SOURCE_DIR}/src/mbgl/util/variable_anchor_offset_collection.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/version.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/version.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/work_request.cpp diff --git a/bazel/core.bzl b/bazel/core.bzl index 82ce0b9a672..472fde18105 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", @@ -645,7 +646,6 @@ MLN_CORE_SOURCE = [ "src/mbgl/util/url.cpp", "src/mbgl/util/url.hpp", "src/mbgl/util/utf.hpp", - "src/mbgl/util/variable_anchor_offset_collection.cpp", "src/mbgl/util/version.cpp", "src/mbgl/util/version.hpp", "src/mbgl/util/work_request.cpp", @@ -803,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", @@ -861,7 +862,6 @@ MLN_CORE_HEADERS = [ "include/mbgl/util/type_list.hpp", "include/mbgl/util/unitbezier.hpp", "include/mbgl/util/util.hpp", - "include/mbgl/util/variable_anchor_offset_collection.hpp", "include/mbgl/util/variant.hpp", "include/mbgl/util/vectors.hpp", "include/mbgl/util/work_request.hpp", diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index d1a63b0347f..a73f6f461b6 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -2,11 +2,11 @@ #include #include +#include #include #include #include #include -#include #include #include diff --git a/include/mbgl/style/expression/value.hpp b/include/mbgl/style/expression/value.hpp index 7ec69ffda54..d7a305ac369 100644 --- a/include/mbgl/style/expression/value.hpp +++ b/include/mbgl/style/expression/value.hpp @@ -7,11 +7,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs index a60d50e6e2b..4b2232fdc34 100644 --- a/include/mbgl/style/layers/layer.hpp.ejs +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -20,7 +20,7 @@ <% } -%> <% if (type === 'symbol') { -%> #include -#include +#include <% } -%> #include diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 79c5bda486b..4d565cb9b45 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/mbgl/util/variable_anchor_offset_collection.hpp b/include/mbgl/style/variable_anchor_offset_collection.hpp similarity index 100% rename from include/mbgl/util/variable_anchor_offset_collection.hpp rename to include/mbgl/style/variable_anchor_offset_collection.hpp diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index 3e59480b55e..3fe9f512ac4 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -4,11 +4,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp index 66d174a82d7..661a58ce11f 100644 --- a/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/conversion/constant.hpp @@ -5,10 +5,10 @@ #include #include #include -#include #include #include +#include #include diff --git a/platform/darwin/src/MLNStyleValue_Private.h b/platform/darwin/src/MLNStyleValue_Private.h index 812a5c126d7..f95638eee62 100644 --- a/platform/darwin/src/MLNStyleValue_Private.h +++ b/platform/darwin/src/MLNStyleValue_Private.h @@ -245,8 +245,9 @@ class MLNStyleValueTransformer { if ([rawValue isKindOfClass:[NSArray class]]) { NSArray *array = (NSArray *)rawValue; if (array.count % 2 != 0) { - [NSException raise:NSInvalidArgumentException - format:@"VariableTextAnchorOffset array should have even number of elements."]; + [NSException + raise:NSInvalidArgumentException + format:@"VariableTextAnchorOffset array should have an even number of elements."]; } std::vector anchorOffsets; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 7f0f27e5adb..37848d6ef35 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -3,12 +3,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index 8cedb663a36..b994546846d 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -145,7 +145,7 @@ std::optional Converter #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/src/mbgl/util/variable_anchor_offset_collection.cpp b/src/mbgl/style/variable_anchor_offset_collection.cpp similarity index 96% rename from src/mbgl/util/variable_anchor_offset_collection.cpp rename to src/mbgl/style/variable_anchor_offset_collection.cpp index a8597514913..f4d2755900b 100644 --- a/src/mbgl/util/variable_anchor_offset_collection.cpp +++ b/src/mbgl/style/variable_anchor_offset_collection.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/test/style/conversion/variable_anchor_offset_collection.test.cpp b/test/style/conversion/variable_anchor_offset_collection.test.cpp index b10dbd5efbb..e7b7ca6604c 100644 --- a/test/style/conversion/variable_anchor_offset_collection.test.cpp +++ b/test/style/conversion/variable_anchor_offset_collection.test.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include @@ -42,7 +42,7 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { ASSERT_EQ(error.message, expectedError); // empty array - expectedError = "array must containing an even number"; + expectedError = "array must containing an even number of elements"; variableAnchorOffset = parseVariableAnchorOffsetCollection("[]"); ASSERT_FALSE(variableAnchorOffset.has_value()); ASSERT_EQ(error.message, expectedError); @@ -100,8 +100,7 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { EXPECT_EQ(7u, value.getObject()->size()); } - auto jsonToExpression = [](const std::string& json) { - conversion::Error error; + auto jsonToExpression = [&](const std::string& json) { auto propertyValue = conversion::convertJSON>( json, error, /*allowDataExpressions*/ true, /*convertTokens*/ false); return propertyValue->asExpression(); diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index 7dd3330453d..c424f8dd68a 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -1,8 +1,8 @@ #include #include +#include #include #include -#include using namespace mbgl; From 7d46f8fbe7af8a6d6c1e5e17925628ad302f3d26 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Thu, 24 Oct 2024 20:13:15 +0800 Subject: [PATCH 34/35] fix comments --- include/mbgl/util/interpolate.hpp | 15 ++++++++++++--- src/mbgl/layout/symbol_layout.cpp | 12 ++++++------ src/mbgl/style/conversion/constant.cpp | 4 ++-- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index 3fe9f512ac4..509d721d4dc 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -152,13 +152,22 @@ struct Interpolator { public: VariableAnchorOffsetCollection operator()(const VariableAnchorOffsetCollection& a, const VariableAnchorOffsetCollection& b, - const float t) const noexcept { - assert(a.size() == b.size()); + 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]; - assert(aPair.anchorType == bPair.anchorType); + 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); diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index a22a35934fc..21a3d2d218e 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -364,9 +364,9 @@ std::optional SymbolLayout::getTextVariableAncho // If style specifies text-variable-anchor-offset, just return it if (!textVariableAnchorOffset.isUndefined()) { - std::vector anchorOffsets; 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) { @@ -389,7 +389,7 @@ std::optional SymbolLayout::getTextVariableAncho break; } - anchorOffsets.emplace_back(AnchorOffsetPair{anchorOffset.anchorType, variableTextOffset}); + anchorOffsets.push_back(AnchorOffsetPair{anchorOffset.anchorType, variableTextOffset}); } result = VariableAnchorOffsetCollection(std::move(anchorOffsets)); @@ -407,15 +407,15 @@ std::optional SymbolLayout::getTextVariableAncho layout->evaluate(zoom, feature, canonicalID)[1] * util::ONE_EM}}; } - std::vector anchorOffsets; - anchorOffsets.reserve(variableTextAnchor.size()); + std::vector anchorOffsetPairs; + anchorOffsetPairs.reserve(variableTextAnchor.size()); for (auto anchor : variableTextAnchor) { auto offset = variableTextOffset; offset = SymbolLayout::evaluateVariableOffset(anchor, offset); - anchorOffsets.emplace_back(AnchorOffsetPair{anchor, offset}); + anchorOffsetPairs.push_back(AnchorOffsetPair{anchor, offset}); } - result = VariableAnchorOffsetCollection(std::move(anchorOffsets)); + result = VariableAnchorOffsetCollection(std::move(anchorOffsetPairs)); } } diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index b994546846d..4f1f0f9764d 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -145,7 +145,7 @@ std::optional Converter Converter{xOffset.value(), yOffset.value()}; - collection.emplace_back(AnchorOffsetPair{anchorType, offset}); + collection.push_back(AnchorOffsetPair{anchorType, offset}); } return VariableAnchorOffsetCollection(std::move(collection)); From 9389638a2b62fd6a61fe3b2204ffac007957db90 Mon Sep 17 00:00:00 2001 From: Yingfang Wang Date: Thu, 24 Oct 2024 20:45:24 +0800 Subject: [PATCH 35/35] update unit test --- test/CMakeLists.txt | 2 +- ...variable_anchor_offset_collection.test.cpp | 43 ++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) rename test/style/{conversion => }/variable_anchor_offset_collection.test.cpp (82%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7c4d13daaee..9d15d5ce41e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -52,7 +52,6 @@ add_library( ${PROJECT_SOURCE_DIR}/test/style/conversion/property_value.test.cpp ${PROJECT_SOURCE_DIR}/test/style/conversion/stringify.test.cpp ${PROJECT_SOURCE_DIR}/test/style/conversion/tileset.test.cpp - ${PROJECT_SOURCE_DIR}/test/style/conversion/variable_anchor_offset_collection.test.cpp ${PROJECT_SOURCE_DIR}/test/style/expression/dependency.test.cpp ${PROJECT_SOURCE_DIR}/test/style/expression/expression.test.cpp ${PROJECT_SOURCE_DIR}/test/style/expression/util.test.cpp @@ -64,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/variable_anchor_offset_collection.test.cpp b/test/style/variable_anchor_offset_collection.test.cpp similarity index 82% rename from test/style/conversion/variable_anchor_offset_collection.test.cpp rename to test/style/variable_anchor_offset_collection.test.cpp index e7b7ca6604c..9b777486921 100644 --- a/test/style/conversion/variable_anchor_offset_collection.test.cpp +++ b/test/style/variable_anchor_offset_collection.test.cpp @@ -13,7 +13,43 @@ using namespace mbgl; using namespace mbgl::style; using namespace mbgl::style::conversion; -TEST(StyleConversion, VariableAnchorOffsetCollection) { +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) { @@ -42,7 +78,7 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { ASSERT_EQ(error.message, expectedError); // empty array - expectedError = "array must containing an even number of elements"; + expectedError = "array must contain an even number of elements"; variableAnchorOffset = parseVariableAnchorOffsetCollection("[]"); ASSERT_FALSE(variableAnchorOffset.has_value()); ASSERT_EQ(error.message, expectedError); @@ -99,7 +135,10 @@ TEST(StyleConversion, VariableAnchorOffsetCollection) { 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);

    ;_H#uF7q5%s{c1*rNJqq#TfGh=m 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�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 BCg}hG 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 index 0f9eb6b592d4d7a2174c8b529768556a1f0ce34f..8b0da17d945f6916976f2456e0364243305e02ee 100644 GIT binary patch literal 29202 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�&pmJ6G*k=zeP$~~1;yBA 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 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 index d1a653f2760782b2df79bc0ccb57b48364449693..a7598d9d6fde5cd594113d4d6fda77852f9aabda 100644 GIT binary patch literal 51785 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%0Ag9au%e%rcr>!Sb8Eq(HC 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