From a346096da81fccf5fbc82d83bfc128695e6ec3a5 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 9 Sep 2025 14:25:02 +0100 Subject: [PATCH] [0.81] Backport `useNativeEqualsInNativeReadableArrayAndroid` and `useNativeTransformHelperAndroid` in the experimental channel (#53567) * Use native implementation of equals in ReadableNativeArray (#52611) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52611 We compare the current transform (represented as a ReadableArray) with the incoming one to know whether to invalidate. This can be expensive as it requires to materialize the entire transform data structure over JNI. Instead, we can delegate this comparison to native code, which can compare the underlying folly::dynamic directly. Changelog: [Internal] Reviewed By: NickGerleman Differential Revision: D78340288 fbshipit-source-id: f44a054e234694c316fb080fe2dbc2017780123a * Use native helpers to accelerate transform processing (#52603) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52603 Processing transforms is expensive in Java, as it requires bridging the entire ReadableNativeArray/Map. Instead, we can use the existing parser logic `resolveTransform` logic to perform this operation in C++. Ideally, we actually re-use the existing parsed transform from Props, that could be something we revisit after Props 2.0. As a follow-up, we should consider also moving the matrix decomposition logic from MatrixMathHelper here, and make that the only information we send back to Java. Changelog: [Internal] Reviewed By: NickGerleman Differential Revision: D78298588 fbshipit-source-id: a698ac8587ccfb2be04665747082398ccdde9294 * Add TransformHelper.cpp to `reactnativejni_common` (#52640) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52640 Not having `TransformHelper.cpp` included in CMake is causing the C++ code to fail compiling. This diff fixes it. Changelog: [Internal] [Changed] - Reviewed By: cipolleschi, javache Differential Revision: D78414015 fbshipit-source-id: 4900427a86eb38bfec10e5e385296d89c73e9051 * [LOCAL] Unbreak compilation due to CMake dependencies --------- Co-authored-by: Pieter De Baets --- .../react/bridge/ReadableNativeArray.kt | 10 +++- .../featureflags/ReactNativeFeatureFlags.kt | 14 ++++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 22 ++++++- .../ReactNativeFeatureFlagsCxxInterop.kt | 6 +- .../ReactNativeFeatureFlagsDefaults.kt | 6 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 24 +++++++- ...agsOverrides_RNOSS_Experimental_Android.kt | 6 +- .../ReactNativeFeatureFlagsProvider.kt | 6 +- .../react/uimanager/TransformHelper.kt | 19 ++++++ .../JReactNativeFeatureFlagsCxxInterop.cpp | 30 +++++++++- .../JReactNativeFeatureFlagsCxxInterop.h | 8 ++- .../src/main/jni/react/jni/CMakeLists.txt | 3 +- .../src/main/jni/react/jni/NativeArray.h | 4 ++ .../src/main/jni/react/jni/OnLoad-common.cpp | 2 + .../jni/react/jni/ReadableNativeArray.cpp | 6 ++ .../main/jni/react/jni/ReadableNativeArray.h | 1 + .../main/jni/react/jni/TransformHelper.cpp | 60 +++++++++++++++++++ .../src/main/jni/react/jni/TransformHelper.h | 22 +++++++ .../featureflags/ReactNativeFeatureFlags.cpp | 10 +++- .../featureflags/ReactNativeFeatureFlags.h | 12 +++- .../ReactNativeFeatureFlagsAccessor.cpp | 52 +++++++++++++--- .../ReactNativeFeatureFlagsAccessor.h | 8 ++- .../ReactNativeFeatureFlagsDefaults.h | 10 +++- .../ReactNativeFeatureFlagsDynamicProvider.h | 20 ++++++- ...tiveFeatureFlagsOverridesOSSExperimental.h | 10 +++- .../ReactNativeFeatureFlagsProvider.h | 4 +- .../NativeReactNativeFeatureFlags.cpp | 12 +++- .../NativeReactNativeFeatureFlags.h | 6 +- .../components/view/BaseViewProps.cpp | 10 +++- .../renderer/components/view/BaseViewProps.h | 5 ++ .../ReactNativeFeatureFlags.config.js | 21 +++++++ .../featureflags/ReactNativeFeatureFlags.js | 12 +++- .../specs/NativeReactNativeFeatureFlags.js | 4 +- 33 files changed, 412 insertions(+), 33 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.cpp create mode 100644 packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.h diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.kt index 22be6e092cd..764dec3d0fb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.kt @@ -8,6 +8,7 @@ package com.facebook.react.bridge import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags import java.util.ArrayList import java.util.Arrays import kotlin.jvm.JvmStatic @@ -65,9 +66,16 @@ public open class ReadableNativeArray protected constructor() : NativeArray(), R if (other !is ReadableNativeArray) { return false } - return localArray.contentDeepEquals(other.localArray) + + return if (ReactNativeFeatureFlags.useNativeEqualsInNativeReadableArrayAndroid()) { + nativeEquals(other) + } else { + localArray.contentDeepEquals(other.localArray) + } } + private external fun nativeEquals(other: ReadableNativeArray): Boolean + override fun toArrayList(): ArrayList { val arrayList = ArrayList() repeat(size()) { i -> diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index b2fb68f5d37..8a10052cd03 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<3e4d74a17c15742d35db9e4247f3e1c1>> + * @generated SignedSource<> */ /** @@ -342,6 +342,18 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun useFabricInterop(): Boolean = accessor.useFabricInterop() + /** + * Use a native implementation of equals in NativeReadableArray. + */ + @JvmStatic + public fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean = accessor.useNativeEqualsInNativeReadableArrayAndroid() + + /** + * Use a native implementation of TransformHelper + */ + @JvmStatic + public fun useNativeTransformHelperAndroid(): Boolean = accessor.useNativeTransformHelperAndroid() + /** * When enabled, the native view configs are used in bridgeless mode. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index 9edc477ef4f..4c31c559aa4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<8e0125e82b359e6a175ffc49a4df5537>> */ /** @@ -72,6 +72,8 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null private var useFabricInteropCache: Boolean? = null + private var useNativeEqualsInNativeReadableArrayAndroidCache: Boolean? = null + private var useNativeTransformHelperAndroidCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null private var useRawPropsJsiValueCache: Boolean? = null @@ -548,6 +550,24 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean { + var cached = useNativeEqualsInNativeReadableArrayAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.useNativeEqualsInNativeReadableArrayAndroid() + useNativeEqualsInNativeReadableArrayAndroidCache = cached + } + return cached + } + + override fun useNativeTransformHelperAndroid(): Boolean { + var cached = useNativeTransformHelperAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.useNativeTransformHelperAndroid() + useNativeTransformHelperAndroidCache = cached + } + return cached + } + override fun useNativeViewConfigsInBridgelessMode(): Boolean { var cached = useNativeViewConfigsInBridgelessModeCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index afd221a4bf2..915e42883fc 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -132,6 +132,10 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun useFabricInterop(): Boolean + @DoNotStrip @JvmStatic public external fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean + + @DoNotStrip @JvmStatic public external fun useNativeTransformHelperAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun useNativeViewConfigsInBridgelessMode(): Boolean @DoNotStrip @JvmStatic public external fun useOptimizedEventBatchingOnAndroid(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index e59da172aba..70dc144b28f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<12c2727291b635ef7c3163d153669c2c>> + * @generated SignedSource<<10d708ce4449eede46d750a1ed48d02e>> */ /** @@ -127,6 +127,10 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun useFabricInterop(): Boolean = true + override fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean = false + + override fun useNativeTransformHelperAndroid(): Boolean = false + override fun useNativeViewConfigsInBridgelessMode(): Boolean = false override fun useOptimizedEventBatchingOnAndroid(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index baa7b54af77..b5aa6b46dd7 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<3ea9946ef21c8ac8bb9bb63712636e89>> + * @generated SignedSource<> */ /** @@ -76,6 +76,8 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null private var useFabricInteropCache: Boolean? = null + private var useNativeEqualsInNativeReadableArrayAndroidCache: Boolean? = null + private var useNativeTransformHelperAndroidCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null private var useRawPropsJsiValueCache: Boolean? = null @@ -604,6 +606,26 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean { + var cached = useNativeEqualsInNativeReadableArrayAndroidCache + if (cached == null) { + cached = currentProvider.useNativeEqualsInNativeReadableArrayAndroid() + accessedFeatureFlags.add("useNativeEqualsInNativeReadableArrayAndroid") + useNativeEqualsInNativeReadableArrayAndroidCache = cached + } + return cached + } + + override fun useNativeTransformHelperAndroid(): Boolean { + var cached = useNativeTransformHelperAndroidCache + if (cached == null) { + cached = currentProvider.useNativeTransformHelperAndroid() + accessedFeatureFlags.add("useNativeTransformHelperAndroid") + useNativeTransformHelperAndroidCache = cached + } + return cached + } + override fun useNativeViewConfigsInBridgelessMode(): Boolean { var cached = useNativeViewConfigsInBridgelessModeCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt index 2d32fcd900e..1b8ad3bdc5c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<58da46268043f086730132430735b720>> + * @generated SignedSource<<0bafb0a2fb79c4220d21f1736894af14>> */ /** @@ -24,4 +24,8 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android : // but that is more expensive than just duplicating the defaults here. override fun preventShadowTreeCommitExhaustion(): Boolean = true + + override fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean = true + + override fun useNativeTransformHelperAndroid(): Boolean = true } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 1da19692aed..de14fb57768 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1e81de36735c6c9286b228c75c9a0228>> + * @generated SignedSource<<21704207ce520def05b05f89dfba1048>> */ /** @@ -127,6 +127,10 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun useFabricInterop(): Boolean + @DoNotStrip public fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean + + @DoNotStrip public fun useNativeTransformHelperAndroid(): Boolean + @DoNotStrip public fun useNativeViewConfigsInBridgelessMode(): Boolean @DoNotStrip public fun useOptimizedEventBatchingOnAndroid(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt index 88313b35fea..f72ab667427 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt @@ -8,10 +8,12 @@ package com.facebook.react.uimanager import com.facebook.common.logging.FLog +import com.facebook.react.bridge.NativeArray import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.ReadableType import com.facebook.react.common.ReactConstants +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags public object TransformHelper { @@ -69,6 +71,14 @@ public object TransformHelper { transformOrigin: ReadableArray?, allowPercentageResolution: Boolean ) { + if (allowPercentageResolution && + ReactNativeFeatureFlags.useNativeTransformHelperAndroid() && + transforms is NativeArray && + transformOrigin is NativeArray?) { + nativeProcessTransform(transforms, result, viewWidth, viewHeight, transformOrigin) + return + } + val helperMatrix = helperMatrix.get()!! MatrixMathHelper.resetIdentityMatrix(result) val offsets = @@ -220,4 +230,13 @@ public object TransformHelper { return doubleArrayOf(newTranslateX, newTranslateY, newTranslateZ) } + + @JvmStatic + private external fun nativeProcessTransform( + transforms: NativeArray, + result: DoubleArray, + viewWidth: Float, + viewHeight: Float, + transformOrigin: NativeArray? + ) } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index 0bcbbc10fc9..5ae6ba010df 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -351,6 +351,18 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool useNativeEqualsInNativeReadableArrayAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useNativeEqualsInNativeReadableArrayAndroid"); + return method(javaProvider_); + } + + bool useNativeTransformHelperAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useNativeTransformHelperAndroid"); + return method(javaProvider_); + } + bool useNativeViewConfigsInBridgelessMode() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useNativeViewConfigsInBridgelessMode"); @@ -657,6 +669,16 @@ bool JReactNativeFeatureFlagsCxxInterop::useFabricInterop( return ReactNativeFeatureFlags::useFabricInterop(); } +bool JReactNativeFeatureFlagsCxxInterop::useNativeEqualsInNativeReadableArrayAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid(); +} + +bool JReactNativeFeatureFlagsCxxInterop::useNativeTransformHelperAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::useNativeTransformHelperAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::useNativeViewConfigsInBridgelessMode( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode(); @@ -879,6 +901,12 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "useFabricInterop", JReactNativeFeatureFlagsCxxInterop::useFabricInterop), + makeNativeMethod( + "useNativeEqualsInNativeReadableArrayAndroid", + JReactNativeFeatureFlagsCxxInterop::useNativeEqualsInNativeReadableArrayAndroid), + makeNativeMethod( + "useNativeTransformHelperAndroid", + JReactNativeFeatureFlagsCxxInterop::useNativeTransformHelperAndroid), makeNativeMethod( "useNativeViewConfigsInBridgelessMode", JReactNativeFeatureFlagsCxxInterop::useNativeViewConfigsInBridgelessMode), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index 42312d4bf22..a04ebe7fc0e 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<57f2dcf4b71512c6b15e8021258d6036>> */ /** @@ -186,6 +186,12 @@ class JReactNativeFeatureFlagsCxxInterop static bool useFabricInterop( facebook::jni::alias_ref); + static bool useNativeEqualsInNativeReadableArrayAndroid( + facebook::jni::alias_ref); + + static bool useNativeTransformHelperAndroid( + facebook::jni::alias_ref); + static bool useNativeViewConfigsInBridgelessMode( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt index f315cca6dd1..61cc16c0834 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt @@ -31,13 +31,14 @@ add_library( OnLoad-common.cpp ReadableNativeArray.cpp ReadableNativeMap.cpp + TransformHelper.cpp WritableNativeArray.cpp WritableNativeMap.cpp ) target_merge_so(reactnativejni_common) target_include_directories(reactnativejni_common PUBLIC ../../) -target_link_libraries(reactnativejni_common fbjni folly_runtime react_cxxreact) +target_link_libraries(reactnativejni_common fbjni folly_runtime react_cxxreact yoga react_renderer_graphics) target_compile_reactnative_options(reactnativejni_common PRIVATE) target_compile_options(reactnativejni_common PRIVATE -Wno-unused-lambda-capture) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h index c7087485521..738738437b0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h @@ -21,6 +21,10 @@ class NativeArray : public jni::HybridClass { jni::local_ref toString(); + const folly::dynamic& getArray() const { + return array_; + } + RN_EXPORT folly::dynamic consume(); // Whether this array has been added to another array or map and no longer diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp index 293d2ffc8ab..ef069ed7e41 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp @@ -11,6 +11,7 @@ #include "JReactMarker.h" #include "NativeArray.h" #include "NativeMap.h" +#include "TransformHelper.h" #include "WritableNativeArray.h" #include "WritableNativeMap.h" @@ -27,6 +28,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { ReadableNativeMap::registerNatives(); WritableNativeArray::registerNatives(); WritableNativeMap::registerNatives(); + TransformHelper::registerNatives(); }); } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp index 9add683e2a4..bdc4d6bbbbb 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp @@ -40,10 +40,16 @@ local_ref> ReadableNativeArray::importTypeArray() { return jarray; } +bool ReadableNativeArray::equals( + jni::alias_ref other) { + return array_ == other->cthis()->array_; +} + void ReadableNativeArray::registerNatives() { registerHybrid({ makeNativeMethod("importArray", ReadableNativeArray::importArray), makeNativeMethod("importTypeArray", ReadableNativeArray::importTypeArray), + makeNativeMethod("nativeEquals", ReadableNativeArray::equals), }); } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h index 02d9445192e..1ab3243ad12 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h @@ -35,6 +35,7 @@ class ReadableNativeArray static void mapException(std::exception_ptr ex); static void registerNatives(); + bool equals(jni::alias_ref other); jni::local_ref> importArray(); jni::local_ref> importTypeArray(); }; diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.cpp new file mode 100644 index 00000000000..b33d269ac29 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TransformHelper.h" + +#include +#include + +#include "NativeArray.h" + +using namespace facebook::jni; + +namespace facebook::react { + +namespace { +void processTransform( + jni::alias_ref /*unused*/, + NativeArray* jTransforms, + jni::alias_ref jResult, + float viewWidth, + float viewHeight, + NativeArray* jTransformOrigin) { + // Assuming parsing transforms doesn't require a real PropsParserContext + static ContextContainer contextContainer; + static PropsParserContext context(0, contextContainer); + + RawValue transformValue(jTransforms->getArray()); + Transform transform; + fromRawValue(context, transformValue, transform); + + TransformOrigin transformOrigin; + if (jTransformOrigin != nullptr) { + RawValue transformOriginValue(jTransformOrigin->getArray()); + fromRawValue(context, transformOriginValue, transformOrigin); + } + + auto result = BaseViewProps::resolveTransform( + Size(viewWidth, viewHeight), transform, transformOrigin); + + // Convert from matrix of floats to double matrix + constexpr size_t MatrixSize = std::tuple_size_v; + std::array doubleTransform{}; + std::copy( + result.matrix.begin(), result.matrix.end(), doubleTransform.begin()); + jResult->setRegion(0, MatrixSize, doubleTransform.data()); +} + +} // namespace + +void TransformHelper::registerNatives() { + javaClassLocal()->registerNatives({ + makeNativeMethod("nativeProcessTransform", processTransform), + }); +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.h new file mode 100644 index 00000000000..342a8ee1100 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/TransformHelper.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook::react { + +class TransformHelper : public jni::JavaClass { + public: + static auto constexpr* kJavaDescriptor = + "Lcom/facebook/react/uimanager/TransformHelper;"; + + static void registerNatives(); +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 1feef568183..667aec1cb3f 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<2cabd888b74b84201ff027457efc6007>> */ /** @@ -234,6 +234,14 @@ bool ReactNativeFeatureFlags::useFabricInterop() { return getAccessor().useFabricInterop(); } +bool ReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid() { + return getAccessor().useNativeEqualsInNativeReadableArrayAndroid(); +} + +bool ReactNativeFeatureFlags::useNativeTransformHelperAndroid() { + return getAccessor().useNativeTransformHelperAndroid(); +} + bool ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode() { return getAccessor().useNativeViewConfigsInBridgelessMode(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 6663518acd8..564d82bba30 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -299,6 +299,16 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool useFabricInterop(); + /** + * Use a native implementation of equals in NativeReadableArray. + */ + RN_EXPORT static bool useNativeEqualsInNativeReadableArrayAndroid(); + + /** + * Use a native implementation of TransformHelper + */ + RN_EXPORT static bool useNativeTransformHelperAndroid(); + /** * When enabled, the native view configs are used in bridgeless mode. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 877131981d2..d3b0351a093 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<681bff71eb87886a108f67b3162b030c>> + * @generated SignedSource<<7ae9a203a94e3a22197bc9eda69b741c>> */ /** @@ -965,6 +965,42 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::useNativeEqualsInNativeReadableArrayAndroid() { + auto flagValue = useNativeEqualsInNativeReadableArrayAndroid_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(52, "useNativeEqualsInNativeReadableArrayAndroid"); + + flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid(); + useNativeEqualsInNativeReadableArrayAndroid_ = flagValue; + } + + return flagValue.value(); +} + +bool ReactNativeFeatureFlagsAccessor::useNativeTransformHelperAndroid() { + auto flagValue = useNativeTransformHelperAndroid_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(53, "useNativeTransformHelperAndroid"); + + flagValue = currentProvider_->useNativeTransformHelperAndroid(); + useNativeTransformHelperAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { auto flagValue = useNativeViewConfigsInBridgelessMode_.load(); @@ -974,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(52, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(54, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -992,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(53, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(55, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -1010,7 +1046,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(54, "useRawPropsJsiValue"); + markFlagAsAccessed(56, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -1028,7 +1064,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(55, "useShadowNodeStateOnClone"); + markFlagAsAccessed(57, "useShadowNodeStateOnClone"); flagValue = currentProvider_->useShadowNodeStateOnClone(); useShadowNodeStateOnClone_ = flagValue; @@ -1046,7 +1082,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(56, "useTurboModuleInterop"); + markFlagAsAccessed(58, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -1064,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(57, "useTurboModules"); + markFlagAsAccessed(59, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; @@ -1082,7 +1118,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(58, "virtualViewPrerenderRatio"); + markFlagAsAccessed(60, "virtualViewPrerenderRatio"); flagValue = currentProvider_->virtualViewPrerenderRatio(); virtualViewPrerenderRatio_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index c71e8133664..8e2acc5b241 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<74560113d0b23c05d7822eeba1c0dee4>> */ /** @@ -84,6 +84,8 @@ class ReactNativeFeatureFlagsAccessor { bool updateRuntimeShadowNodeReferencesOnCommit(); bool useAlwaysAvailableJSErrorHandling(); bool useFabricInterop(); + bool useNativeEqualsInNativeReadableArrayAndroid(); + bool useNativeTransformHelperAndroid(); bool useNativeViewConfigsInBridgelessMode(); bool useOptimizedEventBatchingOnAndroid(); bool useRawPropsJsiValue(); @@ -102,7 +104,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 59> accessedFeatureFlags_; + std::array, 61> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> animatedShouldSignalBatch_; @@ -156,6 +158,8 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> updateRuntimeShadowNodeReferencesOnCommit_; std::atomic> useAlwaysAvailableJSErrorHandling_; std::atomic> useFabricInterop_; + std::atomic> useNativeEqualsInNativeReadableArrayAndroid_; + std::atomic> useNativeTransformHelperAndroid_; std::atomic> useNativeViewConfigsInBridgelessMode_; std::atomic> useOptimizedEventBatchingOnAndroid_; std::atomic> useRawPropsJsiValue_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 0dc1de80ced..e0742c9c5c9 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<9832c18e4c7ccf232b7222e2356f99d9>> + * @generated SignedSource<<1a54000b8eb51cb91304902c7f722d45>> */ /** @@ -235,6 +235,14 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return true; } + bool useNativeEqualsInNativeReadableArrayAndroid() override { + return false; + } + + bool useNativeTransformHelperAndroid() override { + return false; + } + bool useNativeViewConfigsInBridgelessMode() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 46ec128d23b..f5c85f530a4 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<19f0a48bcfa8f8ffaf634e85301adc7e>> + * @generated SignedSource<<244db790cc754f31402981967cd902b5>> */ /** @@ -513,6 +513,24 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::useFabricInterop(); } + bool useNativeEqualsInNativeReadableArrayAndroid() override { + auto value = values_["useNativeEqualsInNativeReadableArrayAndroid"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::useNativeEqualsInNativeReadableArrayAndroid(); + } + + bool useNativeTransformHelperAndroid() override { + auto value = values_["useNativeTransformHelperAndroid"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::useNativeTransformHelperAndroid(); + } + bool useNativeViewConfigsInBridgelessMode() override { auto value = values_["useNativeViewConfigsInBridgelessMode"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h index c45e55ce07a..230dc476cef 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -30,6 +30,14 @@ class ReactNativeFeatureFlagsOverridesOSSExperimental : public ReactNativeFeatur bool preventShadowTreeCommitExhaustion() override { return true; } + + bool useNativeEqualsInNativeReadableArrayAndroid() override { + return true; + } + + bool useNativeTransformHelperAndroid() override { + return true; + } }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 3df0f3be4a1..e9dd92d9494 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<815769cc8d08e19b2598dd1862ed5060>> + * @generated SignedSource<<2387ed12fe46fb5b606ad13a17511f03>> */ /** @@ -77,6 +77,8 @@ class ReactNativeFeatureFlagsProvider { virtual bool updateRuntimeShadowNodeReferencesOnCommit() = 0; virtual bool useAlwaysAvailableJSErrorHandling() = 0; virtual bool useFabricInterop() = 0; + virtual bool useNativeEqualsInNativeReadableArrayAndroid() = 0; + virtual bool useNativeTransformHelperAndroid() = 0; virtual bool useNativeViewConfigsInBridgelessMode() = 0; virtual bool useOptimizedEventBatchingOnAndroid() = 0; virtual bool useRawPropsJsiValue() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index cda934866a5..1e9e0ffc9b2 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<474a64af739969acebb4bb9bb1005168>> + * @generated SignedSource<<45e1b08fd2438b27af82591b5cfa5744>> */ /** @@ -304,6 +304,16 @@ bool NativeReactNativeFeatureFlags::useFabricInterop( return ReactNativeFeatureFlags::useFabricInterop(); } +bool NativeReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid(); +} + +bool NativeReactNativeFeatureFlags::useNativeTransformHelperAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::useNativeTransformHelperAndroid(); +} + bool NativeReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 5696d5a7c7f..bc8014a5d80 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -140,6 +140,10 @@ class NativeReactNativeFeatureFlags bool useFabricInterop(jsi::Runtime& runtime); + bool useNativeEqualsInNativeReadableArrayAndroid(jsi::Runtime& runtime); + + bool useNativeTransformHelperAndroid(jsi::Runtime& runtime); + bool useNativeViewConfigsInBridgelessMode(jsi::Runtime& runtime); bool useOptimizedEventBatchingOnAndroid(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp index 690aedc3501..5bf3c6e4179 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp @@ -550,6 +550,13 @@ BorderMetrics BaseViewProps::resolveBorderMetrics( Transform BaseViewProps::resolveTransform( const LayoutMetrics& layoutMetrics) const { const auto& frameSize = layoutMetrics.frame.size; + return resolveTransform(frameSize, transform, transformOrigin); +} + +Transform BaseViewProps::resolveTransform( + const Size& frameSize, + const Transform& transform, + const TransformOrigin& transformOrigin) { auto transformMatrix = Transform{}; if (frameSize.width == 0 && frameSize.height == 0) { return transformMatrix; @@ -562,8 +569,7 @@ Transform BaseViewProps::resolveTransform( } else { for (const auto& operation : transform.operations) { transformMatrix = transformMatrix * - Transform::FromTransformOperation( - operation, layoutMetrics.frame.size, transform); + Transform::FromTransformOperation(operation, frameSize, transform); } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h index f7e56418ef0..6258d1375da 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h @@ -115,6 +115,11 @@ class BaseViewProps : public YogaStylableProps, public AccessibilityProps { Transform resolveTransform(const LayoutMetrics& layoutMetrics) const; bool getClipsContentToBounds() const; + static Transform resolveTransform( + const Size& frameSize, + const Transform& transform, + const TransformOrigin& transformOrigin); + #if RN_DEBUG_STRING_CONVERTIBLE SharedDebugStringConvertibleList getDebugProps() const override; #endif diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 7bb81fa3bf0..feb33a2d55d 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -595,6 +595,27 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + useNativeEqualsInNativeReadableArrayAndroid: { + defaultValue: false, + metadata: { + dateAdded: '2025-07-15', + description: + 'Use a native implementation of equals in NativeReadableArray.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'experimental', + }, + useNativeTransformHelperAndroid: { + defaultValue: false, + metadata: { + dateAdded: '2025-07-15', + description: 'Use a native implementation of TransformHelper', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'experimental', + }, useNativeViewConfigsInBridgelessMode: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index ee5043e87bc..108ed513497 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<999a8d329cdab258ac64c03b24f1a516>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -103,6 +103,8 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ updateRuntimeShadowNodeReferencesOnCommit: Getter, useAlwaysAvailableJSErrorHandling: Getter, useFabricInterop: Getter, + useNativeEqualsInNativeReadableArrayAndroid: Getter, + useNativeTransformHelperAndroid: Getter, useNativeViewConfigsInBridgelessMode: Getter, useOptimizedEventBatchingOnAndroid: Getter, useRawPropsJsiValue: Getter, @@ -404,6 +406,14 @@ export const useAlwaysAvailableJSErrorHandling: Getter = createNativeFl * Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly. */ export const useFabricInterop: Getter = createNativeFlagGetter('useFabricInterop', true); +/** + * Use a native implementation of equals in NativeReadableArray. + */ +export const useNativeEqualsInNativeReadableArrayAndroid: Getter = createNativeFlagGetter('useNativeEqualsInNativeReadableArrayAndroid', false); +/** + * Use a native implementation of TransformHelper + */ +export const useNativeTransformHelperAndroid: Getter = createNativeFlagGetter('useNativeTransformHelperAndroid', false); /** * When enabled, the native view configs are used in bridgeless mode. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index e64f0920b3e..4558b60203c 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1b84b6e04c214f6c2798010372937990>> + * @generated SignedSource<<8b4f1275a16d5b83f5594da1eb89c6c1>> * @flow strict * @noformat */ @@ -77,6 +77,8 @@ export interface Spec extends TurboModule { +updateRuntimeShadowNodeReferencesOnCommit?: () => boolean; +useAlwaysAvailableJSErrorHandling?: () => boolean; +useFabricInterop?: () => boolean; + +useNativeEqualsInNativeReadableArrayAndroid?: () => boolean; + +useNativeTransformHelperAndroid?: () => boolean; +useNativeViewConfigsInBridgelessMode?: () => boolean; +useOptimizedEventBatchingOnAndroid?: () => boolean; +useRawPropsJsiValue?: () => boolean;