diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 79ae4e24dd0f56..c4a2cd600a373a 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2672,11 +2672,6 @@ public final class com/facebook/react/fabric/EmptyReactNativeConfig : com/facebo public fun getString (Ljava/lang/String;)Ljava/lang/String; } -public final class com/facebook/react/fabric/FabricComponents { - public static final field INSTANCE Lcom/facebook/react/fabric/FabricComponents; - public static final fun getFabricComponentName (Ljava/lang/String;)Ljava/lang/String; -} - public final class com/facebook/react/fabric/FabricSoLoader { public static final field INSTANCE Lcom/facebook/react/fabric/FabricSoLoader; public static final fun staticInit ()V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricComponents.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricComponents.kt deleted file mode 100644 index ee1c55701719e8..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricComponents.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 - -/** - * Utility class for Fabric components, this will be removed - * - * TODO T97384889: remove this class when the component names are unified between JS - Android - - * iOS - C++ - */ -public object FabricComponents { - - // TODO T97384889: unify component names between JS - Android - iOS - C++ - private val componentNames: Map = - mapOf( - "View" to "RCTView", - "Image" to "RCTImageView", - "ScrollView" to "RCTScrollView", - "Slider" to "RCTSlider", - "ModalHostView" to "RCTModalHostView", - "Paragraph" to "RCTText", - "Text" to "RCText", - "RawText" to "RCTRawText", - "ActivityIndicatorView" to "AndroidProgressBar", - "ShimmeringView" to "RKShimmeringView", - "TemplateView" to "RCTTemplateView", - "AxialGradientView" to "RCTAxialGradientView", - "Video" to "RCTVideo", - "Map" to "RCTMap", - "WebView" to "RCTWebView", - "Keyframes" to "RCTKeyframes", - "ImpressionTrackingView" to "RCTImpressionTrackingView", - "SafeAreaView" to "RCTSafeAreaView", - ) - - /** @return the name of component in the Fabric environment */ - @JvmStatic - public fun getFabricComponentName(componentName: String): String = - componentNames.get(componentName) ?: componentName -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/FabricNameComponentMapping.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/FabricNameComponentMapping.kt index 4775a788f5ef4e..c032448a7a33e7 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/FabricNameComponentMapping.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/FabricNameComponentMapping.kt @@ -7,12 +7,7 @@ package com.facebook.react.fabric.mounting.mountitems -/** - * Utility class for Fabric components, this will be removed - * - * TODO T97384889: remove this class when the component names are unified between JS - Android - - * iOS - C++ - */ +/** Utility class for Fabric components, this will be removed */ internal object FabricNameComponentMapping { private val componentNames: Map = mapOf( @@ -23,7 +18,7 @@ internal object FabricNameComponentMapping { "Slider" to "RCTSlider", "ModalHostView" to "RCTModalHostView", "Paragraph" to "RCTText", - "Text" to "RCText", + "Text" to "RCTText", "RawText" to "RCTRawText", "ActivityIndicatorView" to "AndroidProgressBar", "ShimmeringView" to "RKShimmeringView", @@ -39,7 +34,6 @@ internal object FabricNameComponentMapping { /** @return the name of component in the Fabric environment */ @JvmStatic fun getFabricComponentName(componentName: String): String { - val component = componentNames[componentName] - return component ?: componentName + return componentNames[componentName] ?: componentName } } 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 36f23bee043c59..fc8bcd1eed05f4 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 @@ -46,7 +46,9 @@ void FabricMountingManager::onSurfaceStop(SurfaceId surfaceId) { allocatedViewRegistry_.erase(surfaceId); } -static inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) { +namespace { + +inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) { switch (mountItemType) { case CppMountItem::Type::Create: return 2; // tag, isLayoutable @@ -72,7 +74,30 @@ static inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) { } } -static inline void updateBufferSizes( +inline int getObjectBufferSizeForType(CppMountItem::Type mountItemType) { + switch (mountItemType) { + case CppMountItem::Type::Create: + return 4; // component name, props, state, event emitter + case CppMountItem::Type::UpdateProps: + return 1; // props object + case CppMountItem::Type::UpdateState: + return 1; // state object + case CppMountItem::Type::UpdateEventEmitter: + return 1; // event emitter object + case CppMountItem::Type::UpdatePadding: + case CppMountItem::Type::UpdateLayout: + case CppMountItem::Type::UpdateOverflowInset: + case CppMountItem::Type::Insert: + case CppMountItem::Type::Remove: + case CppMountItem::Type::Delete: + return 0; + case CppMountItem::Undefined: + case CppMountItem::Multiple: + return -1; + } +} + +inline void updateBufferSizes( CppMountItem::Type mountItemType, size_t numInstructions, int& batchMountItemIntsSize, @@ -85,22 +110,11 @@ static inline void updateBufferSizes( numInstructions == 1 ? 1 : 2; // instructionType[, numInstructions] batchMountItemIntsSize += numInstructions * getIntBufferSizeForType(mountItemType); - - if (mountItemType == CppMountItem::Type::UpdateProps) { - batchMountItemObjectsSize += - numInstructions; // props object * numInstructions - } else if (mountItemType == CppMountItem::Type::UpdateState) { - batchMountItemObjectsSize += - numInstructions; // state object * numInstructions - } else if (mountItemType == CppMountItem::Type::UpdateEventEmitter) { - batchMountItemObjectsSize += - numInstructions; // EventEmitter object * numInstructions - } + batchMountItemObjectsSize += + numInstructions * getObjectBufferSizeForType(mountItemType); } -static inline void computeBufferSizes( - int& batchMountItemIntsSize, - int& batchMountItemObjectsSize, +inline std::pair computeBufferSizes( std::vector& cppCommonMountItems, std::vector& cppDeleteMountItems, std::vector& cppUpdatePropsMountItems, @@ -109,6 +123,9 @@ static inline void computeBufferSizes( std::vector& cppUpdateLayoutMountItems, std::vector& cppUpdateOverflowInsetMountItems, std::vector& cppUpdateEventEmitterMountItems) { + int batchMountItemIntsSize = 0; + int batchMountItemObjectsSize = 0; + CppMountItem::Type lastType = CppMountItem::Type::Undefined; int numSameType = 0; for (const auto& mountItem : cppCommonMountItems) { @@ -126,10 +143,7 @@ static inline void computeBufferSizes( } batchMountItemIntsSize += getIntBufferSizeForType(mountItemType); - if (mountItemType == CppMountItem::Type::Create) { - batchMountItemObjectsSize += - 4; // component name, props, state, event emitter - } + batchMountItemObjectsSize += getObjectBufferSizeForType(mountItemType); } updateBufferSizes( @@ -167,25 +181,8 @@ static inline void computeBufferSizes( cppDeleteMountItems.size(), batchMountItemIntsSize, batchMountItemObjectsSize); -} -static inline void writeIntBufferTypePreamble( - int mountItemType, - size_t numItems, - _JNIEnv* env, - jintArray& intBufferArray, - int& intBufferPosition) { - jint temp[2]; - if (numItems == 1) { - temp[0] = mountItemType; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp); - intBufferPosition += 1; - } else { - temp[0] = mountItemType | CppMountItem::Type::Multiple; - temp[1] = static_cast(numItems); - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 2, temp); - intBufferPosition += 2; - } + return std::make_pair(batchMountItemIntsSize, batchMountItemObjectsSize); } // TODO: this method will be removed when binding for components are code-gen @@ -202,7 +199,7 @@ jni::local_ref getPlatformComponentName(const ShadowView& shadowView) { return jni::make_jstring(shadowView.componentName); } -static inline float scale(Float value, Float pointScaleFactor) { +inline float scale(Float value, Float pointScaleFactor) { std::feclearexcept(FE_ALL_EXCEPT); float result = value * pointScaleFactor; if (std::fetestexcept(FE_OVERFLOW)) { @@ -218,7 +215,7 @@ static inline float scale(Float value, Float pointScaleFactor) { return result; } -jni::local_ref FabricMountingManager::getProps( +jni::local_ref getProps( const ShadowView& oldShadowView, const ShadowView& newShadowView) { auto componentName = newShadowView.componentName; @@ -235,6 +232,227 @@ jni::local_ref FabricMountingManager::getProps( return ReadableNativeMap::newObjectCxxArgs(newShadowView.props->rawProps); } +struct InstructionBuffer { + JNIEnv* env; + jintArray ints; + jni::local_ref> objects; + + int intsPosition = 0; + int objectsPosition = 0; + + inline void writeInt(int value) { + env->SetIntArrayRegion(ints, intsPosition, 1, &value); + intsPosition += 1; + } + + template + inline void writeIntArray(const std::array& buffer) { + env->SetIntArrayRegion(ints, intsPosition, N, buffer.data()); + intsPosition += N; + } + + inline void writeObject(jobject obj) { + objects->setElement(objectsPosition, obj); + objectsPosition += 1; + } + + template + inline void writeObjectsArray(const std::array& buffer) { + for (size_t i = 0; i < N; i++) { + objects->setElement(objectsPosition + i, buffer[i]); + } + objectsPosition += N; + } +}; + +inline void writeMountItemPreamble( + InstructionBuffer& buffer, + int mountItemType, + size_t numItems) { + if (numItems == 1) { + buffer.writeInt(mountItemType); + } else { + buffer.writeIntArray(std::array{ + mountItemType | CppMountItem::Type::Multiple, + static_cast(numItems)}); + } +} + +inline void writeCreateMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + int isLayoutable = + mountItem.newChildShadowView.layoutMetrics != EmptyLayoutMetrics ? 1 : 0; + buffer.writeIntArray( + std::array{mountItem.newChildShadowView.tag, isLayoutable}); + + auto componentName = getPlatformComponentName(mountItem.newChildShadowView); + + jni::local_ref props = + getProps(mountItem.oldChildShadowView, mountItem.newChildShadowView); + + // Do not hold onto Java object from C + // We DO want to hold onto C object from Java, since we don't know the + // lifetime of the Java object + jni::local_ref javaStateWrapper = nullptr; + if (mountItem.newChildShadowView.state != nullptr) { + javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); + StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); + cStateWrapper->setState(mountItem.newChildShadowView.state); + } + + // Do not hold a reference to javaEventEmitter from the C++ side. + auto javaEventEmitter = EventEmitterWrapper::newObjectCxxArgs( + mountItem.newChildShadowView.eventEmitter); + + buffer.writeObjectsArray(std::array{ + componentName.get(), + props.get(), + javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr, + javaEventEmitter.get()}); +} + +inline void writeDeleteMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + buffer.writeInt(mountItem.oldChildShadowView.tag); +} + +inline void writeInsertMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + buffer.writeIntArray(std::array{ + mountItem.newChildShadowView.tag, + mountItem.parentShadowView.tag, + mountItem.index}); +} + +inline void writeRemoveMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + buffer.writeIntArray(std::array{ + mountItem.oldChildShadowView.tag, + mountItem.parentShadowView.tag, + mountItem.index}); +} + +inline void writeUpdatePropsMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + buffer.writeInt(mountItem.newChildShadowView.tag); + buffer.writeObject( + getProps(mountItem.oldChildShadowView, mountItem.newChildShadowView) + .get()); +} + +inline void writeUpdateStateMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + buffer.writeInt(mountItem.newChildShadowView.tag); + + auto state = mountItem.newChildShadowView.state; + // Do not hold onto Java object from C + // We DO want to hold onto C object from Java, since we don't know the + // lifetime of the Java object + jni::local_ref javaStateWrapper = nullptr; + if (state != nullptr) { + javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); + StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); + cStateWrapper->setState(state); + } + + buffer.writeObject( + javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr); +} + +inline void writeUpdateLayoutMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + const auto& layoutMetrics = mountItem.newChildShadowView.layoutMetrics; + auto pointScaleFactor = layoutMetrics.pointScaleFactor; + auto frame = layoutMetrics.frame; + + int x = round(scale(frame.origin.x, pointScaleFactor)); + int y = round(scale(frame.origin.y, pointScaleFactor)); + int w = round(scale(frame.size.width, pointScaleFactor)); + int h = round(scale(frame.size.height, pointScaleFactor)); + + if (ReactNativeFeatureFlags::setAndroidLayoutDirection()) { + buffer.writeIntArray(std::array{ + mountItem.newChildShadowView.tag, + mountItem.parentShadowView.tag, + x, + y, + w, + h, + toInt(layoutMetrics.displayType), + toInt(layoutMetrics.layoutDirection)}); + } else { + buffer.writeIntArray(std::array{ + mountItem.newChildShadowView.tag, + mountItem.parentShadowView.tag, + x, + y, + w, + h, + toInt(layoutMetrics.displayType)}); + } +} + +inline void writeUpdateEventEmitterMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + buffer.writeInt(mountItem.newChildShadowView.tag); + + // Do not hold a reference to javaEventEmitter from the C++ side. + auto javaEventEmitter = EventEmitterWrapper::newObjectCxxArgs( + mountItem.newChildShadowView.eventEmitter); + buffer.writeObject(javaEventEmitter.get()); +} + +inline void writeUpdatePaddingMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics; + auto pointScaleFactor = layoutMetrics.pointScaleFactor; + auto contentInsets = layoutMetrics.contentInsets; + + int insetLeft = floor(scale(contentInsets.left, pointScaleFactor)); + int insetTop = floor(scale(contentInsets.top, pointScaleFactor)); + int insetRight = floor(scale(contentInsets.right, pointScaleFactor)); + int insetBottom = floor(scale(contentInsets.bottom, pointScaleFactor)); + + buffer.writeIntArray(std::array{ + mountItem.newChildShadowView.tag, + insetLeft, + insetTop, + insetRight, + insetBottom}); +} + +inline void writeUpdateOverflowInsetMountItem( + InstructionBuffer& buffer, + const CppMountItem& mountItem) { + auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics; + auto pointScaleFactor = layoutMetrics.pointScaleFactor; + auto overflowInset = layoutMetrics.overflowInset; + + int overflowInsetLeft = round(scale(overflowInset.left, pointScaleFactor)); + int overflowInsetTop = round(scale(overflowInset.top, pointScaleFactor)); + int overflowInsetRight = round(scale(overflowInset.right, pointScaleFactor)); + int overflowInsetBottom = + round(scale(overflowInset.bottom, pointScaleFactor)); + + buffer.writeIntArray(std::array{ + mountItem.newChildShadowView.tag, + overflowInsetLeft, + overflowInsetTop, + overflowInsetRight, + overflowInsetBottom}); +} + +} // namespace + void FabricMountingManager::executeMount( const MountingTransaction& transaction) { SystraceSection section("FabricMountingManager::executeMount"); @@ -437,11 +655,7 @@ void FabricMountingManager::executeMount( // We now have all the information we need, including ordering of mount items, // to know exactly how much space must be allocated - int batchMountItemIntsSize = 0; - int batchMountItemObjectsSize = 0; - computeBufferSizes( - batchMountItemIntsSize, - batchMountItemObjectsSize, + auto [batchMountItemIntsSize, batchMountItemObjectsSize] = computeBufferSizes( cppCommonMountItems, cppDeleteMountItems, cppUpdatePropsMountItems, @@ -451,12 +665,6 @@ void FabricMountingManager::executeMount( cppUpdateOverflowInsetMountItems, cppUpdateEventEmitterMountItems); - static auto createMountItemsIntBufferBatchContainer = - JFabricUIManager::javaClassStatic() - ->getMethod( - jint, jintArray, jni::jtypeArray, jint)>( - "createIntBufferBatchMountItem"); - static auto scheduleMountItem = JFabricUIManager::javaClassStatic() ->getMethodNewIntArray(batchMountItemIntsSize); - auto objBufferArray = - jni::JArrayClass::newArray(batchMountItemObjectsSize); + InstructionBuffer buffer = { + env, + env->NewIntArray(batchMountItemIntsSize), + jni::JArrayClass::newArray(batchMountItemObjectsSize), + }; // Fill in arrays - int intBufferPosition = 0; - int objBufferPosition = 0; int prevMountItemType = -1; - jint temp[8]; + // Fill in CREATE instructions. for (int i = 0; i < cppCommonMountItems.size(); i++) { const auto& mountItem = cppCommonMountItems[i]; @@ -514,221 +721,77 @@ void FabricMountingManager::executeMount( numSameItemTypes++; } - writeIntBufferTypePreamble( - mountItemType, - numSameItemTypes, - env, - intBufferArray, - intBufferPosition); + writeMountItemPreamble(buffer, mountItemType, numSameItemTypes); + prevMountItemType = mountItemType; } - prevMountItemType = mountItemType; - - if (mountItemType == CppMountItem::Type::Create) { - auto componentName = - getPlatformComponentName(mountItem.newChildShadowView); - - int isLayoutable = - mountItem.newChildShadowView.layoutMetrics != EmptyLayoutMetrics ? 1 - : 0; - jni::local_ref props = - getProps(mountItem.oldChildShadowView, mountItem.newChildShadowView); - - // Do not hold onto Java object from C - // We DO want to hold onto C object from Java, since we don't know the - // lifetime of the Java object - jni::local_ref javaStateWrapper = nullptr; - if (mountItem.newChildShadowView.state != nullptr) { - javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); - StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); - cStateWrapper->setState(mountItem.newChildShadowView.state); - } - // Do not hold a reference to javaEventEmitter from the C++ side. - auto javaEventEmitter = EventEmitterWrapper::newObjectCxxArgs( - mountItem.newChildShadowView.eventEmitter); - temp[0] = mountItem.newChildShadowView.tag; - temp[1] = isLayoutable; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 2, temp); - intBufferPosition += 2; - - (*objBufferArray)[objBufferPosition++] = componentName.get(); - (*objBufferArray)[objBufferPosition++] = props.get(); - (*objBufferArray)[objBufferPosition++] = - javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr; - (*objBufferArray)[objBufferPosition++] = javaEventEmitter.get(); - } else if (mountItemType == CppMountItem::Type::Insert) { - temp[0] = mountItem.newChildShadowView.tag; - temp[1] = mountItem.parentShadowView.tag; - temp[2] = mountItem.index; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 3, temp); - intBufferPosition += 3; - } else if (mountItemType == CppMountItem::Remove) { - temp[0] = mountItem.oldChildShadowView.tag; - temp[1] = mountItem.parentShadowView.tag; - temp[2] = mountItem.index; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 3, temp); - intBufferPosition += 3; - } else { - LOG(ERROR) << "Unexpected CppMountItem type: " << mountItemType; + switch (mountItemType) { + case CppMountItem::Type::Create: + writeCreateMountItem(buffer, mountItem); + break; + case CppMountItem::Type::Insert: + writeInsertMountItem(buffer, mountItem); + break; + case CppMountItem::Type::Remove: + writeRemoveMountItem(buffer, mountItem); + break; + default: + LOG(FATAL) << "Unexpected CppMountItem type: " << mountItemType; } } if (!cppUpdatePropsMountItems.empty()) { - writeIntBufferTypePreamble( + writeMountItemPreamble( + buffer, CppMountItem::Type::UpdateProps, - cppUpdatePropsMountItems.size(), - env, - intBufferArray, - intBufferPosition); - + cppUpdatePropsMountItems.size()); for (const auto& mountItem : cppUpdatePropsMountItems) { - temp[0] = mountItem.newChildShadowView.tag; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp); - intBufferPosition += 1; - (*objBufferArray)[objBufferPosition++] = - getProps(mountItem.oldChildShadowView, mountItem.newChildShadowView); + writeUpdatePropsMountItem(buffer, mountItem); } } if (!cppUpdateStateMountItems.empty()) { - writeIntBufferTypePreamble( + writeMountItemPreamble( + buffer, CppMountItem::Type::UpdateState, - cppUpdateStateMountItems.size(), - env, - intBufferArray, - intBufferPosition); - + cppUpdateStateMountItems.size()); for (const auto& mountItem : cppUpdateStateMountItems) { - temp[0] = mountItem.newChildShadowView.tag; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp); - intBufferPosition += 1; - - auto state = mountItem.newChildShadowView.state; - // Do not hold onto Java object from C - // We DO want to hold onto C object from Java, since we don't know the - // lifetime of the Java object - jni::local_ref javaStateWrapper = nullptr; - if (state != nullptr) { - javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); - StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); - cStateWrapper->setState(state); - } - - (*objBufferArray)[objBufferPosition++] = - (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr); + writeUpdateStateMountItem(buffer, mountItem); } } if (!cppUpdatePaddingMountItems.empty()) { - writeIntBufferTypePreamble( + writeMountItemPreamble( + buffer, CppMountItem::Type::UpdatePadding, - cppUpdatePaddingMountItems.size(), - env, - intBufferArray, - intBufferPosition); - + cppUpdatePaddingMountItems.size()); for (const auto& mountItem : cppUpdatePaddingMountItems) { - auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics; - auto pointScaleFactor = layoutMetrics.pointScaleFactor; - auto contentInsets = layoutMetrics.contentInsets; - - int left = floor(scale(contentInsets.left, pointScaleFactor)); - int top = floor(scale(contentInsets.top, pointScaleFactor)); - int right = floor(scale(contentInsets.right, pointScaleFactor)); - int bottom = floor(scale(contentInsets.bottom, pointScaleFactor)); - - temp[0] = mountItem.newChildShadowView.tag; - temp[1] = left; - temp[2] = top; - temp[3] = right; - temp[4] = bottom; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 5, temp); - intBufferPosition += 5; + writeUpdatePaddingMountItem(buffer, mountItem); } } if (!cppUpdateLayoutMountItems.empty()) { - writeIntBufferTypePreamble( + writeMountItemPreamble( + buffer, CppMountItem::Type::UpdateLayout, - cppUpdateLayoutMountItems.size(), - env, - intBufferArray, - intBufferPosition); - + cppUpdateLayoutMountItems.size()); for (const auto& mountItem : cppUpdateLayoutMountItems) { - const auto& layoutMetrics = mountItem.newChildShadowView.layoutMetrics; - auto pointScaleFactor = layoutMetrics.pointScaleFactor; - auto frame = layoutMetrics.frame; - - int x = round(scale(frame.origin.x, pointScaleFactor)); - int y = round(scale(frame.origin.y, pointScaleFactor)); - int w = round(scale(frame.size.width, pointScaleFactor)); - int h = round(scale(frame.size.height, pointScaleFactor)); - int displayType = toInt(layoutMetrics.displayType); - int layoutDirection = toInt(layoutMetrics.layoutDirection); - - temp[0] = mountItem.newChildShadowView.tag; - temp[1] = mountItem.parentShadowView.tag; - temp[2] = x; - temp[3] = y; - temp[4] = w; - temp[5] = h; - temp[6] = displayType; - - if (ReactNativeFeatureFlags::setAndroidLayoutDirection()) { - temp[7] = layoutDirection; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 8, temp); - intBufferPosition += 8; - } else { - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 7, temp); - intBufferPosition += 7; - } + writeUpdateLayoutMountItem(buffer, mountItem); } } if (!cppUpdateOverflowInsetMountItems.empty()) { - writeIntBufferTypePreamble( + writeMountItemPreamble( + buffer, CppMountItem::Type::UpdateOverflowInset, - cppUpdateOverflowInsetMountItems.size(), - env, - intBufferArray, - intBufferPosition); - + cppUpdateOverflowInsetMountItems.size()); for (const auto& mountItem : cppUpdateOverflowInsetMountItems) { - auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics; - auto pointScaleFactor = layoutMetrics.pointScaleFactor; - auto overflowInset = layoutMetrics.overflowInset; - - int overflowInsetLeft = - round(scale(overflowInset.left, pointScaleFactor)); - int overflowInsetTop = round(scale(overflowInset.top, pointScaleFactor)); - int overflowInsetRight = - round(scale(overflowInset.right, pointScaleFactor)); - int overflowInsetBottom = - round(scale(overflowInset.bottom, pointScaleFactor)); - - temp[0] = mountItem.newChildShadowView.tag; - temp[1] = overflowInsetLeft; - temp[2] = overflowInsetTop; - temp[3] = overflowInsetRight; - temp[4] = overflowInsetBottom; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 5, temp); - intBufferPosition += 5; + writeUpdateOverflowInsetMountItem(buffer, mountItem); } } if (!cppUpdateEventEmitterMountItems.empty()) { - writeIntBufferTypePreamble( + writeMountItemPreamble( + buffer, CppMountItem::Type::UpdateEventEmitter, - cppUpdateEventEmitterMountItems.size(), - env, - intBufferArray, - intBufferPosition); - + cppUpdateEventEmitterMountItems.size()); for (const auto& mountItem : cppUpdateEventEmitterMountItems) { - temp[0] = mountItem.newChildShadowView.tag; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp); - intBufferPosition += 1; - - // Do not hold a reference to javaEventEmitter from the C++ side. - auto javaEventEmitter = EventEmitterWrapper::newObjectCxxArgs( - mountItem.newChildShadowView.eventEmitter); - (*objBufferArray)[objBufferPosition++] = javaEventEmitter.get(); + writeUpdateEventEmitterMountItem(buffer, mountItem); } } @@ -737,28 +800,28 @@ void FabricMountingManager::executeMount( // requires that the differ never produces "DELETE...CREATE" in that order for // the same tag. It's nice to be able to batch all similar operations together // for space efficiency. + // FIXME: this optimization is incorrect when multiple transactions are + // merged together if (!cppDeleteMountItems.empty()) { - writeIntBufferTypePreamble( - CppMountItem::Type::Delete, - cppDeleteMountItems.size(), - env, - intBufferArray, - intBufferPosition); - + writeMountItemPreamble( + buffer, CppMountItem::Type::Delete, cppDeleteMountItems.size()); for (const auto& mountItem : cppDeleteMountItems) { - temp[0] = mountItem.oldChildShadowView.tag; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp); - intBufferPosition += 1; + writeDeleteMountItem(buffer, mountItem); } } - // If there are no items, we pass a nullptr instead of passing the object - // through the JNI + static auto createMountItemsIntBufferBatchContainer = + JFabricUIManager::javaClassStatic() + ->getMethod( + jint, jintArray, jni::jtypeArray, jint)>( + "createIntBufferBatchMountItem"); auto batch = createMountItemsIntBufferBatchContainer( javaUIManager_, surfaceId, - batchMountItemIntsSize == 0 ? nullptr : intBufferArray, - batchMountItemObjectsSize == 0 ? nullptr : objBufferArray.get(), + // If there are no items, we pass a nullptr instead of passing the + // object through the JNI + batchMountItemIntsSize > 0 ? buffer.ints : nullptr, + batchMountItemObjectsSize > 0 ? buffer.objects.get() : nullptr, revisionNumber); auto finishTransactionEndTime = telemetryTimePointNow(); @@ -776,7 +839,7 @@ void FabricMountingManager::executeMount( telemetryTimePointToMilliseconds(finishTransactionEndTime), telemetry.getAffectedLayoutNodesCount()); - env->DeleteLocalRef(intBufferArray); + env->DeleteLocalRef(buffer.ints); } void FabricMountingManager::drainPreallocateViewsQueue() { 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 afafc989ab3736..79859bcb97df5c 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 @@ -83,10 +83,6 @@ class FabricMountingManager final { allocatedViewRegistry_{}; std::recursive_mutex allocatedViewsMutex_; - jni::local_ref getProps( - const ShadowView& oldShadowView, - const ShadowView& newShadowView); - /* * Calls FabricUIManager.preallocateView() on the Java side if view needs to * be preallocated. diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp index 9a29c126368be8..b2c840db60d1cb 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp @@ -40,6 +40,16 @@ enum class NoBreadcrumb {}; namespace facebook::react { +enum class ReparentMode { Flatten, Unflatten }; + +bool ShadowViewNodePair::operator==(const ShadowViewNodePair& rhs) const { + return this->shadowNode == rhs.shadowNode; +} + +bool ShadowViewNodePair::operator!=(const ShadowViewNodePair& rhs) const { + return !(*this == rhs); +} + /* * Extremely simple and naive implementation of a map. * The map is simple but it's optimized for particular constraints that we have diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.h b/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.h index f78fb229587001..c564b0a94ba966 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.h +++ b/packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.h @@ -14,7 +14,48 @@ namespace facebook::react { -enum class ReparentMode { Flatten, Unflatten }; +/* + * Describes pair of a `ShadowView` and a `ShadowNode`. + * This is not exposed to the mounting layer. + */ +struct ShadowViewNodePair final { + using NonOwningList = std::vector; + + ShadowView shadowView; + const ShadowNode* shadowNode; + + /** + * The ShadowNode does not form a stacking context, and the native views + * corresponding to its children may be parented to an ancestor. + */ + bool flattened{false}; + + /** + * Whether this ShadowNode should create a corresponding native view. + */ + bool isConcreteView{true}; + Point contextOrigin{0, 0}; + + size_t mountIndex{0}; + + /** + * This is nullptr unless `inOtherTree` is set to true. + * We rely on this only for marginal cases. TODO: could we + * rely on this more heavily to simplify the diffing algorithm + * overall? + */ + mutable const ShadowViewNodePair* otherTreePair{nullptr}; + + /* + * The stored pointer to `ShadowNode` represents an identity of the pair. + */ + bool operator==(const ShadowViewNodePair& rhs) const; + bool operator!=(const ShadowViewNodePair& rhs) const; + + bool inOtherTree() const { + return this->otherTreePair != nullptr; + } +}; /** * During differ, we need to keep some `ShadowViewNodePair`s in memory. diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp index d1db123889b3ba..d681e942a1676d 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp @@ -77,12 +77,4 @@ std::vector getDebugProps( #endif -bool ShadowViewNodePair::operator==(const ShadowViewNodePair& rhs) const { - return this->shadowNode == rhs.shadowNode; -} - -bool ShadowViewNodePair::operator!=(const ShadowViewNodePair& rhs) const { - return !(*this == rhs); -} - } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.h b/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.h index 6c776f31bab1e2..36dd55d37a58c3 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.h +++ b/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.h @@ -57,50 +57,6 @@ std::vector getDebugProps( #endif -/* - * Describes pair of a `ShadowView` and a `ShadowNode`. - * This is not exposed to the mounting layer. - * - */ -struct ShadowViewNodePair final { - using NonOwningList = std::vector; - - ShadowView shadowView; - const ShadowNode* shadowNode; - - /** - * The ShadowNode does not form a stacking context, and the native views - * corresponding to its children may be parented to an ancestor. - */ - bool flattened{false}; - - /** - * Whether this ShadowNode should create a corresponding native view. - */ - bool isConcreteView{true}; - Point contextOrigin{0, 0}; - - size_t mountIndex{0}; - - /** - * This is nullptr unless `inOtherTree` is set to true. - * We rely on this only for marginal cases. TODO: could we - * rely on this more heavily to simplify the diffing algorithm - * overall? - */ - mutable const ShadowViewNodePair* otherTreePair{nullptr}; - - /* - * The stored pointer to `ShadowNode` represents an identity of the pair. - */ - bool operator==(const ShadowViewNodePair& rhs) const; - bool operator!=(const ShadowViewNodePair& rhs) const; - - bool inOtherTree() const { - return this->otherTreePair != nullptr; - } -}; - } // namespace facebook::react namespace std { diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/stubs/stubs.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/stubs/stubs.cpp index b6de0a7ba7a1f5..3e96aa93f89224 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/stubs/stubs.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/stubs/stubs.cpp @@ -43,7 +43,7 @@ static void calculateShadowViewMutationsForNewTree( ShadowViewMutation::List& mutations, ViewNodePairScope& scope, const ShadowView& parentShadowView, - std::vector newChildPairs) { + ShadowViewNodePair::NonOwningList newChildPairs) { // Sorting pairs based on `orderIndex` if needed. reorderInPlaceIfNeeded(newChildPairs);