diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 65b7d4c16e2c..62fa18eb249f 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -4369,6 +4369,7 @@ public final class com/facebook/react/uimanager/LengthPercentage { public static final field Companion Lcom/facebook/react/uimanager/LengthPercentage$Companion; public fun ()V public fun (FLcom/facebook/react/uimanager/LengthPercentageType;)V + public final fun getUnit ()Lcom/facebook/react/uimanager/LengthPercentageType; public final fun resolve (FF)F public static final fun setFromDynamic (Lcom/facebook/react/bridge/Dynamic;)Lcom/facebook/react/uimanager/LengthPercentage; } @@ -5173,6 +5174,7 @@ public class com/facebook/react/uimanager/TransformHelper { public fun ()V public static fun processTransform (Lcom/facebook/react/bridge/ReadableArray;[D)V public static fun processTransform (Lcom/facebook/react/bridge/ReadableArray;[DFFLcom/facebook/react/bridge/ReadableArray;)V + public static fun processTransform (Lcom/facebook/react/bridge/ReadableArray;[DFFLcom/facebook/react/bridge/ReadableArray;Z)V } public abstract interface class com/facebook/react/uimanager/UIBlock { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 28262eb7ce15..5ce62921824b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -572,13 +572,16 @@ protected void setTransformProperty( return; } + boolean allowPercentageResolution = ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC; + sMatrixDecompositionContext.reset(); TransformHelper.processTransform( transforms, sTransformDecompositionArray, PixelUtil.toDIPFromPixel(view.getWidth()), PixelUtil.toDIPFromPixel(view.getHeight()), - transformOrigin); + transformOrigin, + allowPercentageResolution); MatrixMathHelper.decomposeMatrix(sTransformDecompositionArray, sMatrixDecompositionContext); view.setTranslationX( PixelUtil.toPixelFromDIP( diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt index 6f5d5187f330..c4b18fc50a1e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt @@ -20,7 +20,7 @@ public enum class LengthPercentageType { public class LengthPercentage( private val value: Float, - private val unit: LengthPercentageType, + public val unit: LengthPercentageType, ) { public companion object { @JvmStatic diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java index 51f82f8bf2f0..ade6073a10eb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java @@ -45,19 +45,41 @@ private static double convertToRadians(ReadableMap transformMap, String key) { return inRadians ? value : MatrixMathHelper.degreesToRadians(value); } + /** + * @deprecated Use {@link #processTransform(ReadableArray, double[], float, float, ReadableArray, + * boolean)} instead. + */ + @Deprecated(forRemoval = true, since = "0.75") public static void processTransform(ReadableArray transforms, double[] result) { - processTransform(transforms, result, 0, 0, null); + processTransform(transforms, result, 0, 0, null, false); } + /** + * @deprecated Use {@link #processTransform(ReadableArray, double[], float, float, ReadableArray, + * boolean)} instead. + */ + @Deprecated(forRemoval = true, since = "0.75") public static void processTransform( ReadableArray transforms, double[] result, float viewWidth, float viewHeight, ReadableArray transformOrigin) { + processTransform(transforms, result, viewWidth, viewHeight, transformOrigin, false); + } + + public static void processTransform( + ReadableArray transforms, + double[] result, + float viewWidth, + float viewHeight, + ReadableArray transformOrigin, + boolean allowPercentageResolution) { double[] helperMatrix = sHelperMatrix.get(); MatrixMathHelper.resetIdentityMatrix(result); - float[] offsets = getTranslateForTransformOrigin(viewWidth, viewHeight, transformOrigin); + float[] offsets = + getTranslateForTransformOrigin( + viewWidth, viewHeight, transformOrigin, allowPercentageResolution); if (offsets != null) { MatrixMathHelper.resetIdentityMatrix(helperMatrix); @@ -104,13 +126,13 @@ public static void processTransform( } else if ("translate".equals(transformType)) { ReadableArray value = transform.getArray(transformType); double x = 0; - if (value.getType(0) == ReadableType.String) { + if (value.getType(0) == ReadableType.String && allowPercentageResolution) { x = parseTranslateValue(value.getString(0), viewWidth); } else { x = value.getDouble(0); } double y = 0; - if (value.getType(1) == ReadableType.String) { + if (value.getType(1) == ReadableType.String && allowPercentageResolution) { y = parseTranslateValue(value.getString(1), viewHeight); } else { y = value.getDouble(1); @@ -119,7 +141,8 @@ public static void processTransform( MatrixMathHelper.applyTranslate3D(helperMatrix, x, y, z); } else if ("translateX".equals(transformType)) { double translateValue = 0; - if (transform.getType(transformType) == ReadableType.String) { + if (transform.getType(transformType) == ReadableType.String + && allowPercentageResolution) { translateValue = parseTranslateValue(transform.getString(transformType), viewWidth); } else { translateValue = transform.getDouble(transformType); @@ -127,7 +150,8 @@ public static void processTransform( MatrixMathHelper.applyTranslate2D(helperMatrix, translateValue, 0d); } else if ("translateY".equals(transformType)) { double translateValue = 0; - if (transform.getType(transformType) == ReadableType.String) { + if (transform.getType(transformType) == ReadableType.String + && allowPercentageResolution) { translateValue = parseTranslateValue(transform.getString(transformType), viewHeight); } else { translateValue = transform.getDouble(transformType); @@ -167,7 +191,10 @@ private static double parseTranslateValue(String stringValue, double dimension) } private static float[] getTranslateForTransformOrigin( - float viewWidth, float viewHeight, ReadableArray transformOrigin) { + float viewWidth, + float viewHeight, + ReadableArray transformOrigin, + boolean allowPercentageResolution) { if (transformOrigin == null || (viewHeight == 0 && viewWidth == 0)) { return null; } @@ -183,10 +210,12 @@ private static float[] getTranslateForTransformOrigin( break; case String: { - String part = transformOrigin.getString(i); - if (part.endsWith("%")) { - float val = Float.parseFloat(part.substring(0, part.length() - 1)); - origin[i] = (i == 0 ? viewWidth : viewHeight) * val / 100.0f; + if (allowPercentageResolution) { + String part = transformOrigin.getString(i); + if (part.endsWith("%")) { + float val = Float.parseFloat(part.substring(0, part.length() - 1)); + origin[i] = (i == 0 ? viewWidth : viewHeight) * val / 100.0f; + } } break; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java index b910dd8266de..29f22aa352ee 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java @@ -26,6 +26,7 @@ import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.BackgroundStyleApplicator; import com.facebook.react.uimanager.LengthPercentage; +import com.facebook.react.uimanager.LengthPercentageType; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.Spacing; @@ -156,6 +157,15 @@ public void nextFocusUp(ReactViewGroup view, int viewId) { }) public void setBorderRadius(ReactViewGroup view, int index, Dynamic rawBorderRadius) { @Nullable LengthPercentage borderRadius = LengthPercentage.setFromDynamic(rawBorderRadius); + + // We do not support percentage border radii on Paper in order to be consistent with iOS (to + // avoid developer surprise if it works on one platform but not another). + if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC + && borderRadius != null + && borderRadius.getUnit() == LengthPercentageType.PERCENT) { + borderRadius = null; + } + if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) { BackgroundStyleApplicator.setBorderRadius( view, BorderRadiusProp.values()[index], borderRadius);