Add support for text-variable-anchor-offset property (#2921)

Co-authored-by: Yingfang Wang <junew@microsoft.com>
Co-authored-by: Alexey Kon <48697757+random3940@users.noreply.github.com>
This commit is contained in:
wangyingfang
2024-10-28 19:15:54 +08:00
committed by GitHub
parent 90a798bfee
commit 1a63194078
192 changed files with 5931 additions and 107 deletions

View File

@@ -44,6 +44,25 @@ Result<jni::Local<jni::Object<>>> Converter<jni::Local<jni::Object<>>, Padding>:
return result;
}
Result<jni::Local<jni::Object<>>> Converter<jni::Local<jni::Object<>>, VariableAnchorOffsetCollection>::operator()(
jni::JNIEnv& env, const VariableAnchorOffsetCollection& value) const {
auto variableAnchorOffsets = jni::Array<jni::Object<>>::New(env, value.size() * 2);
for (std::size_t i = 0; i < value.size(); i++) {
auto anchorOffsetPair = value[i];
auto anchorType = jni::Make<jni::String>(env,
Enum<style::SymbolAnchorType>::toString(anchorOffsetPair.anchorType));
auto offset = jni::Array<jni::Float>::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<jni::Local<jni::Object<>>> Converter<jni::Local<jni::Object<>>, style::expression::Formatted>::operator()(
jni::JNIEnv& env, const style::expression::Formatted& value) const {
return Formatted::New(env, value);

View File

@@ -8,6 +8,7 @@
#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/expression/image.hpp>
#include <mbgl/style/variable_anchor_offset_collection.hpp>
#include <jni/jni.hpp>
@@ -63,6 +64,11 @@ struct Converter<jni::Local<jni::Object<>>, Padding> {
Result<jni::Local<jni::Object<>>> operator()(jni::JNIEnv& env, const Padding& value) const;
};
template <>
struct Converter<jni::Local<jni::Object<>>, VariableAnchorOffsetCollection> {
Result<jni::Local<jni::Object<>>> operator()(jni::JNIEnv& env, const VariableAnchorOffsetCollection& value) const;
};
template <>
struct Converter<jni::Local<jni::Object<>>, style::expression::Formatted> {
Result<jni::Local<jni::Object<>>> operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const;

View File

@@ -189,6 +189,11 @@ jni::Local<jni::Object<>> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) {
return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextVariableAnchor()));
}
jni::Local<jni::Object<>> SymbolLayer::getTextVariableAnchorOffset(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextVariableAnchorOffset()));
}
jni::Local<jni::Object<>> SymbolLayer::getTextAnchor(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
return std::move(*convert<jni::Local<jni::Object<>>>(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"),

View File

@@ -86,6 +86,8 @@ public:
jni::Local<jni::Object<jni::ObjectTag>> getTextVariableAnchor(jni::JNIEnv&);
jni::Local<jni::Object<jni::ObjectTag>> getTextVariableAnchorOffset(jni::JNIEnv&);
jni::Local<jni::Object<jni::ObjectTag>> getTextAnchor(jni::JNIEnv&);
jni::Local<jni::Object<jni::ObjectTag>> getTextMaxAngle(jni::JNIEnv&);

View File

@@ -2387,6 +2387,50 @@ The unit is in density-independent pixels only for SDF sprites that were created
return new LayoutPropertyValue<>("text-variable-anchor", value);
}
/**
* To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations, each paired with an offset value. The renderer will attempt to place the label at each location, in order, before moving on to the next location+offset. Use `text-justify: auto` to choose justification based on anchor position.
The length of the array must be even, and must alternate between enum and point entries. i.e., each anchor location must be accompanied by a point, and that point defines the offset when the corresponding anchor location is used. Positive offset values indicate right and down, while negative values indicate left and up. Anchor locations may repeat, allowing the renderer to try multiple offsets to try and place a label using the same anchor.
When present, this property takes precedence over {@link Property.TEXT_ANCHOR}, {@link PropertyFactory#textVariableAnchor}, {@link PropertyFactory#textOffset}, and {@link PropertyFactory#textRadialOffset}.
```json
{ "text-variable-anchor-offset": ["top", [0, 4], "left", [3,0], "bottom", [1, 1]] }
```
When the renderer chooses the `top` anchor, `[0, 4]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted down by 4 ems.
When the renderer chooses the `left` anchor, `[3, 0]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted right by 3 ems.
*
* @param value a Object[] value
* @return property wrapper around Object[]
*/
public static PropertyValue<Object[]> textVariableAnchorOffset(Object[] value) {
return new LayoutPropertyValue<>("text-variable-anchor-offset", value);
}
/**
* To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations, each paired with an offset value. The renderer will attempt to place the label at each location, in order, before moving on to the next location+offset. Use `text-justify: auto` to choose justification based on anchor position.
The length of the array must be even, and must alternate between enum and point entries. i.e., each anchor location must be accompanied by a point, and that point defines the offset when the corresponding anchor location is used. Positive offset values indicate right and down, while negative values indicate left and up. Anchor locations may repeat, allowing the renderer to try multiple offsets to try and place a label using the same anchor.
When present, this property takes precedence over {@link Property.TEXT_ANCHOR}, {@link PropertyFactory#textVariableAnchor}, {@link PropertyFactory#textOffset}, and {@link PropertyFactory#textRadialOffset}.
```json
{ "text-variable-anchor-offset": ["top", [0, 4], "left", [3,0], "bottom", [1, 1]] }
```
When the renderer chooses the `top` anchor, `[0, 4]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted down by 4 ems.
When the renderer chooses the `left` anchor, `[3, 0]` will be used for {@link PropertyFactory#textOffset}; the text will be shifted right by 3 ems.
*
* @param value a Object[] value
* @return property wrapper around Object[]
*/
public static PropertyValue<Expression> textVariableAnchorOffset(Expression value) {
return new LayoutPropertyValue<>("text-variable-anchor-offset", value);
}
/**
* Part of the text placed closest to the anchor.
*

View File

@@ -505,6 +505,18 @@ public class SymbolLayer extends Layer {
return (PropertyValue<String[]>) new PropertyValue("text-variable-anchor", nativeGetTextVariableAnchor());
}
/**
* Get the TextVariableAnchorOffset property
*
* @return property wrapper value around Object[]
*/
@NonNull
@SuppressWarnings("unchecked")
public PropertyValue<Object[]> getTextVariableAnchorOffset() {
checkThread();
return (PropertyValue<Object[]>) new PropertyValue("text-variable-anchor-offset", nativeGetTextVariableAnchorOffset());
}
/**
* Get the TextAnchor property
*
@@ -1245,6 +1257,10 @@ public class SymbolLayer extends Layer {
@Keep
private native Object nativeGetTextVariableAnchor();
@NonNull
@Keep
private native Object nativeGetTextVariableAnchorOffset();
@NonNull
@Keep
private native Object nativeGetTextAnchor();

View File

@@ -722,6 +722,19 @@ public class SymbolLayerTest extends BaseLayerTest {
assertEquals(layer.getTextVariableAnchor().getValue(), propertyValue);
}
@Test
@UiThreadTest
public void testTextVariableAnchorOffsetAsConstant() {
Timber.i("text-variable-anchor-offset");
assertNotNull(layer);
assertNull(layer.getTextVariableAnchorOffset().getValue());
// Set and Get
Object[] propertyValue = new Object[] {"top", new Float[]{1f, 2f}};
layer.setProperties(textVariableAnchorOffset(propertyValue));
assertEquals(layer.getTextVariableAnchorOffset().getValue(), propertyValue);
}
@Test
@UiThreadTest
public void testTextAnchorAsConstant() {

View File

@@ -120,7 +120,9 @@ global.propertyType = function propertyType(property) {
case 'color':
return 'String';
case 'padding':
return 'Float[]'
return 'Float[]';
case 'variableAnchorOffsetCollection':
return 'Object[]';
case 'array':
return `${propertyType({type:property.value, name: property.name})}[]`;
default:
@@ -197,6 +199,8 @@ global.propertyNativeType = function (property) {
return `Color`;
case 'padding':
return 'Padding';
case 'variableAnchorOffsetCollection':
return 'VariableAnchorOffsetCollection';
case 'array':
if (property.length) {
return `std::array<${propertyType({type: property.value})}, ${property.length}>`;
@@ -269,6 +273,8 @@ global.defaultValueJava = function(property) {
return '"rgba(255,128,0,0.7)"';
case 'padding':
return '{2.0f, 2.0f, 2.0f, 2.0f}';
case 'variableAnchorOffsetCollection':
return 'new Object[] {"top", new Float[]{1f, 2f}}';
case 'array':
switch (property.value) {
case 'string':