From 404f323359f9af469ba60132d802ffa0b2d72675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Tue, 18 Jun 2024 05:24:57 -0700 Subject: [PATCH] Set up experiment to fix the mapping of event priorities between Fabric and React (#45013) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45013 Changelog: [internal] ## Context We recently realized that in the majority of events dispatched to React from Fabric, passive effects were being mounted synchronously, blocking paint instead of in a separate task after paint. The reason for that is that in React, passive effects for discrete events are mounted synchronously by design (see https://github.com/reactwg/react-18/discussions/128), and Fabric is currently assigning the discrete event priority to most current events (including things like layout events). ## Changes This creates a feature flag to opt into a more granular control over event priorities in React Native. Instead of assigning the discrete event priority to events by default, this would assign the "default" event priority by default, except for events dispatched during continuous events that would also be considered continuous. This would also fix the priority for continuous events, that it was currently being assigned as "default" incorrectly. Reviewed By: christophpurrer, javache, sammy-SC Differential Revision: D58677191 fbshipit-source-id: c65a8dc2118ed028e1e895adec54f9072b7e55a6 --- .../featureflags/ReactNativeFeatureFlags.kt | 8 +++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 ++++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 +++++- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 ++++++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 ++- .../featureflags/ReactNativeFeatureFlags.h | 7 ++- .../ReactNativeFeatureFlagsAccessor.cpp | 46 +++++++++++++------ .../ReactNativeFeatureFlagsAccessor.h | 6 ++- .../ReactNativeFeatureFlagsDefaults.h | 6 ++- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 ++- .../NativeReactNativeFeatureFlags.h | 4 +- .../renderer/core/EventQueueProcessor.cpp | 45 +++++++++++++----- .../ReactNativeFeatureFlags.config.js | 5 ++ .../featureflags/ReactNativeFeatureFlags.js | 7 ++- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 20 files changed, 168 insertions(+), 43 deletions(-) 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 1d37426856c..ccddca4abb1 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<<177f05d7b2fadcfffa32cb5a7a21c76b>> + * @generated SignedSource<<9a33a6bc10cdb2b0f9fcb15805a06982>> */ /** @@ -94,6 +94,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableUIConsistency(): Boolean = accessor.enableUIConsistency() + /** + * Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React. + */ + @JvmStatic + public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = accessor.fixMappingOfEventPrioritiesBetweenFabricAndReact() + /** * Fixes a leak in SurfaceMountingManager.mRemoveDeleteTreeUIFrameCallback */ 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 25b762bd413..884795d8109 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<<492902f307361b8f7b7d42973561a3b4>> + * @generated SignedSource<<5d67280406c16b01ba71b7b75e814a79>> */ /** @@ -31,6 +31,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var enableMicrotasksCache: Boolean? = null private var enableSynchronousStateUpdatesCache: Boolean? = null private var enableUIConsistencyCache: Boolean? = null + private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null private var fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeakCache: Boolean? = null private var forceBatchingMountItemsOnAndroidCache: Boolean? = null private var fuseboxEnabledDebugCache: Boolean? = null @@ -144,6 +145,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean { + var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.fixMappingOfEventPrioritiesBetweenFabricAndReact() + fixMappingOfEventPrioritiesBetweenFabricAndReactCache = cached + } + return cached + } + override fun fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(): Boolean { var cached = fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeakCache 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 947512885ac..9abef85cb31 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<<05bf91e1b2a64cdc48615137deec627a>> + * @generated SignedSource<<154baea748cdf7b8e05a1e4448053673>> */ /** @@ -50,6 +50,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableUIConsistency(): Boolean + @DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean + @DoNotStrip @JvmStatic public external fun fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(): Boolean @DoNotStrip @JvmStatic public external fun forceBatchingMountItemsOnAndroid(): 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 27cf09922f0..04d17b77e8c 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<<7c95ebf976344317cd8904d71ea22fe5>> + * @generated SignedSource<<34bbd584a612fa88cc6adf2d2bc51b92>> */ /** @@ -45,6 +45,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableUIConsistency(): Boolean = false + override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false + override fun fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(): Boolean = false override fun forceBatchingMountItemsOnAndroid(): 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 f73a9f3d265..9d3d163dc48 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<> + * @generated SignedSource<> */ /** @@ -35,6 +35,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var enableMicrotasksCache: Boolean? = null private var enableSynchronousStateUpdatesCache: Boolean? = null private var enableUIConsistencyCache: Boolean? = null + private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null private var fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeakCache: Boolean? = null private var forceBatchingMountItemsOnAndroidCache: Boolean? = null private var fuseboxEnabledDebugCache: Boolean? = null @@ -159,6 +160,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean { + var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache + if (cached == null) { + cached = currentProvider.fixMappingOfEventPrioritiesBetweenFabricAndReact() + accessedFeatureFlags.add("fixMappingOfEventPrioritiesBetweenFabricAndReact") + fixMappingOfEventPrioritiesBetweenFabricAndReactCache = cached + } + return cached + } + override fun fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(): Boolean { var cached = fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeakCache if (cached == null) { 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 d4a63baf4d2..eb3e21e1278 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<> + * @generated SignedSource<> */ /** @@ -45,6 +45,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableUIConsistency(): Boolean + @DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean + @DoNotStrip public fun fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(): Boolean @DoNotStrip public fun forceBatchingMountItemsOnAndroid(): Boolean 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 9eeab79065a..d5ad1a7f1c8 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<<2af7a8ae4860f81b46e48afb17ee54b6>> + * @generated SignedSource<<88f5b83b8a3d7902eaab333246b59ed3>> */ /** @@ -105,6 +105,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("fixMappingOfEventPrioritiesBetweenFabricAndReact"); + return method(javaProvider_); + } + bool fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak"); @@ -242,6 +248,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableUIConsistency( return ReactNativeFeatureFlags::enableUIConsistency(); } +bool JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact(); +} + bool JReactNativeFeatureFlagsCxxInterop::fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(); @@ -357,6 +368,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableUIConsistency", JReactNativeFeatureFlagsCxxInterop::enableUIConsistency), + makeNativeMethod( + "fixMappingOfEventPrioritiesBetweenFabricAndReact", + JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact), makeNativeMethod( "fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak", JReactNativeFeatureFlagsCxxInterop::fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak), 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 1206b2215fb..f9e1381671a 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<<1d1422d073ae40ee4bbc788dc222cc28>> + * @generated SignedSource<<66b47850d8e211f78b3e3dd40b6cc37e>> */ /** @@ -63,6 +63,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableUIConsistency( facebook::jni::alias_ref); + static bool fixMappingOfEventPrioritiesBetweenFabricAndReact( + facebook::jni::alias_ref); + static bool fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 0d291b1b9ec..ce3f391dffb 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<> */ /** @@ -65,6 +65,10 @@ bool ReactNativeFeatureFlags::enableUIConsistency() { return getAccessor().enableUIConsistency(); } +bool ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact() { + return getAccessor().fixMappingOfEventPrioritiesBetweenFabricAndReact(); +} + bool ReactNativeFeatureFlags::fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak() { return getAccessor().fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index b809f8409f7..014c5142092 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<<5f1ae3edfe01ee0545bd89137c5cb3e9>> + * @generated SignedSource<> */ /** @@ -92,6 +92,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableUIConsistency(); + /** + * Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React. + */ + RN_EXPORT static bool fixMappingOfEventPrioritiesBetweenFabricAndReact(); + /** * Fixes a leak in SurfaceMountingManager.mRemoveDeleteTreeUIFrameCallback */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 8bca846e683..179d23099e1 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<<6d08fc8ff31f1db50cb4b14edb6b690f>> + * @generated SignedSource<<44087cc6e946a05884c8761987878183>> */ /** @@ -227,6 +227,24 @@ bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAndReact() { + auto flagValue = fixMappingOfEventPrioritiesBetweenFabricAndReact_.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(11, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + + flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); + fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak() { auto flagValue = fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak_.load(); @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::fixStoppedSurfaceRemoveDeleteTreeUIFrameCa // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak"); + markFlagAsAccessed(12, "fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak"); flagValue = currentProvider_->fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(); fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak_ = flagValue; @@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::forceBatchingMountItemsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(12, "forceBatchingMountItemsOnAndroid"); + markFlagAsAccessed(13, "forceBatchingMountItemsOnAndroid"); flagValue = currentProvider_->forceBatchingMountItemsOnAndroid(); forceBatchingMountItemsOnAndroid_ = flagValue; @@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledDebug() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(13, "fuseboxEnabledDebug"); + markFlagAsAccessed(14, "fuseboxEnabledDebug"); flagValue = currentProvider_->fuseboxEnabledDebug(); fuseboxEnabledDebug_ = flagValue; @@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(14, "fuseboxEnabledRelease"); + markFlagAsAccessed(15, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -308,7 +326,7 @@ bool ReactNativeFeatureFlagsAccessor::lazyAnimationCallbacks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(15, "lazyAnimationCallbacks"); + markFlagAsAccessed(16, "lazyAnimationCallbacks"); flagValue = currentProvider_->lazyAnimationCallbacks(); lazyAnimationCallbacks_ = flagValue; @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::preventDoubleTextMeasure() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "preventDoubleTextMeasure"); + markFlagAsAccessed(17, "preventDoubleTextMeasure"); flagValue = currentProvider_->preventDoubleTextMeasure(); preventDoubleTextMeasure_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::setAndroidLayoutDirection() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "setAndroidLayoutDirection"); + markFlagAsAccessed(18, "setAndroidLayoutDirection"); flagValue = currentProvider_->setAndroidLayoutDirection(); setAndroidLayoutDirection_ = flagValue; @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "useImmediateExecutorInAndroidBridgeless"); + markFlagAsAccessed(19, "useImmediateExecutorInAndroidBridgeless"); flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless(); useImmediateExecutorInAndroidBridgeless_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "useModernRuntimeScheduler"); + markFlagAsAccessed(20, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; @@ -398,7 +416,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(20, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(21, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "useRuntimeShadowNodeReferenceUpdate"); + markFlagAsAccessed(22, "useRuntimeShadowNodeReferenceUpdate"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); useRuntimeShadowNodeReferenceUpdate_ = flagValue; @@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdateOnLayou // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(22, "useRuntimeShadowNodeReferenceUpdateOnLayout"); + markFlagAsAccessed(23, "useRuntimeShadowNodeReferenceUpdateOnLayout"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdateOnLayout(); useRuntimeShadowNodeReferenceUpdateOnLayout_ = flagValue; @@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(23, "useStateAlignmentMechanism"); + markFlagAsAccessed(24, "useStateAlignmentMechanism"); flagValue = currentProvider_->useStateAlignmentMechanism(); useStateAlignmentMechanism_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index ac520127127..092b983a4ce 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<<3be4d7eb8694603de9fb5885562d5a78>> + * @generated SignedSource<<45258896e458cce165b403e043356eb9>> */ /** @@ -42,6 +42,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableMicrotasks(); bool enableSynchronousStateUpdates(); bool enableUIConsistency(); + bool fixMappingOfEventPrioritiesBetweenFabricAndReact(); bool fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(); bool forceBatchingMountItemsOnAndroid(); bool fuseboxEnabledDebug(); @@ -65,7 +66,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 24> accessedFeatureFlags_; + std::array, 25> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowCollapsableChildren_; @@ -78,6 +79,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableMicrotasks_; std::atomic> enableSynchronousStateUpdates_; std::atomic> enableUIConsistency_; + std::atomic> fixMappingOfEventPrioritiesBetweenFabricAndReact_; std::atomic> fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak_; std::atomic> forceBatchingMountItemsOnAndroid_; std::atomic> fuseboxEnabledDebug_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 916ed06c2aa..8af86e0d738 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<<97c824bb63734389fae8eea61b92d440>> + * @generated SignedSource<<0f6ca616cc516096ec250d61be440952>> */ /** @@ -71,6 +71,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override { + return false; + } + bool fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 3923d4b9e88..87d9985fa20 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<<454a55db4c97f9c28c0a8427d4c0bd57>> + * @generated SignedSource<<3da295d89796e905588eb863a51c2054>> */ /** @@ -36,6 +36,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableMicrotasks() = 0; virtual bool enableSynchronousStateUpdates() = 0; virtual bool enableUIConsistency() = 0; + virtual bool fixMappingOfEventPrioritiesBetweenFabricAndReact() = 0; virtual bool fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak() = 0; virtual bool forceBatchingMountItemsOnAndroid() = 0; virtual bool fuseboxEnabledDebug() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 4d6a71669d1..6951bd60316 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<<81d9543c4231939f31dc5c9bb06c942c>> + * @generated SignedSource<<82399968da4f450b87c908031466a38a>> */ /** @@ -92,6 +92,11 @@ bool NativeReactNativeFeatureFlags::enableUIConsistency( return ReactNativeFeatureFlags::enableUIConsistency(); } +bool NativeReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact(); +} + bool NativeReactNativeFeatureFlags::fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 0b16a9e99a0..2266b229203 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<<6b8504e42d72611f4d4b6606d69c42aa>> */ /** @@ -57,6 +57,8 @@ class NativeReactNativeFeatureFlags bool enableUIConsistency(jsi::Runtime& runtime); + bool fixMappingOfEventPrioritiesBetweenFabricAndReact(jsi::Runtime& runtime); + bool fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(jsi::Runtime& runtime); bool forceBatchingMountItemsOnAndroid(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventQueueProcessor.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventQueueProcessor.cpp index 6866422b17f..d8f0a2748d5 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventQueueProcessor.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventQueueProcessor.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "EventEmitter.h" #include "EventLogger.h" #include "EventQueue.h" @@ -38,20 +39,42 @@ void EventQueueProcessor::flushEvents( } for (const auto& event : events) { - if (event.category == RawEvent::Category::ContinuousEnd) { - hasContinuousEventStarted_ = false; - } + auto reactPriority = ReactEventPriority::Default; - auto reactPriority = hasContinuousEventStarted_ - ? ReactEventPriority::Default - : ReactEventPriority::Discrete; + if (ReactNativeFeatureFlags:: + fixMappingOfEventPrioritiesBetweenFabricAndReact()) { + reactPriority = [&]() { + switch (event.category) { + case RawEvent::Category::Discrete: + return ReactEventPriority::Discrete; + case RawEvent::Category::ContinuousStart: + hasContinuousEventStarted_ = true; + return ReactEventPriority::Discrete; + case RawEvent::Category::ContinuousEnd: + hasContinuousEventStarted_ = false; + return ReactEventPriority::Discrete; + case RawEvent::Category::Continuous: + return ReactEventPriority::Continuous; + case RawEvent::Category::Unspecified: + return hasContinuousEventStarted_ ? ReactEventPriority::Continuous + : ReactEventPriority::Default; + } + }(); + } else { + if (event.category == RawEvent::Category::ContinuousEnd) { + hasContinuousEventStarted_ = false; + } - if (event.category == RawEvent::Category::Continuous) { - reactPriority = ReactEventPriority::Default; - } + reactPriority = hasContinuousEventStarted_ ? ReactEventPriority::Default + : ReactEventPriority::Discrete; - if (event.category == RawEvent::Category::Discrete) { - reactPriority = ReactEventPriority::Discrete; + if (event.category == RawEvent::Category::Continuous) { + reactPriority = ReactEventPriority::Default; + } + + if (event.category == RawEvent::Category::Discrete) { + reactPriority = ReactEventPriority::Discrete; + } } auto eventLogger = eventLogger_.lock(); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 3cd9aeabda8..313fffce528 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -88,6 +88,11 @@ const definitions: FeatureFlagDefinitions = { description: 'Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution).', }, + fixMappingOfEventPrioritiesBetweenFabricAndReact: { + defaultValue: false, + description: + 'Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.', + }, fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 2554ebcc349..6bc4b7dd1ca 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<<870e25c844e692bb04ee49fe20cd3baf>> + * @generated SignedSource<> * @flow strict-local */ @@ -51,6 +51,7 @@ export type ReactNativeFeatureFlags = { enableMicrotasks: Getter, enableSynchronousStateUpdates: Getter, enableUIConsistency: Getter, + fixMappingOfEventPrioritiesBetweenFabricAndReact: Getter, fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak: Getter, forceBatchingMountItemsOnAndroid: Getter, fuseboxEnabledDebug: Getter, @@ -150,6 +151,10 @@ export const enableSynchronousStateUpdates: Getter = createNativeFlagGe * Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution). */ export const enableUIConsistency: Getter = createNativeFlagGetter('enableUIConsistency', false); +/** + * Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React. + */ +export const fixMappingOfEventPrioritiesBetweenFabricAndReact: Getter = createNativeFlagGetter('fixMappingOfEventPrioritiesBetweenFabricAndReact', false); /** * Fixes a leak in SurfaceMountingManager.mRemoveDeleteTreeUIFrameCallback */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 6d879790467..475f8fd79cf 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<<6922b452333fc62a263bd77d42afbbbe>> + * @generated SignedSource<<6715ba4954b31464c591597c53a2a0de>> * @flow strict-local */ @@ -34,6 +34,7 @@ export interface Spec extends TurboModule { +enableMicrotasks?: () => boolean; +enableSynchronousStateUpdates?: () => boolean; +enableUIConsistency?: () => boolean; + +fixMappingOfEventPrioritiesBetweenFabricAndReact?: () => boolean; +fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak?: () => boolean; +forceBatchingMountItemsOnAndroid?: () => boolean; +fuseboxEnabledDebug?: () => boolean;