diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h index 70a56433d57b..83ef0e245856 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h @@ -69,6 +69,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag changedProps:(folly::dynamic)props componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor; + +- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag withProps:(facebook::react::Props::Shared)newProps; @end NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm index 68662f06d59b..7fb299d2b373 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm @@ -330,6 +330,41 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag [componentView finalizeUpdates:RNComponentViewUpdateMaskProps]; } +- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag withProps:(Props::Shared)newProps +{ + RCTAssertMainQueue(); + + UIView *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag]; + if (!componentView) { + RCTLogWarn(@"Attempted to update view with tag %ld, but it no longer exists", (long)reactTag); + return; + } + + NSSet *propKeys = componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN ?: [NSSet new]; + + Props::Shared oldProps = [componentView props]; + + componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = nil; + [componentView updateProps:newProps oldProps:oldProps]; + componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = propKeys; + + const auto &newViewProps = static_cast(*newProps); + + if (componentView.layer.opacity != (float)newViewProps.opacity) { + componentView.layer.opacity = newViewProps.opacity; + } + + auto layoutMetrics = LayoutMetrics(); + layoutMetrics.frame.size.width = componentView.layer.bounds.size.width; + layoutMetrics.frame.size.height = componentView.layer.bounds.size.height; + CATransform3D newTransform = RCTCATransform3DFromTransformMatrix(newViewProps.resolveTransform(layoutMetrics)); + if (!CATransform3DEqualToTransform(newTransform, componentView.layer.transform)) { + componentView.layer.transform = newTransform; + } + + [componentView finalizeUpdates:RNComponentViewUpdateMaskProps]; +} + - (void)synchronouslyDispatchCommandOnUIThread:(ReactTag)reactTag commandName:(NSString *)commandName args:(NSArray *)args diff --git a/packages/react-native/React/Fabric/RCTScheduler.h b/packages/react-native/React/Fabric/RCTScheduler.h index 8b809580c10c..1c20d2c7c9de 100644 --- a/packages/react-native/React/Fabric/RCTScheduler.h +++ b/packages/react-native/React/Fabric/RCTScheduler.h @@ -19,6 +19,10 @@ #import #import +namespace facebook::react { +struct AnimatedProps; +} // namespace facebook::react + NS_ASSUME_NONNULL_BEGIN /** @@ -45,6 +49,11 @@ NS_ASSUME_NONNULL_BEGIN forShadowView:(const facebook::react::ShadowView &)shadowView; - (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(facebook::react::Tag)reactTag props:(folly::dynamic)props; + +- (void)schedulerDidSynchronouslyUpdateViewWithAnimatedPropsOnUIThread:(facebook::react::Tag)reactTag + surfaceId:(facebook::react::SurfaceId)surfaceId + animatedProps: + (const facebook::react::AnimatedProps &)animatedProps; @end /** diff --git a/packages/react-native/React/Fabric/RCTScheduler.mm b/packages/react-native/React/Fabric/RCTScheduler.mm index 9519f18428e4..3e5fff212efc 100644 --- a/packages/react-native/React/Fabric/RCTScheduler.mm +++ b/packages/react-native/React/Fabric/RCTScheduler.mm @@ -10,6 +10,7 @@ #import #import #import +#import #import #import #import @@ -79,6 +80,18 @@ void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, [scheduler.delegate schedulerDidSynchronouslyUpdateViewOnUIThread:tag props:props]; } + void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates) override + { + RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; + for (const auto &[tag, animatedProps] : updates) { + [scheduler.delegate schedulerDidSynchronouslyUpdateViewWithAnimatedPropsOnUIThread:tag + surfaceId:surfaceId + animatedProps:animatedProps]; + } + } + void schedulerDidUpdateShadowTree(const std::unordered_map &tagToProps) override { // Does nothing. diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm index ab8f3c490780..ad8b46f2864d 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm +++ b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm @@ -28,8 +28,10 @@ #import #import +#import #import #import +#import #import #import #import @@ -416,6 +418,44 @@ - (void)schedulerDidSetIsJSResponder:(BOOL)isJSResponder [_mountingManager setIsJSResponder:isJSResponder blockNativeResponder:blockNativeResponder forShadowView:shadowView]; } +- (void)schedulerDidSynchronouslyUpdateViewWithAnimatedPropsOnUIThread:(Tag)tag + surfaceId:(SurfaceId)surfaceId + animatedProps:(const AnimatedProps &)animatedProps +{ + RCTScheduler *scheduler = [self scheduler]; + if (!scheduler) { + return; + } + + UIView *componentView = + [_mountingManager.componentViewRegistry findComponentViewWithTag:tag]; + if (componentView == nil) { + return; + } + ComponentHandle handle = [[componentView class] componentDescriptorProvider].handle; + auto *componentDescriptor = [scheduler findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN:handle]; + if (!componentDescriptor) { + return; + } + + Props::Shared oldProps = [componentView props]; + PropsParserContext propsParserContext{surfaceId, *[self contextContainer]}; + + Props::Shared newProps; + if (animatedProps.rawProps) { + newProps = componentDescriptor->cloneProps(propsParserContext, oldProps, RawProps(*animatedProps.rawProps)); + } else { + newProps = componentDescriptor->cloneProps(propsParserContext, oldProps, RawProps{}); + } + + auto viewProps = std::const_pointer_cast(std::static_pointer_cast(newProps)); + for (auto &animatedProp : animatedProps.props) { + cloneProp(*viewProps, *animatedProp); + } + + [_mountingManager synchronouslyUpdateViewOnUIThread:tag withProps:newProps]; +} + - (void)addObserver:(id)observer { std::unique_lock lock(_observerListMutex); diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index cc3f6b5e9448..e602fb793644 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2267,6 +2267,7 @@ public class com/facebook/react/fabric/FabricUIManager : com/facebook/react/brid public fun stopSurface (I)V public fun stopSurface (Lcom/facebook/react/fabric/SurfaceHandlerBinding;)V public fun sweepActiveTouchForTag (II)V + public fun synchronouslyUpdateViewBatch ([I[D)V public fun synchronouslyUpdateViewOnUIThread (ILcom/facebook/react/bridge/ReadableMap;)V public fun updateRootLayoutSpecs (IIIII)V } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 2a0baaeace09..f2c9771e63e4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -61,6 +61,7 @@ import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.react.fabric.mounting.SurfaceMountingManager; import com.facebook.react.fabric.mounting.mountitems.BatchMountItem; +import com.facebook.react.fabric.mounting.mountitems.BatchedAnimatedPropsMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.MountItem; import com.facebook.react.fabric.mounting.mountitems.MountItemFactory; @@ -858,6 +859,16 @@ private synchronized ViewTransitionSnapshotManager getViewTransitionSnapshotMana return mViewTransitionSnapshotManager; } + @SuppressWarnings("unused") + @UiThread + @ThreadConfined(UI) + public void synchronouslyUpdateViewBatch(final int[] intBuffer, final double[] doubleBuffer) { + UiThreadUtil.assertOnUiThread(); + + MountItem mountItem = new BatchedAnimatedPropsMountItem(intBuffer, doubleBuffer); + mountItem.execute(mMountingManager); + } + @SuppressLint("NotInvokedPrivateMethod") @SuppressWarnings("unused") @AnyThread diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchedAnimatedPropsMountItem.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchedAnimatedPropsMountItem.kt new file mode 100644 index 000000000000..2c8c0132f61a --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchedAnimatedPropsMountItem.kt @@ -0,0 +1,299 @@ +/* + * 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. + */ + +package com.facebook.react.fabric.mounting.mountitems + +import android.view.View +import com.facebook.react.bridge.JavaOnlyArray +import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.fabric.mounting.MountingManager +import com.facebook.react.uimanager.ViewProps + +/** + * A [MountItem] that decodes a batched buffer of animated prop updates and applies them + * synchronously. The buffer protocol encodes multiple per-view prop updates into compact int/double + * arrays, which this mount item decodes into [JavaOnlyMap] props and applies via + * [MountingManager.updatePropsSynchronously]. + */ +internal class BatchedAnimatedPropsMountItem( + private val intBuffer: IntArray, + private val doubleBuffer: DoubleArray, +) : MountItem { + + override fun execute(mountingManager: MountingManager) { + var intIdx = 0 + var doubleIdx = 0 + while (intIdx < intBuffer.size) { + val command = intBuffer[intIdx++] + if (command != CMD_START_OF_VIEW) { + break + } + val viewTag = intBuffer[intIdx++] + val props = JavaOnlyMap() + + while (intIdx < intBuffer.size) { + val cmd = intBuffer[intIdx++] + if (cmd == CMD_END_OF_VIEW) { + break + } + + when (cmd) { + in CMD_OPACITY..CMD_SHADOW_RADIUS -> + props.putDouble(commandToString(cmd), doubleBuffer[doubleIdx++]) + in CMD_BACKGROUND_COLOR..CMD_TINT_COLOR, + in CMD_BORDER_COLOR..CMD_BORDER_END_COLOR -> + props.putInt(commandToString(cmd), intBuffer[intIdx++]) + in CMD_BORDER_RADIUS..CMD_BORDER_END_END_RADIUS -> { + // Border radius: value in doubleBuffer, unit in intBuffer + val value = doubleBuffer[doubleIdx++] + val unit = intBuffer[intIdx++] + if (unit == CMD_UNIT_PX) { + props.putDouble(commandToString(cmd), value) + } else if (unit == CMD_UNIT_PERCENT) { + props.putString(commandToString(cmd), "$value%") + } + } + CMD_START_OF_TRANSFORM -> { + val transform = JavaOnlyArray() + while (intIdx < intBuffer.size) { + val transformCmd = intBuffer[intIdx++] + if (transformCmd == CMD_END_OF_TRANSFORM) { + props.putArray(ViewProps.TRANSFORM, transform) + break + } + val name = transformCommandToString(transformCmd) + when (transformCmd) { + in CMD_SCALE..CMD_SCALE_Y, + CMD_PERSPECTIVE -> { + val entry = JavaOnlyMap() + entry.putDouble(name, doubleBuffer[doubleIdx++]) + transform.pushMap(entry) + } + in CMD_TRANSLATE_X..CMD_TRANSLATE_Y -> { + val value = doubleBuffer[doubleIdx++] + val unitCmd = intBuffer[intIdx++] + val entry = JavaOnlyMap() + if (unitCmd == CMD_UNIT_PX) { + entry.putDouble(name, value) + } else { + entry.putString(name, "$value%") + } + transform.pushMap(entry) + } + in CMD_ROTATE..CMD_SKEW_Y -> { + val angle = doubleBuffer[doubleIdx++] + val unitCmd = intBuffer[intIdx++] + val unitStr = if (unitCmd == CMD_UNIT_DEG) "deg" else "rad" + val entry = JavaOnlyMap() + entry.putString(name, "$angle$unitStr") + transform.pushMap(entry) + } + CMD_MATRIX -> { + // matrix + val size = intBuffer[intIdx++] + val matrix = JavaOnlyArray() + for (m in 0 until size) { + matrix.pushDouble(doubleBuffer[doubleIdx++]) + } + val entry = JavaOnlyMap() + entry.putArray(name, matrix) + transform.pushMap(entry) + } + } + } + } + } + } + + try { + mountingManager.updatePropsSynchronously(viewTag, props) + } catch (ex: Exception) { + // Same surface-teardown race as in SynchronousMountItem. + } + } + } + + override fun toString(): String { + val sb = StringBuilder("BATCHED UPDATE PROPS ") + var intIdx = 0 + var doubleIdx = 0 + try { + while (intIdx < intBuffer.size) { + if (intBuffer[intIdx++] != CMD_START_OF_VIEW) break + val viewTag = intBuffer[intIdx++] + sb.append('[').append(viewTag).append("]: {") + var firstProp = true + + view@ while (true) { + val cmd = intBuffer[intIdx++] + if (cmd == CMD_END_OF_VIEW) break@view + + if (!firstProp) sb.append(", ") + firstProp = false + + when (cmd) { + in CMD_OPACITY..CMD_SHADOW_RADIUS -> + sb.append(commandToString(cmd)).append('=').append(doubleBuffer[doubleIdx++]) + in CMD_BACKGROUND_COLOR..CMD_TINT_COLOR, + in CMD_BORDER_COLOR..CMD_BORDER_END_COLOR -> + sb.append(commandToString(cmd)).append('=').append(intBuffer[intIdx++]) + in CMD_BORDER_RADIUS..CMD_BORDER_END_END_RADIUS -> { + val value = doubleBuffer[doubleIdx++] + val unit = intBuffer[intIdx++] + sb.append(commandToString(cmd)).append('=').append(value) + if (unit == CMD_UNIT_PERCENT) sb.append('%') + } + CMD_START_OF_TRANSFORM -> { + sb.append(ViewProps.TRANSFORM).append("=[") + var firstEntry = true + while (true) { + val transformCmd = intBuffer[intIdx++] + if (transformCmd == CMD_END_OF_TRANSFORM) break + if (!firstEntry) sb.append(", ") + firstEntry = false + sb.append(transformCommandToString(transformCmd)).append('=') + when (transformCmd) { + in CMD_SCALE..CMD_SCALE_Y, + CMD_PERSPECTIVE -> sb.append(doubleBuffer[doubleIdx++]) + in CMD_TRANSLATE_X..CMD_TRANSLATE_Y -> { + sb.append(doubleBuffer[doubleIdx++]) + if (intBuffer[intIdx++] == CMD_UNIT_PERCENT) sb.append('%') + } + in CMD_ROTATE..CMD_SKEW_Y -> { + sb.append(doubleBuffer[doubleIdx++]) + sb.append(if (intBuffer[intIdx++] == CMD_UNIT_DEG) "deg" else "rad") + } + CMD_MATRIX -> { + val size = intBuffer[intIdx++] + sb.append('[') + for (i in 0 until size) { + if (i > 0) sb.append(", ") + sb.append(doubleBuffer[doubleIdx++]) + } + sb.append(']') + } + } + } + sb.append(']') + } + } + } + sb.append("}; ") + } + } catch (t: Throwable) { + sb.append("') + } + return sb.toString() + } + + override fun getSurfaceId(): Int = View.NO_ID + + companion object { + // Buffer protocol commands + private const val CMD_START_OF_VIEW = 1 + private const val CMD_START_OF_TRANSFORM = 2 + private const val CMD_END_OF_TRANSFORM = 3 + private const val CMD_END_OF_VIEW = 4 + private const val CMD_OPACITY = 10 + private const val CMD_ELEVATION = 11 + private const val CMD_Z_INDEX = 12 + private const val CMD_SHADOW_OPACITY = 13 + private const val CMD_SHADOW_RADIUS = 14 + private const val CMD_BACKGROUND_COLOR = 15 + private const val CMD_COLOR = 16 + private const val CMD_TINT_COLOR = 17 + private const val CMD_BORDER_RADIUS = 20 + private const val CMD_BORDER_TOP_LEFT_RADIUS = 21 + private const val CMD_BORDER_TOP_RIGHT_RADIUS = 22 + private const val CMD_BORDER_TOP_START_RADIUS = 23 + private const val CMD_BORDER_TOP_END_RADIUS = 24 + private const val CMD_BORDER_BOTTOM_LEFT_RADIUS = 25 + private const val CMD_BORDER_BOTTOM_RIGHT_RADIUS = 26 + private const val CMD_BORDER_BOTTOM_START_RADIUS = 27 + private const val CMD_BORDER_BOTTOM_END_RADIUS = 28 + private const val CMD_BORDER_START_START_RADIUS = 29 + private const val CMD_BORDER_START_END_RADIUS = 30 + private const val CMD_BORDER_END_START_RADIUS = 31 + private const val CMD_BORDER_END_END_RADIUS = 32 + private const val CMD_BORDER_COLOR = 40 + private const val CMD_BORDER_TOP_COLOR = 41 + private const val CMD_BORDER_BOTTOM_COLOR = 42 + private const val CMD_BORDER_LEFT_COLOR = 43 + private const val CMD_BORDER_RIGHT_COLOR = 44 + private const val CMD_BORDER_START_COLOR = 45 + private const val CMD_BORDER_END_COLOR = 46 + private const val CMD_TRANSLATE_X = 100 + private const val CMD_TRANSLATE_Y = 101 + private const val CMD_SCALE = 102 + private const val CMD_SCALE_X = 103 + private const val CMD_SCALE_Y = 104 + private const val CMD_ROTATE = 105 + private const val CMD_ROTATE_X = 106 + private const val CMD_ROTATE_Y = 107 + private const val CMD_ROTATE_Z = 108 + private const val CMD_SKEW_X = 109 + private const val CMD_SKEW_Y = 110 + private const val CMD_MATRIX = 111 + private const val CMD_PERSPECTIVE = 112 + private const val CMD_UNIT_DEG = 200 + private const val CMD_UNIT_PX = 202 + private const val CMD_UNIT_PERCENT = 203 + + @JvmStatic + fun commandToString(command: Int): String = + when (command) { + CMD_OPACITY -> ViewProps.OPACITY + CMD_ELEVATION -> ViewProps.ELEVATION + CMD_Z_INDEX -> ViewProps.Z_INDEX + CMD_SHADOW_OPACITY -> "shadowOpacity" + CMD_SHADOW_RADIUS -> "shadowRadius" + CMD_BACKGROUND_COLOR -> ViewProps.BACKGROUND_COLOR + CMD_COLOR -> ViewProps.COLOR + CMD_TINT_COLOR -> "tintColor" + CMD_BORDER_RADIUS -> ViewProps.BORDER_RADIUS + CMD_BORDER_TOP_LEFT_RADIUS -> ViewProps.BORDER_TOP_LEFT_RADIUS + CMD_BORDER_TOP_RIGHT_RADIUS -> ViewProps.BORDER_TOP_RIGHT_RADIUS + CMD_BORDER_TOP_START_RADIUS -> ViewProps.BORDER_TOP_START_RADIUS + CMD_BORDER_TOP_END_RADIUS -> ViewProps.BORDER_TOP_END_RADIUS + CMD_BORDER_BOTTOM_LEFT_RADIUS -> ViewProps.BORDER_BOTTOM_LEFT_RADIUS + CMD_BORDER_BOTTOM_RIGHT_RADIUS -> ViewProps.BORDER_BOTTOM_RIGHT_RADIUS + CMD_BORDER_BOTTOM_START_RADIUS -> ViewProps.BORDER_BOTTOM_START_RADIUS + CMD_BORDER_BOTTOM_END_RADIUS -> ViewProps.BORDER_BOTTOM_END_RADIUS + CMD_BORDER_START_START_RADIUS -> ViewProps.BORDER_START_START_RADIUS + CMD_BORDER_START_END_RADIUS -> ViewProps.BORDER_START_END_RADIUS + CMD_BORDER_END_START_RADIUS -> ViewProps.BORDER_END_START_RADIUS + CMD_BORDER_END_END_RADIUS -> ViewProps.BORDER_END_END_RADIUS + CMD_BORDER_COLOR -> ViewProps.BORDER_COLOR + CMD_BORDER_TOP_COLOR -> ViewProps.BORDER_TOP_COLOR + CMD_BORDER_BOTTOM_COLOR -> ViewProps.BORDER_BOTTOM_COLOR + CMD_BORDER_LEFT_COLOR -> ViewProps.BORDER_LEFT_COLOR + CMD_BORDER_RIGHT_COLOR -> ViewProps.BORDER_RIGHT_COLOR + CMD_BORDER_START_COLOR -> ViewProps.BORDER_START_COLOR + CMD_BORDER_END_COLOR -> ViewProps.BORDER_END_COLOR + else -> "unknown" + } + + @JvmStatic + fun transformCommandToString(command: Int): String = + when (command) { + CMD_TRANSLATE_X -> "translateX" + CMD_TRANSLATE_Y -> "translateY" + CMD_SCALE -> "scale" + CMD_SCALE_X -> ViewProps.SCALE_X + CMD_SCALE_Y -> ViewProps.SCALE_Y + CMD_ROTATE -> "rotate" + CMD_ROTATE_X -> "rotateX" + CMD_ROTATE_Y -> "rotateY" + CMD_ROTATE_Z -> "rotateZ" + CMD_SKEW_X -> "skewX" + CMD_SKEW_Y -> "skewY" + CMD_MATRIX -> "matrix" + CMD_PERSPECTIVE -> "perspective" + else -> "unknown" + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropBufferEncoder.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropBufferEncoder.cpp new file mode 100644 index 000000000000..f522c4b6fe61 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropBufferEncoder.cpp @@ -0,0 +1,428 @@ +/* + * 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 "AnimatedPropBufferEncoder.h" +#include "AnimatedPropCommands.h" + +#include +#include +#include +#include +#include +#include + +namespace facebook::react { + +namespace { + +// Maps a rawProps key (as it appears in folly::dynamic) to its buffer-protocol +// command constant. Returns std::nullopt for keys that are not buffer-eligible. +// NOTE: Keep in sync with BatchedAnimatedPropsMountItem.commandToString on the +// Java side. +std::optional propNameToCommand(const std::string& name) { + static const std::unordered_map kMap = { + {"opacity", animationbackend::CMD_OPACITY}, + {"elevation", animationbackend::CMD_ELEVATION}, + {"zIndex", animationbackend::CMD_Z_INDEX}, + {"shadowOpacity", animationbackend::CMD_SHADOW_OPACITY}, + {"shadowRadius", animationbackend::CMD_SHADOW_RADIUS}, + {"backgroundColor", animationbackend::CMD_BACKGROUND_COLOR}, + {"color", animationbackend::CMD_COLOR}, + {"tintColor", animationbackend::CMD_TINT_COLOR}, + {"borderRadius", animationbackend::CMD_BORDER_RADIUS}, + {"borderTopLeftRadius", animationbackend::CMD_BORDER_TOP_LEFT_RADIUS}, + {"borderTopRightRadius", animationbackend::CMD_BORDER_TOP_RIGHT_RADIUS}, + {"borderTopStartRadius", animationbackend::CMD_BORDER_TOP_START_RADIUS}, + {"borderTopEndRadius", animationbackend::CMD_BORDER_TOP_END_RADIUS}, + {"borderBottomLeftRadius", + animationbackend::CMD_BORDER_BOTTOM_LEFT_RADIUS}, + {"borderBottomRightRadius", + animationbackend::CMD_BORDER_BOTTOM_RIGHT_RADIUS}, + {"borderBottomStartRadius", + animationbackend::CMD_BORDER_BOTTOM_START_RADIUS}, + {"borderBottomEndRadius", animationbackend::CMD_BORDER_BOTTOM_END_RADIUS}, + {"borderStartStartRadius", + animationbackend::CMD_BORDER_START_START_RADIUS}, + {"borderStartEndRadius", animationbackend::CMD_BORDER_START_END_RADIUS}, + {"borderEndStartRadius", animationbackend::CMD_BORDER_END_START_RADIUS}, + {"borderEndEndRadius", animationbackend::CMD_BORDER_END_END_RADIUS}, + {"borderColor", animationbackend::CMD_BORDER_COLOR}, + {"borderTopColor", animationbackend::CMD_BORDER_TOP_COLOR}, + {"borderBottomColor", animationbackend::CMD_BORDER_BOTTOM_COLOR}, + {"borderLeftColor", animationbackend::CMD_BORDER_LEFT_COLOR}, + {"borderRightColor", animationbackend::CMD_BORDER_RIGHT_COLOR}, + {"borderStartColor", animationbackend::CMD_BORDER_START_COLOR}, + {"borderEndColor", animationbackend::CMD_BORDER_END_COLOR}, + // "transform" is dispatched as the START_OF_TRANSFORM marker; the + // packDynamicEntryToBuffers switch handles the nested operations. + {"transform", animationbackend::CMD_START_OF_TRANSFORM}, + }; + auto it = kMap.find(name); + if (it == kMap.end()) { + return std::nullopt; + } + return it->second; +} + +// Maps a transform operation name (e.g. "translateX", "rotate") to its +// transform command constant. Returns std::nullopt for unknown operations. +std::optional transformNameToCommand(const std::string& name) { + static const std::unordered_map kMap = { + {"translateX", animationbackend::CMD_TRANSFORM_TRANSLATE_X}, + {"translateY", animationbackend::CMD_TRANSFORM_TRANSLATE_Y}, + {"scale", animationbackend::CMD_TRANSFORM_SCALE}, + {"scaleX", animationbackend::CMD_TRANSFORM_SCALE_X}, + {"scaleY", animationbackend::CMD_TRANSFORM_SCALE_Y}, + {"rotate", animationbackend::CMD_TRANSFORM_ROTATE}, + {"rotateX", animationbackend::CMD_TRANSFORM_ROTATE_X}, + {"rotateY", animationbackend::CMD_TRANSFORM_ROTATE_Y}, + {"rotateZ", animationbackend::CMD_TRANSFORM_ROTATE_Z}, + {"skewX", animationbackend::CMD_TRANSFORM_SKEW_X}, + {"skewY", animationbackend::CMD_TRANSFORM_SKEW_Y}, + {"matrix", animationbackend::CMD_TRANSFORM_MATRIX}, + {"perspective", animationbackend::CMD_TRANSFORM_PERSPECTIVE}, + }; + auto it = kMap.find(name); + if (it == kMap.end()) { + return std::nullopt; + } + return it->second; +} + +} // namespace + +namespace animationbackend { + +// Packs a single TransformOperation directly into the buffer protocol. +// Mirrors the (TransformOperation -> serialized name -> buffer command) +// path used by updateTransformProps + the dynamic-based packer, but reads +// the typed values straight from the operation. +static void packTransformOperationToBuffers( + const Transform& transform, + const TransformOperation& op, + std::vector& intBuffer, + std::vector& doubleBuffer) { + auto pushUnit = [&](int cmd, const ValueUnit& vu) { + intBuffer.push_back(cmd); + intBuffer.push_back( + vu.unit == UnitType::Percent ? CMD_UNIT_PERCENT : CMD_UNIT_PX); + doubleBuffer.push_back(vu.value); + }; + // updateTransformProps preserves rotation values as floats (radians); + // ValueUnit carries no Deg/Rad distinction, so always emit RAD. + auto pushAngle = [&](int cmd, const ValueUnit& vu) { + intBuffer.push_back(cmd); + intBuffer.push_back(CMD_UNIT_RAD); + doubleBuffer.push_back(vu.value); + }; + + switch (op.type) { + case TransformOperationType::Scale: + if (op.x == op.y && op.x == op.z) { + intBuffer.push_back(CMD_TRANSFORM_SCALE); + doubleBuffer.push_back(op.x.value); + } else { + if (op.x.value != 1.0f) { + intBuffer.push_back(CMD_TRANSFORM_SCALE_X); + doubleBuffer.push_back(op.x.value); + } + if (op.y.value != 1.0f) { + intBuffer.push_back(CMD_TRANSFORM_SCALE_Y); + doubleBuffer.push_back(op.y.value); + } + // No CMD_TRANSFORM_SCALE_Z in the protocol. + } + return; + case TransformOperationType::Translate: + if (op.x.value != 0) { + pushUnit(CMD_TRANSFORM_TRANSLATE_X, op.x); + } + if (op.y.value != 0) { + pushUnit(CMD_TRANSFORM_TRANSLATE_Y, op.y); + } + // No CMD_TRANSFORM_TRANSLATE_Z in the protocol. + return; + case TransformOperationType::Rotate: + if (op.x.value != 0) { + pushAngle(CMD_TRANSFORM_ROTATE_X, op.x); + } + if (op.y.value != 0) { + pushAngle(CMD_TRANSFORM_ROTATE_Y, op.y); + } + if (op.z.value != 0) { + pushAngle(CMD_TRANSFORM_ROTATE_Z, op.z); + } + return; + case TransformOperationType::Skew: + if (op.x.value != 0) { + pushAngle(CMD_TRANSFORM_SKEW_X, op.x); + } + if (op.y.value != 0) { + pushAngle(CMD_TRANSFORM_SKEW_Y, op.y); + } + return; + case TransformOperationType::Perspective: + // updateTransformProps emits "perspectiveX/Y/Z" via + // serializeTransformAxis which has no entries in transformNameToCommand, + // so the dynamic path is a no-op. Match that behavior here. + return; + case TransformOperationType::Arbitrary: + intBuffer.push_back(CMD_TRANSFORM_MATRIX); + intBuffer.push_back(static_cast(transform.matrix.size())); + for (const auto& elem : transform.matrix) { + doubleBuffer.push_back(elem); + } + return; + case TransformOperationType::Identity: + return; + } +} + +// Packs a single AnimatedPropBase straight into the buffer protocol, +// without going through folly::dynamic. Asserts the propName is one of +// the buffer-eligible props supported by this path; the caller of +// synchronouslyUpdatePropsBuffered is contractually required to only +// supply such props. +static void packAnimatedPropToBuffers( + const AnimatedPropBase& animatedProp, + std::vector& intBuffer, + std::vector& doubleBuffer) { + switch (animatedProp.propName) { + case OPACITY: + intBuffer.push_back(CMD_OPACITY); + doubleBuffer.push_back(get(animatedProp)); + return; + case BACKGROUND_COLOR: + intBuffer.push_back(CMD_BACKGROUND_COLOR); + intBuffer.push_back( + static_cast(*get(animatedProp))); + return; + case SHADOW_OPACITY: + intBuffer.push_back(CMD_SHADOW_OPACITY); + doubleBuffer.push_back(get(animatedProp)); + return; + case SHADOW_RADIUS: + intBuffer.push_back(CMD_SHADOW_RADIUS); + doubleBuffer.push_back(get(animatedProp)); + return; + case BORDER_RADII: { + const auto borderRadii = get(animatedProp); + auto pushCorner = [&](int cmd, const std::optional& corner) { + if (corner.has_value()) { + intBuffer.push_back(cmd); + intBuffer.push_back(CMD_UNIT_PX); + doubleBuffer.push_back(corner.value().value); + } + }; + pushCorner(CMD_BORDER_TOP_LEFT_RADIUS, borderRadii.topLeft); + pushCorner(CMD_BORDER_TOP_RIGHT_RADIUS, borderRadii.topRight); + pushCorner(CMD_BORDER_BOTTOM_LEFT_RADIUS, borderRadii.bottomLeft); + pushCorner(CMD_BORDER_BOTTOM_RIGHT_RADIUS, borderRadii.bottomRight); + pushCorner(CMD_BORDER_TOP_START_RADIUS, borderRadii.topStart); + pushCorner(CMD_BORDER_TOP_END_RADIUS, borderRadii.topEnd); + pushCorner(CMD_BORDER_BOTTOM_START_RADIUS, borderRadii.bottomStart); + pushCorner(CMD_BORDER_BOTTOM_END_RADIUS, borderRadii.bottomEnd); + pushCorner(CMD_BORDER_START_START_RADIUS, borderRadii.startStart); + pushCorner(CMD_BORDER_START_END_RADIUS, borderRadii.startEnd); + pushCorner(CMD_BORDER_END_START_RADIUS, borderRadii.endStart); + pushCorner(CMD_BORDER_END_END_RADIUS, borderRadii.endEnd); + pushCorner(CMD_BORDER_RADIUS, borderRadii.all); + return; + } + case BORDER_COLOR: { + const auto borderColors = get(animatedProp); + auto pushEdge = [&](int cmd, const std::optional& color) { + if (color.has_value() && color.value()) { + intBuffer.push_back(cmd); + intBuffer.push_back(static_cast(*color.value())); + } + }; + pushEdge(CMD_BORDER_LEFT_COLOR, borderColors.left); + pushEdge(CMD_BORDER_TOP_COLOR, borderColors.top); + pushEdge(CMD_BORDER_RIGHT_COLOR, borderColors.right); + pushEdge(CMD_BORDER_BOTTOM_COLOR, borderColors.bottom); + pushEdge(CMD_BORDER_START_COLOR, borderColors.start); + pushEdge(CMD_BORDER_END_COLOR, borderColors.end); + pushEdge(CMD_BORDER_COLOR, borderColors.all); + return; + } + case TRANSFORM: { + const auto transform = get(animatedProp); + intBuffer.push_back(CMD_START_OF_TRANSFORM); + for (const auto& op : transform.operations) { + packTransformOperationToBuffers(transform, op, intBuffer, doubleBuffer); + } + intBuffer.push_back(CMD_END_OF_TRANSFORM); + return; + } + default: + // Contract: synchronouslyUpdatePropsBuffered must only be invoked + // with props that can flow through the buffer protocol. + react_native_assert(false); + return; + } +} + +// Packs a single rawProps (key, value) entry into the buffer protocol. +// rawProps still has to flow through folly::dynamic because RawProps +// exposes no public iteration API. +static void packDynamicEntryToBuffers( + const std::string& key, + const folly::dynamic& value, + std::vector& intBuffer, + std::vector& doubleBuffer) { + auto cmd = propNameToCommand(key); + react_native_assert(cmd.has_value()); + + switch (cmd.value()) { + case CMD_OPACITY: + case CMD_ELEVATION: + case CMD_Z_INDEX: + case CMD_SHADOW_OPACITY: + case CMD_SHADOW_RADIUS: + intBuffer.push_back(cmd.value()); + doubleBuffer.push_back(value.asDouble()); + break; + + case CMD_BACKGROUND_COLOR: + case CMD_COLOR: + case CMD_TINT_COLOR: + case CMD_BORDER_COLOR: + case CMD_BORDER_TOP_COLOR: + case CMD_BORDER_BOTTOM_COLOR: + case CMD_BORDER_LEFT_COLOR: + case CMD_BORDER_RIGHT_COLOR: + case CMD_BORDER_START_COLOR: + case CMD_BORDER_END_COLOR: + intBuffer.push_back(cmd.value()); + intBuffer.push_back(value.asInt()); + break; + + case CMD_BORDER_RADIUS: + case CMD_BORDER_TOP_LEFT_RADIUS: + case CMD_BORDER_TOP_RIGHT_RADIUS: + case CMD_BORDER_TOP_START_RADIUS: + case CMD_BORDER_TOP_END_RADIUS: + case CMD_BORDER_BOTTOM_LEFT_RADIUS: + case CMD_BORDER_BOTTOM_RIGHT_RADIUS: + case CMD_BORDER_BOTTOM_START_RADIUS: + case CMD_BORDER_BOTTOM_END_RADIUS: + case CMD_BORDER_START_START_RADIUS: + case CMD_BORDER_START_END_RADIUS: + case CMD_BORDER_END_START_RADIUS: + case CMD_BORDER_END_END_RADIUS: + intBuffer.push_back(cmd.value()); + if (value.isDouble()) { + intBuffer.push_back(CMD_UNIT_PX); + doubleBuffer.push_back(value.getDouble()); + } else if (value.isString()) { + intBuffer.push_back(CMD_UNIT_PERCENT); + auto str = value.getString(); + doubleBuffer.push_back(std::stof(str.substr(0, str.size() - 1))); + } + break; + + case CMD_START_OF_TRANSFORM: + intBuffer.push_back(CMD_START_OF_TRANSFORM); + if (value.isArray()) { + for (const auto& item : value) { + if (!item.isObject() || item.size() != 1) { + continue; + } + auto transformName = item.keys().begin()->getString(); + auto transformCmd = transformNameToCommand(transformName); + if (!transformCmd.has_value()) { + continue; + } + const auto& transformValue = *item.values().begin(); + + switch (transformCmd.value()) { + case CMD_TRANSFORM_SCALE: + case CMD_TRANSFORM_SCALE_X: + case CMD_TRANSFORM_SCALE_Y: + case CMD_TRANSFORM_PERSPECTIVE: + intBuffer.push_back(transformCmd.value()); + doubleBuffer.push_back(transformValue.asDouble()); + break; + case CMD_TRANSFORM_TRANSLATE_X: + case CMD_TRANSFORM_TRANSLATE_Y: + intBuffer.push_back(transformCmd.value()); + if (transformValue.isDouble()) { + intBuffer.push_back(CMD_UNIT_PX); + doubleBuffer.push_back(transformValue.getDouble()); + } else if (transformValue.isString()) { + auto str = transformValue.getString(); + intBuffer.push_back(CMD_UNIT_PERCENT); + doubleBuffer.push_back( + std::stof(str.substr(0, str.size() - 1))); + } + break; + case CMD_TRANSFORM_ROTATE: + case CMD_TRANSFORM_ROTATE_X: + case CMD_TRANSFORM_ROTATE_Y: + case CMD_TRANSFORM_ROTATE_Z: + case CMD_TRANSFORM_SKEW_X: + case CMD_TRANSFORM_SKEW_Y: { + intBuffer.push_back(transformCmd.value()); + if (transformValue.isDouble()) { + intBuffer.push_back(CMD_UNIT_RAD); + doubleBuffer.push_back(transformValue.getDouble()); + } else { + auto str = transformValue.getString(); + if (str.size() > 3 && str.substr(str.size() - 3) == "deg") { + intBuffer.push_back(CMD_UNIT_DEG); + } else { + intBuffer.push_back(CMD_UNIT_RAD); + } + doubleBuffer.push_back( + std::stof(str.substr(0, str.size() - 3))); + } + break; + } + case CMD_TRANSFORM_MATRIX: + intBuffer.push_back(transformCmd.value()); + if (transformValue.isArray()) { + intBuffer.push_back(static_cast(transformValue.size())); + for (const auto& elem : transformValue) { + doubleBuffer.push_back(elem.asDouble()); + } + } + break; + } + } + } + intBuffer.push_back(CMD_END_OF_TRANSFORM); + break; + } +} + +void packDynamicPropsToBuffers( + Tag tag, + const AnimatedProps& animatedProps, + std::vector& intBuffer, + std::vector& doubleBuffer) { + intBuffer.push_back(CMD_START_OF_VIEW); + intBuffer.push_back(tag); + + for (auto& animatedProp : animatedProps.props) { + packAnimatedPropToBuffers(*animatedProp, intBuffer, doubleBuffer); + } + + if (animatedProps.rawProps) { + auto rawDyn = animatedProps.rawProps->toDynamic(); + for (auto& [key, value] : rawDyn.items()) { + packDynamicEntryToBuffers( + key.getString(), value, intBuffer, doubleBuffer); + } + } + + intBuffer.push_back(CMD_END_OF_VIEW); +} + +} // namespace animationbackend + +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropBufferEncoder.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropBufferEncoder.h new file mode 100644 index 000000000000..3bfbd9e482d9 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropBufferEncoder.h @@ -0,0 +1,26 @@ +/* + * 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 +#include +#include + +namespace facebook::react::animationbackend { + +/** + * Packs an AnimatedProps object for a single view directly into the buffer + * protocol used by the synchronous batched update path on Android. + */ +void packDynamicPropsToBuffers( + Tag tag, + const AnimatedProps &animatedProps, + std::vector &intBuffer, + std::vector &doubleBuffer); + +} // namespace facebook::react::animationbackend diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropCommands.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropCommands.h new file mode 100644 index 000000000000..ed2ad63031f3 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/AnimatedPropCommands.h @@ -0,0 +1,78 @@ +/* + * 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 + +namespace facebook::react::animationbackend { + +// Buffer protocol command constants for batched animated prop updates. +// NOTE: Keep in sync with AnimatedPropCommandConstants.kt on the Java side. + +// View delimiters +static constexpr int CMD_START_OF_VIEW = 1; +static constexpr int CMD_START_OF_TRANSFORM = 2; +static constexpr int CMD_END_OF_TRANSFORM = 3; +static constexpr int CMD_END_OF_VIEW = 4; + +// Simple numeric props (value in doubleBuffer) +static constexpr int CMD_OPACITY = 10; +static constexpr int CMD_ELEVATION = 11; +static constexpr int CMD_Z_INDEX = 12; +static constexpr int CMD_SHADOW_OPACITY = 13; +static constexpr int CMD_SHADOW_RADIUS = 14; + +// Color props (value as int in intBuffer) +static constexpr int CMD_BACKGROUND_COLOR = 15; +static constexpr int CMD_COLOR = 16; +static constexpr int CMD_TINT_COLOR = 17; + +// Border radius props (value in doubleBuffer, unit in intBuffer) +static constexpr int CMD_BORDER_RADIUS = 20; +static constexpr int CMD_BORDER_TOP_LEFT_RADIUS = 21; +static constexpr int CMD_BORDER_TOP_RIGHT_RADIUS = 22; +static constexpr int CMD_BORDER_TOP_START_RADIUS = 23; +static constexpr int CMD_BORDER_TOP_END_RADIUS = 24; +static constexpr int CMD_BORDER_BOTTOM_LEFT_RADIUS = 25; +static constexpr int CMD_BORDER_BOTTOM_RIGHT_RADIUS = 26; +static constexpr int CMD_BORDER_BOTTOM_START_RADIUS = 27; +static constexpr int CMD_BORDER_BOTTOM_END_RADIUS = 28; +static constexpr int CMD_BORDER_START_START_RADIUS = 29; +static constexpr int CMD_BORDER_START_END_RADIUS = 30; +static constexpr int CMD_BORDER_END_START_RADIUS = 31; +static constexpr int CMD_BORDER_END_END_RADIUS = 32; + +// Border color props (value as int in intBuffer) +static constexpr int CMD_BORDER_COLOR = 40; +static constexpr int CMD_BORDER_TOP_COLOR = 41; +static constexpr int CMD_BORDER_BOTTOM_COLOR = 42; +static constexpr int CMD_BORDER_LEFT_COLOR = 43; +static constexpr int CMD_BORDER_RIGHT_COLOR = 44; +static constexpr int CMD_BORDER_START_COLOR = 45; +static constexpr int CMD_BORDER_END_COLOR = 46; + +// Transform commands +static constexpr int CMD_TRANSFORM_TRANSLATE_X = 100; +static constexpr int CMD_TRANSFORM_TRANSLATE_Y = 101; +static constexpr int CMD_TRANSFORM_SCALE = 102; +static constexpr int CMD_TRANSFORM_SCALE_X = 103; +static constexpr int CMD_TRANSFORM_SCALE_Y = 104; +static constexpr int CMD_TRANSFORM_ROTATE = 105; +static constexpr int CMD_TRANSFORM_ROTATE_X = 106; +static constexpr int CMD_TRANSFORM_ROTATE_Y = 107; +static constexpr int CMD_TRANSFORM_ROTATE_Z = 108; +static constexpr int CMD_TRANSFORM_SKEW_X = 109; +static constexpr int CMD_TRANSFORM_SKEW_Y = 110; +static constexpr int CMD_TRANSFORM_MATRIX = 111; +static constexpr int CMD_TRANSFORM_PERSPECTIVE = 112; + +// Unit commands +static constexpr int CMD_UNIT_DEG = 200; +static constexpr int CMD_UNIT_RAD = 201; +static constexpr int CMD_UNIT_PX = 202; +static constexpr int CMD_UNIT_PERCENT = 203; + +} // namespace facebook::react::animationbackend diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index b82bdab278c2..154da216f2de 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -7,6 +7,7 @@ #include "FabricMountingManager.h" +#include "AnimatedPropBufferEncoder.h" #include "EventEmitterWrapper.h" #include "MountItem.h" #include "StateWrapperImpl.h" @@ -1253,6 +1254,44 @@ void FabricMountingManager::clearPendingSnapshots() { clearPendingSnapshotsJNI(javaUIManager_); } +void FabricMountingManager::synchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId /*surfaceId*/, + const std::unordered_map& updates) { + std::vector intBuffer; + std::vector doubleBuffer; + + for (const auto& [tag, animatedProps] : updates) { + animationbackend::packDynamicPropsToBuffers( + tag, animatedProps, intBuffer, doubleBuffer); + } + + if (intBuffer.empty()) { + return; + } + + auto env = jni::Environment::current(); + + auto jIntArray = env->NewIntArray(static_cast(intBuffer.size())); + env->SetIntArrayRegion( + jIntArray, 0, static_cast(intBuffer.size()), intBuffer.data()); + + auto jDoubleArray = + env->NewDoubleArray(static_cast(doubleBuffer.size())); + env->SetDoubleArrayRegion( + jDoubleArray, + 0, + static_cast(doubleBuffer.size()), + doubleBuffer.data()); + + static auto synchronouslyUpdateViewBatchJNI = + JFabricUIManager::javaClassStatic() + ->getMethod( + "synchronouslyUpdateViewBatch"); + synchronouslyUpdateViewBatchJNI(javaUIManager_, jIntArray, jDoubleArray); + + env->DeleteLocalRef(jIntArray); + env->DeleteLocalRef(jDoubleArray); +} void FabricMountingManager::scheduleReactRevisionMerge(SurfaceId surfaceId) { static const auto scheduleReactRevisionMerge = JFabricUIManager::javaClassStatic()->getMethod( diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h index 377880b658bb..da8d9531b63e 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h @@ -13,6 +13,7 @@ #include #include +#include #include namespace facebook::react { @@ -74,6 +75,9 @@ class FabricMountingManager final { void clearPendingSnapshots(); + void synchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates); void scheduleReactRevisionMerge(SurfaceId surfaceId); private: diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp index dfaac96caefc..30a2f54d5efb 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp @@ -792,6 +792,16 @@ void FabricUIManagerBinding::schedulerShouldSynchronouslyUpdateViewOnUIThread( } } +void FabricUIManagerBinding:: + schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map& updates) { + if (ReactNativeFeatureFlags::cxxNativeAnimatedEnabled() && mountingManager_) { + mountingManager_->synchronouslyUpdateAnimatedPropsOnUIThread( + surfaceId, updates); + } +} + void FabricUIManagerBinding::schedulerDidUpdateShadowTree( const std::unordered_map& /*tagToProps*/) { // no-op diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h index caf652d2352e..11478770b91a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h @@ -115,6 +115,10 @@ class FabricUIManagerBinding : public jni::HybridClass, void schedulerShouldSynchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props) override; + void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates) override; + void schedulerDidUpdateShadowTree(const std::unordered_map &tagToProps) override; void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override; diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp index 065874af36ad..0ec7da69579e 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp @@ -559,7 +559,6 @@ void packBackfaceVisibility( } dyn.insert("backfaceVisibility", visibilityStr); } - void packAnimatedProp( folly::dynamic& dyn, const std::unique_ptr& animatedProp) { diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp index 1598269ea785..064005d07367 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp @@ -6,6 +6,7 @@ */ #include "AnimatedPropsRegistry.h" +#include #include #include "AnimatedProps.h" @@ -13,6 +14,8 @@ namespace facebook::react { void AnimatedPropsRegistry::update( const std::unordered_map& surfaceUpdates) { + TraceSection s( + "AnimatedPropsRegistry::update", "surfaceCount", surfaceUpdates.size()); auto lock = std::lock_guard(mutex_); for (const auto& [surfaceId, updates] : surfaceUpdates) { auto& surfaceContext = surfaceContexts_[surfaceId]; @@ -59,6 +62,7 @@ std::pair< std::unordered_set>&, SnapshotMap&> AnimatedPropsRegistry::getMap(SurfaceId surfaceId) { + TraceSection s("AnimatedPropsRegistry::getMap", "surfaceId", surfaceId); auto lock = std::lock_guard(mutex_); auto& [pendingMap, map, pendingFamilies, families] = surfaceContexts_[surfaceId]; diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp index 62a8676088ca..399354cf9d59 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp @@ -8,10 +8,10 @@ #include "AnimationBackend.h" #include "AnimatedPropsRegistry.h" +#include #include #include #include -#include #include #include @@ -79,13 +79,17 @@ void AnimationBackend::unpackMutations( void AnimationBackend::applySurfaceUpdates( std::unordered_map& surfaceUpdates, const std::set& asyncFlushSurfaces) { + TraceSection s( + "AnimationBackend::applySurfaceUpdates", + "surfaceCount", + surfaceUpdates.size()); animatedPropsRegistry_->update(surfaceUpdates); for (auto& [surfaceId, updates] : surfaceUpdates) { if (updates.hasLayoutUpdates) { commitUpdates(surfaceId, updates); } else { - synchronouslyUpdateProps(updates.propsMap); + synchronouslyUpdateProps(surfaceId, updates.propsMap); } } @@ -100,6 +104,7 @@ void AnimationBackend::applyMutations(AnimationMutations mutations) { } void AnimationBackend::onAnimationFrame(AnimationTimestamp timestamp) { + TraceSection s("AnimationBackend::onAnimationFrame"); std::vector callbacksCopy; { @@ -159,6 +164,12 @@ void AnimationBackend::pushAnimationMutations(const Callback& callback) { void AnimationBackend::commitUpdates( SurfaceId surfaceId, SurfaceUpdates& surfaceUpdates) { + TraceSection s( + "AnimationBackend::commitUpdates", + "surfaceId", + surfaceId, + "updateCount", + surfaceUpdates.propsMap.size()); auto uiManager = uiManager_.lock(); if (!uiManager) { return; @@ -194,11 +205,13 @@ void AnimationBackend::commitUpdates( }); } -void AnimationBackend::synchronouslyUpdateProps( +void AnimationBackend::synchronouslyUpdatePropsUnbuffered( const std::unordered_map& updates) { + TraceSection s( + "AnimationBackend::synchronouslyUpdatePropsUnbuffered", + "updateCount", + updates.size()); for (auto& [tag, animatedProps] : updates) { - // TODO: We shouldn't repack it into dynamic, but for that a rewrite - // of synchronouslyUpdateViewOnUIThread is needed auto dyn = animationbackend::packAnimatedProps(animatedProps); if (auto uiManager = uiManager_.lock()) { uiManager->synchronouslyUpdateViewOnUIThread(tag, dyn); @@ -206,8 +219,30 @@ void AnimationBackend::synchronouslyUpdateProps( } } +void AnimationBackend::synchronouslyUpdateProps( + SurfaceId surfaceId, + const std::unordered_map& updates) { + TraceSection s( + "AnimationBackend::synchronouslyUpdateProps", + "surfaceId", + surfaceId, + "updateCount", + updates.size()); + if (ReactNativeFeatureFlags::optimizedAnimatedPropUpdates()) { + if (auto uiManager = uiManager_.lock()) { + uiManager->synchronouslyUpdateAnimatedPropsOnUIThread(surfaceId, updates); + } + return; + } + synchronouslyUpdatePropsUnbuffered(updates); +} + void AnimationBackend::requestAsyncFlushForSurfaces( const std::set& surfaces) { + TraceSection s( + "AnimationBackend::requestAsyncFlushForSurfaces", + "surfaceCount", + surfaces.size()); react_native_assert( jsInvoker_ != nullptr || surfaces.empty() && "jsInvoker_ was not provided"); diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.h b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.h index c01ff23a8e71..ddb9f9e7977d 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.h +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.h @@ -52,7 +52,8 @@ class AnimationBackend : public UIManagerAnimationBackend { std::shared_ptr animationChoreographer, std::shared_ptr uiManager); void commitUpdates(SurfaceId surfaceId, SurfaceUpdates &surfaceUpdates); - void synchronouslyUpdateProps(const std::unordered_map &updates); + void synchronouslyUpdateProps(SurfaceId surfaceId, const std::unordered_map &updates); + void synchronouslyUpdatePropsUnbuffered(const std::unordered_map &updates); void requestAsyncFlushForSurfaces(const std::set &surfaces); void clearRegistry(SurfaceId surfaceId) override; void clearRegistryOnSurfaceStop(SurfaceId surfaceId) override; diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp index cb547d9e367d..c71ef5039f70 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp @@ -7,6 +7,7 @@ #include +#include #include namespace facebook::react { @@ -23,6 +24,10 @@ RootShadowNode::Unshared AnimationBackendCommitHook::shadowTreeWillCommit( const RootShadowNode::Shared& oldRootShadowNode, const RootShadowNode::Unshared& newRootShadowNode, const ShadowTreeCommitOptions& commitOptions) noexcept { + TraceSection s( + "AnimationBackendCommitHook::shadowTreeWillCommit", + "surfaceId", + shadowTree.getSurfaceId()); if (commitOptions.source != ShadowTreeCommitSource::React && commitOptions.source != ShadowTreeCommitSource::AnimationEndSync) { return newRootShadowNode; diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 7ea5fc3c782f..6a2d66424215 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -401,6 +401,15 @@ void Scheduler::uiManagerShouldSynchronouslyUpdateViewOnUIThread( } } +void Scheduler::uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map& updates) { + if (delegate_ != nullptr) { + delegate_->schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + surfaceId, updates); + } +} + void Scheduler::uiManagerDidUpdateShadowTree( const std::unordered_map& tagToProps) { if (delegate_ != nullptr) { diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h index bd6de832e04d..591f5d7e7a69 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -94,6 +94,9 @@ class Scheduler final : public UIManagerDelegate { bool isJSResponder, bool blockNativeResponder) override; void uiManagerShouldSynchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props) override; + void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates) override; void uiManagerDidUpdateShadowTree(const std::unordered_map &tagToProps) override; void uiManagerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override; void uiManagerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override; diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h b/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h index 06d9773e4ba5..e1b2c0196b9f 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include @@ -15,6 +16,8 @@ namespace facebook::react { +struct AnimatedProps; + /* * Abstract class for Scheduler's delegate. */ @@ -64,6 +67,17 @@ class SchedulerDelegate { virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props) = 0; + /** + * Synchronously update animated properties for multiple views on the UI + * thread. Each entry maps a Tag to the AnimatedProps that should be applied + * to that view. Platform implementations translate AnimatedProps into the + * native update mechanism (e.g. buffer protocol on Android, typed props on + * iOS). + */ + virtual void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates) = 0; + virtual void schedulerDidUpdateShadowTree(const std::unordered_map &tagToProps) = 0; // View transition bitmap snapshot capture and application. diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp index bce35dd6fa25..79799198539a 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -765,6 +765,15 @@ void UIManager::synchronouslyUpdateViewOnUIThread( } } +void UIManager::synchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map& updates) { + if (delegate_ != nullptr) { + delegate_->uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + surfaceId, updates); + } +} + #pragma mark ContextContainer std::shared_ptr UIManager::getContextContainer() const { diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h index 28b8729e3e01..3d744e9ebb2c 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h @@ -85,6 +85,10 @@ class UIManager final : public ShadowTreeDelegate { void synchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props); + void synchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates); + /* * Provides access to a UIManagerBinding. * The `callback` methods will not be called if the internal pointer to diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h index 27c39b18e5e0..1bbaabdb33c1 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h @@ -15,6 +15,7 @@ namespace facebook::react { +struct AnimatedProps; struct AnimationMutations; using AnimationTimestamp = std::chrono::duration; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h index 235b1fe34eac..b4772d8a0dfc 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h @@ -7,6 +7,8 @@ #pragma once +#include + #include #include #include @@ -14,6 +16,8 @@ namespace facebook::react { +struct AnimatedProps; + /* * Abstract class for UIManager's delegate. */ @@ -64,6 +68,13 @@ class UIManagerDelegate { */ virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props) = 0; + /* + * Synchronously update animated properties on the UI thread. + */ + virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates) = 0; + /* * Called after updateShadowTree is invoked. */ diff --git a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp index 9ad1bb1a4f54..51e42552f23a 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp +++ b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp @@ -71,6 +71,13 @@ void SchedulerDelegateImpl::schedulerShouldSynchronouslyUpdateViewOnUIThread( mountingManager_->synchronouslyUpdateViewOnUIThread(tag, props); } +void SchedulerDelegateImpl:: + schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId /*surfaceId*/, + const std::unordered_map& /*updates*/) { + // Not implemented on CxxPlatform. +} + void SchedulerDelegateImpl::schedulerDidUpdateShadowTree( const std::unordered_map& tagToProps) { mountingManager_->onUpdateShadowTree(tagToProps); diff --git a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h index 089b64d5731c..ec84c938ea78 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h +++ b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h @@ -49,6 +49,10 @@ class SchedulerDelegateImpl : public SchedulerDelegate { void schedulerShouldSynchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props) override; + void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread( + SurfaceId surfaceId, + const std::unordered_map &updates) override; + void schedulerDidUpdateShadowTree(const std::unordered_map &tagToProps) override; void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index bef10cabb729..96dfd045c301 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -1560,7 +1560,8 @@ class facebook::react::AnimationBackend : public facebook::react::UIManagerAnima public virtual void trigger() override; public void commitUpdates(facebook::react::SurfaceId surfaceId, facebook::react::SurfaceUpdates& surfaceUpdates); public void requestAsyncFlushForSurfaces(const std::set& surfaces); - public void synchronouslyUpdateProps(const std::unordered_map& updates); + public void synchronouslyUpdateProps(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); + public void synchronouslyUpdatePropsUnbuffered(const std::unordered_map& updates); } class facebook::react::AnimationBackendCommitHook : public facebook::react::UIManagerCommitHook { @@ -2338,6 +2339,7 @@ class facebook::react::FabricMountingManager { public void sendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType); public void setIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder); public void setViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId); + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag viewTag, const folly::dynamic& props); public ~FabricMountingManager(); } @@ -4489,6 +4491,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) override; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) override; public void addEventListener(std::shared_ptr listener); public void animationTick() const; @@ -4512,6 +4515,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; + public virtual void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~SchedulerDelegate() noexcept = default; } @@ -5239,6 +5243,7 @@ class facebook::react::UIManager : public facebook::react::ShadowTreeDelegate { public void startEmptySurface(facebook::react::ShadowTree::Unique&& shadowTree) const noexcept; public void startSurface(facebook::react::ShadowTree::Unique&& shadowTree, const std::string& moduleName, const folly::dynamic& props, facebook::react::DisplayMode displayMode) const noexcept; public void stopSurfaceForAnimationDelegate(facebook::react::SurfaceId surfaceId) const; + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props); public void unregisterCommitHook(facebook::react::UIManagerCommitHook& commitHook); public void unregisterMountHook(facebook::react::UIManagerMountHook& mountHook); @@ -5306,6 +5311,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~UIManagerDelegate() noexcept = default; } @@ -11528,6 +11534,58 @@ struct facebook::react::dom::RNMeasureRect { static constexpr facebook::react::Tag facebook::react::animated::undefinedAnimatedNodeIdentifier; +static constexpr int facebook::react::animationbackend::CMD_BACKGROUND_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_LEFT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_RIGHT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_END_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_END_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_END_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_LEFT_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_RIGHT_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_START_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_START_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_START_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_LEFT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_RIGHT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_COLOR; +static constexpr int facebook::react::animationbackend::CMD_ELEVATION; +static constexpr int facebook::react::animationbackend::CMD_END_OF_TRANSFORM; +static constexpr int facebook::react::animationbackend::CMD_END_OF_VIEW; +static constexpr int facebook::react::animationbackend::CMD_OPACITY; +static constexpr int facebook::react::animationbackend::CMD_SHADOW_OPACITY; +static constexpr int facebook::react::animationbackend::CMD_SHADOW_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_START_OF_TRANSFORM; +static constexpr int facebook::react::animationbackend::CMD_START_OF_VIEW; +static constexpr int facebook::react::animationbackend::CMD_TINT_COLOR; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_MATRIX; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_PERSPECTIVE; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE_Y; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE_Z; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SCALE; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SCALE_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SCALE_Y; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SKEW_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SKEW_Y; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_TRANSLATE_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_TRANSLATE_Y; +static constexpr int facebook::react::animationbackend::CMD_UNIT_DEG; +static constexpr int facebook::react::animationbackend::CMD_UNIT_PERCENT; +static constexpr int facebook::react::animationbackend::CMD_UNIT_PX; +static constexpr int facebook::react::animationbackend::CMD_UNIT_RAD; +static constexpr int facebook::react::animationbackend::CMD_Z_INDEX; +void facebook::react::animationbackend::packDynamicPropsToBuffers(facebook::react::Tag tag, const facebook::react::AnimatedProps& animatedProps, std::vector& intBuffer, std::vector& doubleBuffer); + + std::shared_ptr facebook::react::CoreComponentsRegistry::sharedProviderRegistry(); void facebook::react::CoreComponentsRegistry::addCoreComponents(std::shared_ptr registry); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index 68b1a1f4344c..375bc625c60e 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -1559,7 +1559,8 @@ class facebook::react::AnimationBackend : public facebook::react::UIManagerAnima public virtual void trigger() override; public void commitUpdates(facebook::react::SurfaceId surfaceId, facebook::react::SurfaceUpdates& surfaceUpdates); public void requestAsyncFlushForSurfaces(const std::set& surfaces); - public void synchronouslyUpdateProps(const std::unordered_map& updates); + public void synchronouslyUpdateProps(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); + public void synchronouslyUpdatePropsUnbuffered(const std::unordered_map& updates); } class facebook::react::AnimationBackendCommitHook : public facebook::react::UIManagerCommitHook { @@ -2336,6 +2337,7 @@ class facebook::react::FabricMountingManager { public void sendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType); public void setIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder); public void setViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId); + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag viewTag, const folly::dynamic& props); public ~FabricMountingManager(); } @@ -4486,6 +4488,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) override; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) override; public void addEventListener(std::shared_ptr listener); public void animationTick() const; @@ -4509,6 +4512,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; + public virtual void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~SchedulerDelegate() noexcept = default; } @@ -5230,6 +5234,7 @@ class facebook::react::UIManager : public facebook::react::ShadowTreeDelegate { public void startEmptySurface(facebook::react::ShadowTree::Unique&& shadowTree) const noexcept; public void startSurface(facebook::react::ShadowTree::Unique&& shadowTree, const std::string& moduleName, const folly::dynamic& props, facebook::react::DisplayMode displayMode) const noexcept; public void stopSurfaceForAnimationDelegate(facebook::react::SurfaceId surfaceId) const; + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props); public void unregisterCommitHook(facebook::react::UIManagerCommitHook& commitHook); public void unregisterMountHook(facebook::react::UIManagerMountHook& mountHook); @@ -5297,6 +5302,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~UIManagerDelegate() noexcept = default; } @@ -11381,6 +11387,58 @@ struct facebook::react::dom::RNMeasureRect { static constexpr facebook::react::Tag facebook::react::animated::undefinedAnimatedNodeIdentifier; +static constexpr int facebook::react::animationbackend::CMD_BACKGROUND_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_LEFT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_RIGHT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_BOTTOM_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_END_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_END_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_END_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_LEFT_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_RIGHT_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_START_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_START_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_START_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_COLOR; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_END_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_LEFT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_RIGHT_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_BORDER_TOP_START_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_COLOR; +static constexpr int facebook::react::animationbackend::CMD_ELEVATION; +static constexpr int facebook::react::animationbackend::CMD_END_OF_TRANSFORM; +static constexpr int facebook::react::animationbackend::CMD_END_OF_VIEW; +static constexpr int facebook::react::animationbackend::CMD_OPACITY; +static constexpr int facebook::react::animationbackend::CMD_SHADOW_OPACITY; +static constexpr int facebook::react::animationbackend::CMD_SHADOW_RADIUS; +static constexpr int facebook::react::animationbackend::CMD_START_OF_TRANSFORM; +static constexpr int facebook::react::animationbackend::CMD_START_OF_VIEW; +static constexpr int facebook::react::animationbackend::CMD_TINT_COLOR; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_MATRIX; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_PERSPECTIVE; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE_Y; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_ROTATE_Z; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SCALE; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SCALE_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SCALE_Y; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SKEW_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_SKEW_Y; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_TRANSLATE_X; +static constexpr int facebook::react::animationbackend::CMD_TRANSFORM_TRANSLATE_Y; +static constexpr int facebook::react::animationbackend::CMD_UNIT_DEG; +static constexpr int facebook::react::animationbackend::CMD_UNIT_PERCENT; +static constexpr int facebook::react::animationbackend::CMD_UNIT_PX; +static constexpr int facebook::react::animationbackend::CMD_UNIT_RAD; +static constexpr int facebook::react::animationbackend::CMD_Z_INDEX; +void facebook::react::animationbackend::packDynamicPropsToBuffers(facebook::react::Tag tag, const facebook::react::AnimatedProps& animatedProps, std::vector& intBuffer, std::vector& doubleBuffer); + + std::shared_ptr facebook::react::CoreComponentsRegistry::sharedProviderRegistry(); void facebook::react::CoreComponentsRegistry::addCoreComponents(std::shared_ptr registry); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index c1530e62333c..decfddb35efa 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -1595,6 +1595,7 @@ interface RCTMountingManager : public NSObject { public virtual void setContextContainer:(std::shared_ptr contextContainer); public virtual void setIsJSResponder:blockNativeResponder:forShadowView:(BOOL isJSResponder, BOOL blockNativeResponder, const facebook::react::ShadowView& shadowView); public virtual void synchronouslyUpdateViewOnUIThread:changedProps:componentDescriptor:(ReactTag reactTag, folly::dynamic props, const facebook::react::ComponentDescriptor& componentDescriptor); + public virtual void synchronouslyUpdateViewOnUIThread:withProps:(ReactTag reactTag, facebook::react::Props::Shared newProps); } interface RCTMultilineTextInputView : public RCTBaseTextInputView { @@ -3387,6 +3388,7 @@ protocol RCTSchedulerDelegate { public virtual void schedulerDidSendAccessibilityEvent:eventType:(const facebook::react::ShadowView& shadowView, const std::string& eventType); public virtual void schedulerDidSetIsJSResponder:blockNativeResponder:forShadowView:(BOOL isJSResponder, BOOL blockNativeResponder, const facebook::react::ShadowView& shadowView); public virtual void schedulerDidSynchronouslyUpdateViewOnUIThread:props:(facebook::react::Tag reactTag, folly::dynamic props); + public virtual void schedulerDidSynchronouslyUpdateViewWithAnimatedPropsOnUIThread:surfaceId:animatedProps:(facebook::react::Tag reactTag, facebook::react::SurfaceId surfaceId, const facebook::react::AnimatedProps& animatedProps); public virtual void schedulerShouldMergeReactRevision:(facebook::react::SurfaceId surfaceId); public virtual void schedulerShouldRenderTransactions:(std::shared_ptr mountingCoordinator); } @@ -4535,7 +4537,8 @@ class facebook::react::AnimationBackend : public facebook::react::UIManagerAnima public virtual void trigger() override; public void commitUpdates(facebook::react::SurfaceId surfaceId, facebook::react::SurfaceUpdates& surfaceUpdates); public void requestAsyncFlushForSurfaces(const std::set& surfaces); - public void synchronouslyUpdateProps(const std::unordered_map& updates); + public void synchronouslyUpdateProps(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); + public void synchronouslyUpdatePropsUnbuffered(const std::unordered_map& updates); } class facebook::react::AnimationBackendCommitHook : public facebook::react::UIManagerCommitHook { @@ -7100,6 +7103,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) override; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) override; public void addEventListener(std::shared_ptr listener); public void animationTick() const; @@ -7123,6 +7127,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; + public virtual void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~SchedulerDelegate() noexcept = default; } @@ -7831,6 +7836,7 @@ class facebook::react::UIManager : public facebook::react::ShadowTreeDelegate { public void startEmptySurface(facebook::react::ShadowTree::Unique&& shadowTree) const noexcept; public void startSurface(facebook::react::ShadowTree::Unique&& shadowTree, const std::string& moduleName, const folly::dynamic& props, facebook::react::DisplayMode displayMode) const noexcept; public void stopSurfaceForAnimationDelegate(facebook::react::SurfaceId surfaceId) const; + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props); public void unregisterCommitHook(facebook::react::UIManagerCommitHook& commitHook); public void unregisterMountHook(facebook::react::UIManagerMountHook& mountHook); @@ -7898,6 +7904,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~UIManagerDelegate() noexcept = default; } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index b085abf3af7e..c751c827a14c 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -1595,6 +1595,7 @@ interface RCTMountingManager : public NSObject { public virtual void setContextContainer:(std::shared_ptr contextContainer); public virtual void setIsJSResponder:blockNativeResponder:forShadowView:(BOOL isJSResponder, BOOL blockNativeResponder, const facebook::react::ShadowView& shadowView); public virtual void synchronouslyUpdateViewOnUIThread:changedProps:componentDescriptor:(ReactTag reactTag, folly::dynamic props, const facebook::react::ComponentDescriptor& componentDescriptor); + public virtual void synchronouslyUpdateViewOnUIThread:withProps:(ReactTag reactTag, facebook::react::Props::Shared newProps); } interface RCTMultilineTextInputView : public RCTBaseTextInputView { @@ -3387,6 +3388,7 @@ protocol RCTSchedulerDelegate { public virtual void schedulerDidSendAccessibilityEvent:eventType:(const facebook::react::ShadowView& shadowView, const std::string& eventType); public virtual void schedulerDidSetIsJSResponder:blockNativeResponder:forShadowView:(BOOL isJSResponder, BOOL blockNativeResponder, const facebook::react::ShadowView& shadowView); public virtual void schedulerDidSynchronouslyUpdateViewOnUIThread:props:(facebook::react::Tag reactTag, folly::dynamic props); + public virtual void schedulerDidSynchronouslyUpdateViewWithAnimatedPropsOnUIThread:surfaceId:animatedProps:(facebook::react::Tag reactTag, facebook::react::SurfaceId surfaceId, const facebook::react::AnimatedProps& animatedProps); public virtual void schedulerShouldMergeReactRevision:(facebook::react::SurfaceId surfaceId); public virtual void schedulerShouldRenderTransactions:(std::shared_ptr mountingCoordinator); } @@ -4534,7 +4536,8 @@ class facebook::react::AnimationBackend : public facebook::react::UIManagerAnima public virtual void trigger() override; public void commitUpdates(facebook::react::SurfaceId surfaceId, facebook::react::SurfaceUpdates& surfaceUpdates); public void requestAsyncFlushForSurfaces(const std::set& surfaces); - public void synchronouslyUpdateProps(const std::unordered_map& updates); + public void synchronouslyUpdateProps(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); + public void synchronouslyUpdatePropsUnbuffered(const std::unordered_map& updates); } class facebook::react::AnimationBackendCommitHook : public facebook::react::UIManagerCommitHook { @@ -7097,6 +7100,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) override; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) override; public void addEventListener(std::shared_ptr listener); public void animationTick() const; @@ -7120,6 +7124,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; + public virtual void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~SchedulerDelegate() noexcept = default; } @@ -7822,6 +7827,7 @@ class facebook::react::UIManager : public facebook::react::ShadowTreeDelegate { public void startEmptySurface(facebook::react::ShadowTree::Unique&& shadowTree) const noexcept; public void startSurface(facebook::react::ShadowTree::Unique&& shadowTree, const std::string& moduleName, const folly::dynamic& props, facebook::react::DisplayMode displayMode) const noexcept; public void stopSurfaceForAnimationDelegate(facebook::react::SurfaceId surfaceId) const; + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props); public void unregisterCommitHook(facebook::react::UIManagerCommitHook& commitHook); public void unregisterMountHook(facebook::react::UIManagerMountHook& mountHook); @@ -7889,6 +7895,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~UIManagerDelegate() noexcept = default; } diff --git a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api index 3914705ee83b..cb7c106591bd 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api @@ -885,7 +885,8 @@ class facebook::react::AnimationBackend : public facebook::react::UIManagerAnima public virtual void trigger() override; public void commitUpdates(facebook::react::SurfaceId surfaceId, facebook::react::SurfaceUpdates& surfaceUpdates); public void requestAsyncFlushForSurfaces(const std::set& surfaces); - public void synchronouslyUpdateProps(const std::unordered_map& updates); + public void synchronouslyUpdateProps(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); + public void synchronouslyUpdatePropsUnbuffered(const std::unordered_map& updates); } class facebook::react::AnimationBackendCommitHook : public facebook::react::UIManagerCommitHook { @@ -3044,6 +3045,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) override; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) override; public void addEventListener(std::shared_ptr listener); public void animationTick() const; @@ -3067,6 +3069,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; + public virtual void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~SchedulerDelegate() noexcept = default; } @@ -3691,6 +3694,7 @@ class facebook::react::UIManager : public facebook::react::ShadowTreeDelegate { public void startEmptySurface(facebook::react::ShadowTree::Unique&& shadowTree) const noexcept; public void startSurface(facebook::react::ShadowTree::Unique&& shadowTree, const std::string& moduleName, const folly::dynamic& props, facebook::react::DisplayMode displayMode) const noexcept; public void stopSurfaceForAnimationDelegate(facebook::react::SurfaceId surfaceId) const; + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props); public void unregisterCommitHook(facebook::react::UIManagerCommitHook& commitHook); public void unregisterMountHook(facebook::react::UIManagerMountHook& mountHook); @@ -3758,6 +3762,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~UIManagerDelegate() noexcept = default; } diff --git a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api index c294e79f1ee6..2865e3a6be72 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api @@ -884,7 +884,8 @@ class facebook::react::AnimationBackend : public facebook::react::UIManagerAnima public virtual void trigger() override; public void commitUpdates(facebook::react::SurfaceId surfaceId, facebook::react::SurfaceUpdates& surfaceUpdates); public void requestAsyncFlushForSurfaces(const std::set& surfaces); - public void synchronouslyUpdateProps(const std::unordered_map& updates); + public void synchronouslyUpdateProps(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); + public void synchronouslyUpdatePropsUnbuffered(const std::unordered_map& updates); } class facebook::react::AnimationBackendCommitHook : public facebook::react::UIManagerCommitHook { @@ -3041,6 +3042,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) override; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) override; public void addEventListener(std::shared_ptr listener); public void animationTick() const; @@ -3064,6 +3066,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; + public virtual void schedulerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~SchedulerDelegate() noexcept = default; } @@ -3682,6 +3685,7 @@ class facebook::react::UIManager : public facebook::react::ShadowTreeDelegate { public void startEmptySurface(facebook::react::ShadowTree::Unique&& shadowTree) const noexcept; public void startSurface(facebook::react::ShadowTree::Unique&& shadowTree, const std::string& moduleName, const folly::dynamic& props, facebook::react::DisplayMode displayMode) const noexcept; public void stopSurfaceForAnimationDelegate(facebook::react::SurfaceId surfaceId) const; + public void synchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props); public void unregisterCommitHook(facebook::react::UIManagerCommitHook& commitHook); public void unregisterMountHook(facebook::react::UIManagerMountHook& mountHook); @@ -3749,6 +3753,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; + public virtual void uiManagerShouldSynchronouslyUpdateAnimatedPropsOnUIThread(facebook::react::SurfaceId surfaceId, const std::unordered_map& updates) = 0; public virtual void uiManagerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; public virtual ~UIManagerDelegate() noexcept = default; }