From 1170a68755f953c16c85ce784aef476e6970fa7c Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Thu, 1 Feb 2024 00:33:54 -0800 Subject: [PATCH] Delete traitCast and identifier traits (#42748) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/42748 React Native has globally enabled RTTI within `rn_xplat_cxx_library`, ahead of RTTI being forced on (regardless of flag) in Android apps (it was previously enabled everywhere but Android, which has caused us no small share of headaches, with public JSI APIs designed around clients using RTTI). This diff: 1. Mechanically replaces usages of `traitCast` with equivalent calls to `dynamic_cast` or `dynamic_pointer_cast` 1. These have similar semantics as current iteration of `traitCast`, where we return `nullptr` for pointer form, or throw on invalid cast for reference form. 2. Removes `IdentifierTrait` as a requirement to cast to a ShadowNode 3. Removes the ShadowNode traits used solely as cast identities This enables consistent usage of `dynamic_cast` (including for user defined ShadowNodes), and also exposes some places where `traitCast` allowed implicit const conversion. The OSS builds should already have RTTI on, and will be able to use `dynamic_cast` on RN provided types (`traitCast` is not extendable). Changelog: [General][Breaking] - Delete traitCast and identifier traits Reviewed By: sammy-SC Differential Revision: D53215009 fbshipit-source-id: d20cbf66b725f5565fa5d03332010d87f2b08b61 --- .../ReactAndroid/src/main/jni/CMakeLists.txt | 1 - .../components/text/BaseTextShadowNode.cpp | 5 +- .../components/text/ParagraphShadowNode.cpp | 9 +- .../components/text/ParagraphShadowNode.h | 1 - .../components/text/RawTextShadowNode.h | 8 - .../renderer/components/text/TextShadowNode.h | 7 - .../AndroidTextInputShadowNode.h | 1 - .../iostextinput/TextInputShadowNode.h | 1 - .../renderer/components/view/ViewShadowNode.h | 6 - .../view/YogaLayoutableShadowNode.cpp | 47 +++--- .../view/YogaLayoutableShadowNode.h | 5 +- .../core/ConcreteComponentDescriptor.h | 7 +- .../react/renderer/core/ConcreteShadowNode.h | 4 - .../renderer/core/LayoutableShadowNode.cpp | 27 +--- .../renderer/core/LayoutableShadowNode.h | 3 - .../react/renderer/core/RawProps.h | 12 ++ .../react/renderer/core/ShadowNode.h | 4 - .../react/renderer/core/ShadowNodeTraits.h | 41 ++--- .../react/renderer/core/TraitCast.h | 90 ----------- .../renderer/core/tests/traitCastTest.cpp | 144 ------------------ .../react/renderer/mounting/ShadowView.cpp | 3 +- .../intersection/IntersectionObserver.cpp | 3 +- .../uimanager/PointerEventsProcessor.cpp | 2 + .../react/renderer/uimanager/UIManager.cpp | 5 +- .../renderer/uimanager/UIManagerBinding.cpp | 7 +- .../react/renderer/uimanager/primitives.h | 3 +- 26 files changed, 75 insertions(+), 371 deletions(-) delete mode 100644 packages/react-native/ReactCommon/react/renderer/core/TraitCast.h delete mode 100644 packages/react-native/ReactCommon/react/renderer/core/tests/traitCastTest.cpp diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index 59f047310fff76..0fe09d67baa626 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -154,7 +154,6 @@ add_executable(reactnative_unittest ${REACT_COMMON_DIR}/react/renderer/core/tests/PrimitivesTest.cpp ${REACT_COMMON_DIR}/react/renderer/core/tests/RawPropsTest.cpp ${REACT_COMMON_DIR}/react/renderer/core/tests/ShadowNodeFamilyTest.cpp - ${REACT_COMMON_DIR}/react/renderer/core/tests/traitCastTest.cpp ${REACT_COMMON_DIR}/react/renderer/debug/tests/DebugStringConvertibleTest.cpp ${REACT_COMMON_DIR}/react/renderer/element/tests/ElementTest.cpp ${REACT_COMMON_DIR}/react/renderer/graphics/tests/GraphicsTest.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextShadowNode.cpp index 58d28d4a807afe..2ff46e65dc879e 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextShadowNode.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include namespace facebook::react { @@ -33,7 +32,7 @@ void BaseTextShadowNode::buildAttributedString( for (const auto& childNode : parentNode.getChildren()) { // RawShadowNode auto rawTextShadowNode = - traitCast(childNode.get()); + dynamic_cast(childNode.get()); if (rawTextShadowNode != nullptr) { auto fragment = AttributedString::Fragment{}; fragment.string = rawTextShadowNode->getConcreteProps().text; @@ -49,7 +48,7 @@ void BaseTextShadowNode::buildAttributedString( } // TextShadowNode - auto textShadowNode = traitCast(childNode.get()); + auto textShadowNode = dynamic_cast(childNode.get()); if (textShadowNode != nullptr) { auto localTextAttributes = baseTextAttributes; localTextAttributes.apply( diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp index 85929d367d2d88..5d7d651dd0132d 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -31,7 +30,7 @@ ParagraphShadowNode::ParagraphShadowNode( const ShadowNodeFragment& fragment) : ConcreteViewShadowNode(sourceShadowNode, fragment) { auto& sourceParagraphShadowNode = - traitCast(sourceShadowNode); + dynamic_cast(sourceShadowNode); if (!fragment.children && !fragment.props && sourceParagraphShadowNode.getIsLayoutClean()) { // This ParagraphShadowNode was cloned but did not change @@ -84,7 +83,7 @@ Content ParagraphShadowNode::getContentWithMeasuredAttachments( for (const auto& attachment : content.attachments) { auto laytableShadowNode = - traitCast(attachment.shadowNode); + dynamic_cast(attachment.shadowNode); if (laytableShadowNode == nullptr) { continue; @@ -213,7 +212,7 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) { for (size_t i = 0; i < content.attachments.size(); i++) { auto& attachment = content.attachments.at(i); - if (traitCast(attachment.shadowNode) == + if (dynamic_cast(attachment.shadowNode) == nullptr) { // Not a layoutable `ShadowNode`, no need to lay it out. continue; @@ -231,7 +230,7 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) { static_cast(paragraphOwningShadowNode.get()); auto& layoutableShadowNode = - traitCast(*clonedShadowNode); + dynamic_cast(*clonedShadowNode); auto attachmentFrame = measurement.attachments[i].frame; auto attachmentSize = roundToPixel<&ceil>( diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.h index fd598951c6dd50..a5f8eeb9355464 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.h @@ -41,7 +41,6 @@ class ParagraphShadowNode final : public ConcreteViewShadowNode< static ShadowNodeTraits BaseTraits() { auto traits = ConcreteViewShadowNode::BaseTraits(); traits.set(ShadowNodeTraits::Trait::LeafYogaNode); - traits.set(ShadowNodeTraits::Trait::TextKind); traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode); #ifdef ANDROID diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/RawTextShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/text/RawTextShadowNode.h index 15d211b9d192e9..7d04c781c081e9 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/RawTextShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/text/RawTextShadowNode.h @@ -26,14 +26,6 @@ class RawTextShadowNode : public ConcreteShadowNode< RawTextProps> { public: using ConcreteShadowNode::ConcreteShadowNode; - static ShadowNodeTraits BaseTraits() { - auto traits = ConcreteShadowNode::BaseTraits(); - traits.set(IdentifierTrait()); - return traits; - } - static ShadowNodeTraits::Trait IdentifierTrait() { - return ShadowNodeTraits::Trait::RawText; - } }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/TextShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/text/TextShadowNode.h index 649097755132ce..695aba56cbc895 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/TextShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/text/TextShadowNode.h @@ -29,19 +29,12 @@ class TextShadowNode : public ConcreteShadowNode< public: static ShadowNodeTraits BaseTraits() { auto traits = ConcreteShadowNode::BaseTraits(); - #ifdef ANDROID traits.set(ShadowNodeTraits::Trait::FormsView); #endif - traits.set(IdentifierTrait()); - return traits; } - static ShadowNodeTraits::Trait IdentifierTrait() { - return ShadowNodeTraits::Trait::Text; - } - using ConcreteShadowNode::ConcreteShadowNode; #ifdef ANDROID diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h index 53f3d42a2dffa0..42b5769c550598 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h @@ -31,7 +31,6 @@ class AndroidTextInputShadowNode final : public ConcreteViewShadowNode< public: static ShadowNodeTraits BaseTraits() { auto traits = ConcreteViewShadowNode::BaseTraits(); - traits.set(ShadowNodeTraits::Trait::TextKind); traits.set(ShadowNodeTraits::Trait::LeafYogaNode); return traits; } diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.h index 88670730af8968..2b0377f7f3be6f 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.h @@ -34,7 +34,6 @@ class TextInputShadowNode final : public ConcreteViewShadowNode< static ShadowNodeTraits BaseTraits() { auto traits = ConcreteViewShadowNode::BaseTraits(); - traits.set(ShadowNodeTraits::Trait::TextKind); traits.set(ShadowNodeTraits::Trait::LeafYogaNode); traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode); return traits; diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.h index 4979d37485b02d..8fdad855e72208 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.h @@ -34,12 +34,6 @@ class ViewShadowNode final : public ConcreteViewShadowNode< ViewShadowNodeProps, ViewEventEmitter> { public: - static ShadowNodeTraits BaseTraits() { - auto traits = ConcreteViewShadowNode::BaseTraits(); - traits.set(ShadowNodeTraits::Trait::View); - return traits; - } - ViewShadowNode( const ShadowNodeFragment& fragment, const ShadowNodeFamily::Shared& family, diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index 1361692e034980..e72b06a984f7f4 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -25,6 +24,8 @@ namespace facebook::react { +static_assert(RawPropsFilterable); + static int FabricDefaultYogaLog( const YGConfigConstRef /*unused*/, const YGNodeConstRef /*unused*/, @@ -62,16 +63,6 @@ static int FabricDefaultYogaLog( thread_local LayoutContext threadLocalLayoutContext; -ShadowNodeTraits YogaLayoutableShadowNode::BaseTraits() { - auto traits = LayoutableShadowNode::BaseTraits(); - traits.set(IdentifierTrait()); - return traits; -} - -ShadowNodeTraits::Trait YogaLayoutableShadowNode::IdentifierTrait() { - return ShadowNodeTraits::Trait::YogaLayoutableKind; -} - YogaLayoutableShadowNode::YogaLayoutableShadowNode( const ShadowNodeFragment& fragment, const ShadowNodeFamily::Shared& family, @@ -123,8 +114,10 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( if (!getTraits().check(ShadowNodeTraits::Trait::LeafYogaNode)) { for (auto& child : getChildren()) { - if (auto layoutableChild = traitCast(child)) { - yogaLayoutableChildren_.push_back(layoutableChild); + if (auto layoutableChild = + std::dynamic_pointer_cast( + child)) { + yogaLayoutableChildren_.push_back(std::move(layoutableChild)); } } } @@ -210,7 +203,7 @@ void YogaLayoutableShadowNode::adoptYogaChild(size_t index) { !getTraits().check(ShadowNodeTraits::Trait::LeafYogaNode)); auto& childNode = - traitCast(*getChildren().at(index)); + dynamic_cast(*getChildren().at(index)); if (childNode.yogaNode_.getOwner() == nullptr) { // The child node is not owned. @@ -243,7 +236,8 @@ void YogaLayoutableShadowNode::appendChild( } if (auto yogaLayoutableChild = - traitCast(childNode)) { + std::dynamic_pointer_cast( + childNode)) { // Here we don't have information about the previous structure of the node // (if it that existed before), so we don't have anything to compare the // Yoga node with (like a previous version of this node). Therefore we must @@ -273,8 +267,9 @@ void YogaLayoutableShadowNode::replaceChild( ensureYogaChildrenLookFine(); auto layoutableOldChild = - traitCast(&oldChild); - auto layoutableNewChild = traitCast(newChild); + dynamic_cast(&oldChild); + auto layoutableNewChild = + std::dynamic_pointer_cast(newChild); if (layoutableOldChild == nullptr && layoutableNewChild == nullptr) { // No need to mutate yogaLayoutableChildren_ @@ -349,7 +344,8 @@ void YogaLayoutableShadowNode::updateYogaChildren() { for (size_t i = 0; i < getChildren().size(); i++) { if (auto yogaLayoutableChild = - traitCast(getChildren()[i])) { + std::dynamic_pointer_cast( + getChildren()[i])) { appendYogaChild(yogaLayoutableChild); adoptYogaChild(i); @@ -496,7 +492,7 @@ void YogaLayoutableShadowNode::configureYogaTree( } YGErrata YogaLayoutableShadowNode::resolveErrata(YGErrata defaultErrata) const { - if (auto viewShadowNode = traitCast(this)) { + if (auto viewShadowNode = dynamic_cast(this)) { const auto& props = viewShadowNode->getConcreteProps(); switch (props.experimental_layoutConformance) { case LayoutConformance::Classic: @@ -745,7 +741,7 @@ Rect YogaLayoutableShadowNode::getContentBounds() const { auto layoutMetricsWithOverflowInset = childNode.getLayoutMetrics(); if (layoutMetricsWithOverflowInset.displayType != DisplayType::None) { - auto viewChildNode = traitCast(&childNode); + auto viewChildNode = dynamic_cast(&childNode); auto hitSlop = viewChildNode != nullptr ? viewChildNode->getConcreteProps().hitSlop : EdgeInsets{}; @@ -776,6 +772,13 @@ Rect YogaLayoutableShadowNode::getContentBounds() const { return contentBounds; } +/*static*/ void YogaLayoutableShadowNode::filterRawProps(RawProps& rawProps) { + if (CoreFeatures::excludeYogaFromRawProps) { + // TODO: this shouldn't live in RawProps + rawProps.filterYogaStylePropsInDynamicConversion(); + } +} + #pragma mark - Yoga Connectors YGNodeRef YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector( @@ -837,7 +840,7 @@ YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector( YogaLayoutableShadowNode& YogaLayoutableShadowNode::shadowNodeFromContext( YGNodeConstRef yogaNode) { - return traitCast( + return dynamic_cast( *static_cast(YGNodeGetContext(yogaNode))); } @@ -1014,7 +1017,7 @@ void YogaLayoutableShadowNode::ensureYogaChildrenAlignment() const { auto& child = children.at(i); react_native_assert( yogaChild->getContext() == - traitCast(child.get())); + dynamic_cast(child.get())); } #endif } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h index d924d7366e9f04..cfebab4a6cbc98 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h @@ -26,9 +26,6 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode { using Shared = std::shared_ptr; using ListOfShared = std::vector; - static ShadowNodeTraits BaseTraits(); - static ShadowNodeTraits::Trait IdentifierTrait(); - #pragma mark - Constructors YogaLayoutableShadowNode( @@ -88,6 +85,8 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode { Rect getContentBounds() const; + static void filterRawProps(RawProps& rawProps); + protected: /* * Yoga config associated (only) with this particular node. diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h index ad8e60fb541da8..653f7700efa2a9 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h @@ -105,11 +105,8 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { return ShadowNodeT::defaultSharedProps(); } - if (CoreFeatures::excludeYogaFromRawProps) { - if (ShadowNodeT::IdentifierTrait() == - ShadowNodeTraits::Trait::YogaLayoutableKind) { - rawProps.filterYogaStylePropsInDynamicConversion(); - } + if constexpr (RawPropsFilterable) { + ShadowNodeT::filterRawProps(rawProps); } rawProps.parse(rawPropsParser_); diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h index ab2ed6cf4da621..4536bec362c380 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h @@ -70,10 +70,6 @@ class ConcreteShadowNode : public BaseShadowNodeT { return BaseShadowNodeT::BaseTraits(); } - static ShadowNodeTraits::Trait IdentifierTrait() { - return BaseShadowNodeT::IdentifierTrait(); - } - static UnsharedConcreteProps Props( const PropsParserContext& context, const RawProps& rawProps, diff --git a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp index 3d64fa601dc940..e0bbf1491f4f23 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -29,13 +28,13 @@ static LayoutableSmallVector calculateTransformedFrames( for (auto i = size; i > 0; --i) { auto currentShadowNode = - traitCast(shadowNodeList.at(i - 1)); + dynamic_cast(shadowNodeList.at(i - 1)); auto currentFrame = currentShadowNode->getLayoutMetrics().frame; if (policy.includeTransform) { if (Transform::isVerticalInversion(transformation)) { auto parentShadowNode = - traitCast(shadowNodeList.at(i)); + dynamic_cast(shadowNodeList.at(i)); currentFrame.origin.y = parentShadowNode->getLayoutMetrics().frame.size.height - currentFrame.size.height - currentFrame.origin.y; @@ -43,7 +42,7 @@ static LayoutableSmallVector calculateTransformedFrames( if (Transform::isHorizontalInversion(transformation)) { auto parentShadowNode = - traitCast(shadowNodeList.at(i)); + dynamic_cast(shadowNodeList.at(i)); currentFrame.origin.x = parentShadowNode->getLayoutMetrics().frame.size.width - currentFrame.size.width - currentFrame.origin.x; @@ -51,7 +50,7 @@ static LayoutableSmallVector calculateTransformedFrames( if (i != size) { auto parentShadowNode = - traitCast(shadowNodeList.at(i)); + dynamic_cast(shadowNodeList.at(i)); auto contentOriginOffset = parentShadowNode->getContentOriginOffset(); if (Transform::isVerticalInversion(transformation)) { contentOriginOffset.y = -contentOriginOffset.y; @@ -152,7 +151,7 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( // Step 2. // Computing the initial size of the measured node. auto descendantLayoutableNode = - traitCast(descendantNode); + dynamic_cast(descendantNode); if (descendantLayoutableNode == nullptr) { return EmptyLayoutMetrics; @@ -183,7 +182,7 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( auto size = shadowNodeList.size(); for (size_t i = 0; i < size; i++) { auto currentShadowNode = - traitCast(shadowNodeList.at(i)); + dynamic_cast(shadowNodeList.at(i)); if (currentShadowNode == nullptr) { return EmptyLayoutMetrics; @@ -241,16 +240,6 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( return layoutMetrics; } -ShadowNodeTraits LayoutableShadowNode::BaseTraits() { - auto traits = ShadowNodeTraits{}; - traits.set(IdentifierTrait()); - return traits; -} - -ShadowNodeTraits::Trait LayoutableShadowNode::IdentifierTrait() { - return ShadowNodeTraits::Trait::LayoutableKind; -} - LayoutMetrics LayoutableShadowNode::getLayoutMetrics() const { return layoutMetrics_; } @@ -278,7 +267,7 @@ LayoutableShadowNode::getLayoutableChildNodes() const { LayoutableShadowNode::UnsharedList layoutableChildren; for (const auto& childShadowNode : getChildren()) { auto layoutableChildShadowNode = - traitCast(childShadowNode.get()); + dynamic_cast(childShadowNode.get()); if (layoutableChildShadowNode != nullptr) { layoutableChildren.push_back( const_cast(layoutableChildShadowNode)); @@ -320,7 +309,7 @@ ShadowNode::Shared LayoutableShadowNode::findNodeAtPoint( const ShadowNode::Shared& node, Point point) { auto layoutableShadowNode = - traitCast(node.get()); + dynamic_cast(node.get()); if (layoutableShadowNode == nullptr) { return nullptr; diff --git a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.h index 94132cbc730ac3..f23d931c137a3f 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.h @@ -39,9 +39,6 @@ class LayoutableShadowNode : public ShadowNode { const ShadowNode& sourceShadowNode, const ShadowNodeFragment& fragment); - static ShadowNodeTraits BaseTraits(); - static ShadowNodeTraits::Trait IdentifierTrait(); - struct LayoutInspectingPolicy { bool includeTransform{true}; bool includeViewportOffset{false}; diff --git a/packages/react-native/ReactCommon/react/renderer/core/RawProps.h b/packages/react-native/ReactCommon/react/renderer/core/RawProps.h index 7edaa8a7ed30f0..73d693443f3a86 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/RawProps.h +++ b/packages/react-native/ReactCommon/react/renderer/core/RawProps.h @@ -137,4 +137,16 @@ class RawProps final { bool ignoreYogaStyleProps_{false}; }; +/* + * Once called, props will be filtered out during conversion to + * folly::dynamic. folly::dynamic conversion is only used on Android and props + * specific to Yoga do not need to be send over JNI to Android. + * This is a performance optimisation to minimise traffic between C++ and + * Java. + */ +template +concept RawPropsFilterable = requires(RawProps& rawProps) { + { T::filterRawProps(rawProps) } -> std::same_as; +}; + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h index 630082ce698692..74f08707b12c48 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h @@ -59,10 +59,6 @@ class ShadowNode : public Sealable, return ShadowNodeTraits{}; } - static ShadowNodeTraits::Trait IdentifierTrait() { - return ShadowNodeTraits::Trait::None; - } - #pragma mark - Constructors /* diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeTraits.h b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeTraits.h index d3fd255326d0cf..7ad24b150e2412 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeTraits.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeTraits.h @@ -28,71 +28,50 @@ class ShadowNodeTraits { // Note: // Not all traits are used yet (but all will be used in the near future). - // Inherits `LayoutableShadowNode`. - LayoutableKind = 1 << 0, - - // Inherits `YogaLayoutableShadowNode`. - YogaLayoutableKind = 1 << 1, - // Inherits `ConcreteViewShadowNode<>` template. - ViewKind = 1 << 2, - - // Inherits `BaseTextShadowNode`. - TextKind = 1 << 3, + ViewKind = 1 << 0, // Used when calculating relative layout in // LayoutableShadowNode::getRelativeLayoutMetrics. This trait marks node as // root, so when calculating relative layout, the calculation will not // traverse beyond this node. See T61257516 for details. - RootNodeKind = 1 << 4, - - // `ViewShadowNode` (exact!) class. - View = 1 << 5, + RootNodeKind = 1 << 1, // The node is hidden. // Nodes with this trait (and all their descendants) will not produce views. - Hidden = 1 << 6, + Hidden = 1 << 2, // Indicates that the `YogaLayoutableShadowNode` must set `isDirty` flag for // Yoga node when a `ShadowNode` is being cloned. `ShadowNode`s that modify // Yoga styles in the constructor (or later) *after* the `ShadowNode` // is cloned must set this trait. // Any Yoga node (not only Leaf ones) can have this trait. - DirtyYogaNode = 1 << 7, + DirtyYogaNode = 1 << 3, // Inherits `YogaLayoutableShadowNode` and enforces that the yoga node is a // leaf. - LeafYogaNode = 1 << 8, + LeafYogaNode = 1 << 4, // Inherits `YogaLayoutableShadowNode` and has a custom measure function. // Only Leaf nodes can have this trait. - MeasurableYogaNode = 1 << 9, + MeasurableYogaNode = 1 << 5, // Indicates that the `ShadowNode` must form a stacking context. // A Stacking Context forms a level of a `ShadowView` hierarchy (in contrast // with a level of a `ShadowNode` hierarchy). // See W3C standard for more details: https://www.w3.org/TR/CSS2/zindex.html - FormsStackingContext = 1 << 10, + FormsStackingContext = 1 << 6, // Indicates that the node must form a `ShadowView`. - FormsView = 1 << 11, + FormsView = 1 << 7, // Internal to `ShadowNode`; do not use it outside. // Indicates that `children` list is shared between nodes and need // to be cloned before the first mutation. - ChildrenAreShared = 1 << 12, - - // Inherits 'RawTextShadowNode' - RawText = 1 << 13, - - // Inherits 'TextShadowNode' - Text = 1 << 14, + ChildrenAreShared = 1 << 8, // Temporary (?) to indicate MapBuffer support on Android - AndroidMapBufferPropsSupported = 1 << 15, - - // Inherits 'ArtBaseShadowNode' (previously built into RN) - Art = 1 << 16, + AndroidMapBufferPropsSupported = 1 << 9, }; /* diff --git a/packages/react-native/ReactCommon/react/renderer/core/TraitCast.h b/packages/react-native/ReactCommon/react/renderer/core/TraitCast.h deleted file mode 100644 index 39dd31de3e84d5..00000000000000 --- a/packages/react-native/ReactCommon/react/renderer/core/TraitCast.h +++ /dev/null @@ -1,90 +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. - */ - -#pragma once - -#include -#include -#include - -namespace facebook::react::details { -template -ShadowNodePointerT traitCastPointer(ParamT shadowNode) { - auto expectedIdentifier = - std::remove_pointer_t::IdentifierTrait(); - if (!shadowNode || !shadowNode->getTraits().check(expectedIdentifier)) { - return nullptr; - } - - return static_cast(shadowNode); -} - -template -ShadowNodeRefT traitCastRef(ParamT&& shadowNode) { - auto expectedIdentifier = - std::remove_reference_t::IdentifierTrait(); - if (!shadowNode.getTraits().check(expectedIdentifier)) { - LOG(FATAL) << "Invalid ShadowNode cast\n" - << "Expected identifier: " << std::hex - << static_cast(expectedIdentifier) << "\n" - << "Actual traits: " << std::hex - << static_cast(shadowNode.getTraits().get()) << "\n"; - } - - return static_cast(shadowNode); -} - -template -std::shared_ptr traitCastShared( - const std::shared_ptr& shadowNode) { - auto expectedIdentifier = ShadowNodeT::IdentifierTrait(); - if (!shadowNode || !shadowNode->getTraits().check(expectedIdentifier)) { - return nullptr; - } - - return std::static_pointer_cast(shadowNode); -} -} // namespace facebook::react::details - -namespace facebook::react { - -// Cast from one ShadowNode reference to another, terminating if the cast is -// invalid. -template -ShadowNodeReferenceT traitCast(const ShadowNode& shadowNode) { - return details::traitCastRef(shadowNode); -} -template -ShadowNodeReferenceT traitCast(ShadowNode& shadowNode) { - return details::traitCastRef(shadowNode); -} - -// Cast from one ShadowNode pointer to another, returning nullptr if the cast is -// invalid. -template -ShadowNodePointerT traitCast(const ShadowNode* shadowNode) { - return details::traitCastPointer(shadowNode); -} -template -ShadowNodePointerT traitCast(ShadowNode* shadowNode) { - return details::traitCastPointer(shadowNode); -} - -// Cast from one ShadowNode shared_ptr to another, returning nullptr if the -// cast is invalid. -template -std::shared_ptr traitCast( - const std::shared_ptr& shadowNode) { - return details::traitCastShared(shadowNode); -} -template -std::shared_ptr traitCast( - const std::shared_ptr& shadowNode) { - return details::traitCastShared(shadowNode); -} - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/traitCastTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/traitCastTest.cpp deleted file mode 100644 index d08f5ab3aee41d..00000000000000 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/traitCastTest.cpp +++ /dev/null @@ -1,144 +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. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace facebook::react; - -TEST(traitCastTest, testOne) { - auto builder = simpleComponentBuilder(); - - auto viewShadowNode = std::shared_ptr{}; - auto scrollViewShadowNode = std::shared_ptr{}; - auto paragraphShadowNode = std::shared_ptr{}; - auto textShadowNode = std::shared_ptr{}; - auto rawTextShadowNode = std::shared_ptr{}; - - // clang-format off - auto element = - Element() - .reference(scrollViewShadowNode) - .children({ - Element() - .reference(paragraphShadowNode) - .children({ - Element() - .reference(textShadowNode), - Element() - .reference(rawTextShadowNode) - }), - Element() - .reference(viewShadowNode), - }); - // clang-format on - - auto rootShadowNode = builder.build(element); - - std::shared_ptr shadowNodeForRawTextShadowNode{rawTextShadowNode}; - std::shared_ptr shadowNodeForTextShadowNode{textShadowNode}; - - // Casting `nullptr` returns `nullptrs`. - ShadowNode* nullShadowNode = nullptr; - EXPECT_FALSE(traitCast(nullShadowNode)); - EXPECT_FALSE(traitCast(nullShadowNode)); - EXPECT_FALSE(traitCast(nullShadowNode)); - EXPECT_FALSE(traitCast(nullShadowNode)); - EXPECT_FALSE(traitCast( - std::shared_ptr(nullShadowNode))); - - // `ViewShadowNode` is `LayoutableShadowNode` and `YogaLayoutableShadowNode`. - EXPECT_TRUE(traitCast(viewShadowNode.get())); - EXPECT_TRUE(traitCast(viewShadowNode.get())); - EXPECT_NO_FATAL_FAILURE( - traitCast(*viewShadowNode)); - EXPECT_NO_FATAL_FAILURE( - traitCast(*viewShadowNode)); - EXPECT_NO_FATAL_FAILURE( - traitCast(*viewShadowNode)); - EXPECT_TRUE(traitCast(viewShadowNode.get())); - EXPECT_TRUE(traitCast(viewShadowNode)); - - // `ScrollViewShadowNode` is `LayoutableShadowNode` and - // `YogaLayoutableShadowNode`. - EXPECT_TRUE( - traitCast(scrollViewShadowNode.get())); - EXPECT_TRUE( - traitCast(scrollViewShadowNode.get())); - EXPECT_NO_FATAL_FAILURE( - traitCast(*scrollViewShadowNode)); - EXPECT_NO_FATAL_FAILURE( - traitCast(*scrollViewShadowNode)); - - // `ParagraphShadowNode` is `LayoutableShadowNode` and - // `YogaLayoutableShadowNode`. - EXPECT_TRUE( - traitCast(paragraphShadowNode.get())); - EXPECT_TRUE( - traitCast(paragraphShadowNode.get())); - EXPECT_NO_FATAL_FAILURE( - traitCast(*paragraphShadowNode)); - EXPECT_NO_FATAL_FAILURE( - traitCast(*paragraphShadowNode)); - - // `TextShadowNode` is *not* `LayoutableShadowNode` nor - // `YogaLayoutableShadowNode`. - EXPECT_FALSE(traitCast(textShadowNode.get())); - EXPECT_FALSE( - traitCast(textShadowNode.get())); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*textShadowNode), ""); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*textShadowNode), ""); - - // `RawTextShadowNode` is *not* `LayoutableShadowNode` nor - // `YogaLayoutableShadowNode`. - EXPECT_FALSE(traitCast(rawTextShadowNode.get())); - EXPECT_FALSE( - traitCast(rawTextShadowNode.get())); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*rawTextShadowNode), ""); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*rawTextShadowNode), ""); - - // trait cast to `RawTextShadowNode` works on `RawTextShadowNode` - // and not on TextShadowNode or ViewShadowNode - EXPECT_TRUE(traitCast( - shadowNodeForRawTextShadowNode.get())); - EXPECT_NO_FATAL_FAILURE( - traitCast(*shadowNodeForRawTextShadowNode)); - EXPECT_FALSE( - traitCast(shadowNodeForTextShadowNode.get())); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*shadowNodeForTextShadowNode), ""); - EXPECT_FALSE(traitCast(viewShadowNode.get())); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*viewShadowNode), ""); - - // trait cast to `TextShadowNode` works on `TextShadowNode` - // and not on RawTextShadowNode or ViewShadowNode - EXPECT_TRUE( - traitCast(shadowNodeForTextShadowNode.get())); - EXPECT_NO_FATAL_FAILURE( - traitCast(*shadowNodeForTextShadowNode)); - EXPECT_FALSE( - traitCast(shadowNodeForRawTextShadowNode.get())); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*shadowNodeForRawTextShadowNode), ""); - EXPECT_FALSE(traitCast(viewShadowNode.get())); - EXPECT_DEATH_IF_SUPPORTED( - traitCast(*viewShadowNode), ""); -} diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp index f191dd644ebae9..51b097b0b98b52 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/ShadowView.cpp @@ -9,13 +9,12 @@ #include #include -#include namespace facebook::react { static LayoutMetrics layoutMetricsFromShadowNode(const ShadowNode& shadowNode) { auto layoutableShadowNode = - traitCast(&shadowNode); + dynamic_cast(&shadowNode); return layoutableShadowNode != nullptr ? layoutableShadowNode->getLayoutMetrics() : EmptyLayoutMetrics; diff --git a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp index 2e478c78e3551a..a5f305525421fd 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp +++ b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace facebook::react { @@ -93,7 +92,7 @@ IntersectionObserver::updateIntersectionObservation( const RootShadowNode& rootShadowNode, double mountTime) { const auto layoutableRootShadowNode = - traitCast(&rootShadowNode); + dynamic_cast(&rootShadowNode); react_native_assert( layoutableRootShadowNode != nullptr && diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp index 28c5eca352c12d..e3ab96f2289e52 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/PointerEventsProcessor.cpp @@ -7,6 +7,8 @@ #include "PointerEventsProcessor.h" +#include + namespace facebook::react { ShadowNode::Shared PointerEventsProcessor::getShadowNodeFromEventTarget( diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp index e88f56f64c2c6c..5cf3e5eeb6ce39 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -322,7 +321,7 @@ ShadowNode::Shared UIManager::getNewestPositionedAncestorOfShadowNode( for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) { const auto layoutableAncestorShadowNode = - traitCast(&(it->first.get())); + dynamic_cast(&(it->first.get())); if (layoutableAncestorShadowNode == nullptr) { return nullptr; } @@ -439,7 +438,7 @@ LayoutMetrics UIManager::getRelativeLayoutMetrics( } auto layoutableAncestorShadowNode = - traitCast(ancestorShadowNode); + dynamic_cast(ancestorShadowNode); if (layoutableAncestorShadowNode == nullptr) { return EmptyLayoutMetrics; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index 90c01c772ada05..03633a8a48566f 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -706,7 +705,7 @@ jsi::Value UIManagerBinding::get( auto newestCloneOfShadowNode = uiManager->getNewestCloneOfShadowNode(*shadowNode); - auto layoutableShadowNode = traitCast( + auto layoutableShadowNode = dynamic_cast( newestCloneOfShadowNode.get()); Point originRelativeToParent = layoutableShadowNode != nullptr ? layoutableShadowNode->getLayoutMetrics().frame.origin @@ -1221,7 +1220,7 @@ jsi::Value UIManagerBinding::get( return jsi::Value::undefined(); } - auto layoutableShadowNode = traitCast( + auto layoutableShadowNode = dynamic_cast( newestCloneOfShadowNode.get()); // This should never happen if (layoutableShadowNode == nullptr) { @@ -1292,7 +1291,7 @@ jsi::Value UIManagerBinding::get( } auto layoutableShadowNode = - traitCast( + dynamic_cast( newestCloneOfShadowNode.get()); // This should never happen if (layoutableShadowNode == nullptr) { diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h b/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h index 62f0858028c361..5d2cd00a19b6f3 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h @@ -14,7 +14,6 @@ #include #include #include -#include #include namespace facebook::react { @@ -193,7 +192,7 @@ inline static jsi::Value getArrayOfInstanceHandlesFromShadowNodes( inline static void getTextContentInShadowNode( const ShadowNode& shadowNode, std::string& result) { - auto rawTextShadowNode = traitCast(&shadowNode); + auto rawTextShadowNode = dynamic_cast(&shadowNode); if (rawTextShadowNode != nullptr) { result.append(rawTextShadowNode->getConcreteProps().text); }