Skip to content

Commit 1fad084

Browse files
committed
Check transforms for skew in C++ on Android
SkewMatrixHelper.isAffine2DTransformWithSkew runs before every transform update on Android 10 and later. It walked the transform array from Kotlin, importing each element and its keys over JNI, only to look for skewX/skewY. Fabric always passes a NativeArray, so read it in C++ instead, as nativeProcessTransform already does.
1 parent 7fc911a commit 1fad084

3 files changed

Lines changed: 51 additions & 0 deletions

File tree

‎packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/SkewMatrixHelper.kt‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package com.facebook.react.uimanager
99

1010
import android.graphics.Matrix
11+
import com.facebook.react.bridge.NativeArray
1112
import com.facebook.react.bridge.ReadableArray
1213
import com.facebook.react.bridge.ReadableMap
1314
import com.facebook.react.bridge.ReadableType
@@ -28,6 +29,10 @@ internal object SkewMatrixHelper {
2829
*/
2930
@JvmStatic
3031
fun isAffine2DTransformWithSkew(transforms: ReadableArray): Boolean {
32+
// Read Fabric's arrays in C++ rather than crossing JNI for every element and key.
33+
if (transforms is NativeArray) {
34+
return TransformHelper.isAffine2DTransformWithSkew(transforms)
35+
}
3136
if (isRawMatrixShorthand(transforms)) {
3237
return false
3338
}

‎packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,14 @@ public object TransformHelper {
237237
return doubleArrayOf(newTranslateX, newTranslateY, newTranslateZ)
238238
}
239239

240+
/** Native implementation of [SkewMatrixHelper.isAffine2DTransformWithSkew]. */
241+
@JvmStatic
242+
internal fun isAffine2DTransformWithSkew(transforms: NativeArray): Boolean =
243+
nativeIsAffine2DTransformWithSkew(transforms)
244+
245+
@JvmStatic
246+
private external fun nativeIsAffine2DTransformWithSkew(transforms: NativeArray): Boolean
247+
240248
@JvmStatic
241249
private external fun nativeProcessTransform(
242250
transforms: NativeArray,

‎packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.cpp‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,49 @@ void processTransform(
5151
jResult->setRegion(0, MatrixSize, doubleTransform.data());
5252
}
5353

54+
// Same result as SkewMatrixHelper.isAffine2DTransformWithSkew, but reads the
55+
// array in place instead of crossing JNI for each element and key.
56+
jboolean isAffine2DTransformWithSkew(
57+
jni::alias_ref<jclass> /*unused*/,
58+
NativeArray* jTransforms) {
59+
const auto& transforms = jTransforms->getArray();
60+
// The raw 16-element matrix shorthand used by Fabric LayoutAnimations.
61+
if (transforms.size() == 16 && transforms[0].isNumber()) {
62+
return JNI_FALSE;
63+
}
64+
bool hasSkewTransform = false;
65+
for (const auto& transform : transforms) {
66+
if (!transform.isObject() || transform.empty()) {
67+
continue;
68+
}
69+
const auto& [key, value] = *transform.items().begin();
70+
if (!key.isString()) {
71+
continue;
72+
}
73+
const auto& type = key.getString();
74+
if (type == "matrix" || type == "perspective" || type == "rotateX" ||
75+
type == "rotateY") {
76+
return JNI_FALSE;
77+
}
78+
if (type == "translate") {
79+
if (value.isArray() && value.size() > 2 && value[2].isNumber() &&
80+
value[2].asDouble() != 0.0) {
81+
return JNI_FALSE;
82+
}
83+
} else if (type == "skewX" || type == "skewY") {
84+
hasSkewTransform = true;
85+
}
86+
}
87+
return hasSkewTransform ? JNI_TRUE : JNI_FALSE;
88+
}
89+
5490
} // namespace
5591

5692
void TransformHelper::registerNatives() {
5793
javaClassLocal()->registerNatives({
5894
makeNativeMethod("nativeProcessTransform", processTransform),
95+
makeNativeMethod(
96+
"nativeIsAffine2DTransformWithSkew", isAffine2DTransformWithSkew),
5997
});
6098
}
6199

0 commit comments

Comments
 (0)