diff --git a/ReactCommon/fabric/components/view/ConcreteViewShadowNode.h b/ReactCommon/fabric/components/view/ConcreteViewShadowNode.h index e6eccb28fb1..de1a995b332 100644 --- a/ReactCommon/fabric/components/view/ConcreteViewShadowNode.h +++ b/ReactCommon/fabric/components/view/ConcreteViewShadowNode.h @@ -54,9 +54,10 @@ class ConcreteViewShadowNode : public ConcreteShadowNode< using ConcreteViewProps = ViewPropsT; ConcreteViewShadowNode( - const ShadowNodeFragment &fragment, - const ComponentDescriptor &componentDescriptor) - : BaseShadowNode(fragment, componentDescriptor), + ShadowNodeFragment const &fragment, + ComponentDescriptor const &componentDescriptor, + ShadowNodeTraits traits) + : BaseShadowNode(fragment, componentDescriptor, traits), YogaLayoutableShadowNode() { YogaLayoutableShadowNode::setProps( *std::static_pointer_cast(fragment.props)); @@ -65,8 +66,8 @@ class ConcreteViewShadowNode : public ConcreteShadowNode< }; ConcreteViewShadowNode( - const ShadowNode &sourceShadowNode, - const ShadowNodeFragment &fragment) + ShadowNode const &sourceShadowNode, + ShadowNodeFragment const &fragment) : BaseShadowNode(sourceShadowNode, fragment), YogaLayoutableShadowNode( static_cast(sourceShadowNode)) { diff --git a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h index a0c226c0f52..e6271d689c6 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h @@ -70,7 +70,12 @@ class ComponentDescriptor { virtual ComponentName getComponentName() const = 0; /* - * Creates a new `ShadowNode` of a particular type. + * Returns traits associated with a particular component type. + */ + virtual ShadowNodeTraits getTraits() const = 0; + + /* + * Creates a new `ShadowNode` of a particular component type. */ virtual SharedShadowNode createShadowNode( const ShadowNodeFragment &fragment) const = 0; diff --git a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h index f87bc5051a5..2e9e7cbb989 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h @@ -61,13 +61,18 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { return ShadowNodeT::Name(); } + ShadowNodeTraits getTraits() const override { + return ShadowNodeT::BaseTraits(); + } + SharedShadowNode createShadowNode( const ShadowNodeFragment &fragment) const override { assert(std::dynamic_pointer_cast(fragment.props)); assert(std::dynamic_pointer_cast( fragment.eventEmitter)); - auto shadowNode = std::make_shared(fragment, *this); + auto shadowNode = + std::make_shared(fragment, *this, getTraits()); adopt(shadowNode); diff --git a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h index cebd47dca4b..60fad4e5e10 100644 --- a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h @@ -50,6 +50,14 @@ class ConcreteShadowNode : public ShadowNode { return ComponentHandle(concreteComponentName); } + /* + * A set of traits associated with a particular class. + * Reimplement in subclasses to declare class-specific traits. + */ + static ShadowNodeTraits BaseTraits() { + return ShadowNodeTraits{}; + } + static SharedConcreteProps Props( const RawProps &rawProps, const SharedProps &baseProps = nullptr) { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index ab7ef1c64bf..453c2227797 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -32,8 +32,9 @@ bool ShadowNode::sameFamily(const ShadowNode &first, const ShadowNode &second) { #pragma mark - Constructors ShadowNode::ShadowNode( - const ShadowNodeFragment &fragment, - const ComponentDescriptor &componentDescriptor) + ShadowNodeFragment const &fragment, + ComponentDescriptor const &componentDescriptor, + ShadowNodeTraits traits) : #if RN_DEBUG_STRING_CONVERTIBLE revision_(1), @@ -48,10 +49,12 @@ ShadowNode::ShadowNode( fragment.surfaceId, fragment.eventEmitter, componentDescriptor)), - childrenAreShared_(true) { + traits_(traits) { assert(props_); assert(children_); + traits_.set(ShadowNodeTraits::Trait::ChildrenAreShared); + for (const auto &child : *children_) { child->family_->setParent(family_); } @@ -74,7 +77,7 @@ ShadowNode::ShadowNode( fragment.state ? fragment.state : sourceShadowNode.getMostRecentState()), family_(sourceShadowNode.family_), - childrenAreShared_(true) { + traits_(sourceShadowNode.traits_) { // `tag`, `surfaceId`, and `eventEmitter` cannot be changed with cloning. assert(fragment.tag == ShadowNodeFragment::tagPlaceholder()); assert(fragment.surfaceId == ShadowNodeFragment::surfaceIdPlaceholder()); @@ -84,6 +87,8 @@ ShadowNode::ShadowNode( assert(props_); assert(children_); + traits_.set(ShadowNodeTraits::Trait::ChildrenAreShared); + if (fragment.children) { for (const auto &child : *children_) { child->family_->setParent(family_); @@ -109,6 +114,10 @@ const SharedShadowNodeList &ShadowNode::getChildren() const { return *children_; } +ShadowNodeTraits ShadowNode::getTraits() const { + return traits_; +} + const SharedProps &ShadowNode::getProps() const { return props_; } @@ -215,10 +224,11 @@ void ShadowNode::setLocalData(const SharedLocalData &localData) { } void ShadowNode::cloneChildrenIfShared() { - if (!childrenAreShared_) { + if (!traits_.check(ShadowNodeTraits::Trait::ChildrenAreShared)) { return; } - childrenAreShared_ = false; + + traits_.unset(ShadowNodeTraits::Trait::ChildrenAreShared); children_ = std::make_shared(*children_); } diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index de525f07324..9b6440e0f2b 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -70,8 +71,9 @@ class ShadowNode : public virtual Sealable, * Creates a Shadow Node based on fields specified in a `fragment`. */ ShadowNode( - const ShadowNodeFragment &fragment, - const ComponentDescriptor &componentDescriptor); + ShadowNodeFragment const &fragment, + ComponentDescriptor const &componentDescriptor, + ShadowNodeTraits traits); /* * Creates a Shadow Node via cloning given `sourceShadowNode` and @@ -94,6 +96,11 @@ class ShadowNode : public virtual Sealable, ComponentName getComponentName() const; ComponentHandle getComponentHandle() const; + /* + * Returns a stored traits. + */ + ShadowNodeTraits getTraits() const; + SharedProps const &getProps() const; SharedShadowNodeList const &getChildren() const; SharedEventEmitter const &getEventEmitter() const; @@ -196,10 +203,10 @@ class ShadowNode : public virtual Sealable, ShadowNodeFamily::Shared family_; /* - * Indicates that `children` list is shared between nodes and need - * to be cloned before the first mutation. + * Traits associated with the particular `ShadowNode` class and an instance of + * that class. */ - bool childrenAreShared_; + ShadowNodeTraits traits_; }; } // namespace react diff --git a/ReactCommon/fabric/core/shadownode/ShadowNodeTraits.cpp b/ReactCommon/fabric/core/shadownode/ShadowNodeTraits.cpp new file mode 100644 index 00000000000..6e200c32be3 --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/ShadowNodeTraits.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ShadowNodeTraits.h" + +namespace facebook { +namespace react {} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/ShadowNodeTraits.h b/ReactCommon/fabric/core/shadownode/ShadowNodeTraits.h new file mode 100644 index 00000000000..5fe7c69c6f2 --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/ShadowNodeTraits.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook { +namespace react { + +/* + * A set of predefined traits associated with a particular `ShadowNode` class + * and an instance of that class. Used for efficient checking for interface + * conformance for and storing important flags. + */ +class ShadowNodeTraits { + public: + /* + * Underlying type for the traits. + * The first 16 bits are reserved for Core. + */ + enum Trait : int32_t { + None = 0, + + // 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, + + // Inherits `YogaLayoutableShadowNode` and enforces that the `YGNode` is a + // leaf. + LeafYogaNode = 1 << 10, + + // Inherits `LayoutableShadowNode` and calls `measure()`. + HasMeasure = 1 << 11, + + // 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 << 15, + }; + + /* + * Sets, unsets, and checks individual traits. + */ + inline void set(Trait trait) { + traits_ = ShadowNodeTraits::Trait(traits_ | trait); + } + + inline void unset(Trait trait) { + traits_ = ShadowNodeTraits::Trait(traits_ & ~trait); + } + + inline bool check(Trait traits) const { + return ShadowNodeTraits::Trait(traits_ & traits) == traits; + } + + private: + Trait traits_{Trait::None}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index 901bca38cc0..071ea5bba1c 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -40,7 +40,8 @@ TEST(ShadowNodeTest, handleShadowNodeCreation) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); ASSERT_FALSE(node->getSealed()); ASSERT_STREQ(node->getComponentName(), "Test"); @@ -65,7 +66,8 @@ TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto node2 = std::make_shared(*node, ShadowNodeFragment{}); ASSERT_STREQ(node->getComponentName(), "Test"); @@ -86,7 +88,8 @@ TEST(ShadowNodeTest, handleShadowNodeMutation) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto node2 = std::make_shared( ShadowNodeFragment{ /* .tag = */ 2, @@ -95,7 +98,8 @@ TEST(ShadowNodeTest, handleShadowNodeMutation) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto node3 = std::make_shared( ShadowNodeFragment{ /* .tag = */ 3, @@ -104,7 +108,8 @@ TEST(ShadowNodeTest, handleShadowNodeMutation) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); node1->appendChild(node2); node1->appendChild(node3); @@ -146,7 +151,8 @@ TEST(ShadowNodeTest, handleCloneFunction) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto firstNodeClone = firstNode->clone({}); @@ -183,7 +189,8 @@ TEST(ShadowNodeTest, handleLocalData) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto secondNode = std::make_shared( ShadowNodeFragment{ /* .tag = */ 9, @@ -192,7 +199,8 @@ TEST(ShadowNodeTest, handleLocalData) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto thirdNode = std::make_shared( ShadowNodeFragment{ /* .tag = */ 9, @@ -201,7 +209,8 @@ TEST(ShadowNodeTest, handleLocalData) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); firstNode->setLocalData(localData42); secondNode->setLocalData(localData42); @@ -244,7 +253,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto nodeABA = std::make_shared( ShadowNodeFragment{ @@ -254,7 +264,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto nodeABB = std::make_shared( ShadowNodeFragment{ /* .tag = */ ShadowNodeFragment::tagPlaceholder(), @@ -263,7 +274,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto nodeABC = std::make_shared( ShadowNodeFragment{ /* .tag = */ ShadowNodeFragment::tagPlaceholder(), @@ -272,7 +284,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto nodeABChildren = std::make_shared( SharedShadowNodeList{nodeABA, nodeABB, nodeABC}); @@ -284,7 +297,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ nodeABChildren, }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto nodeAC = std::make_shared( ShadowNodeFragment{ @@ -294,7 +308,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto nodeAChildren = std::make_shared( SharedShadowNodeList{nodeAA, nodeAB, nodeAC}); @@ -306,7 +321,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ nodeAChildren, }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); auto nodeZ = std::make_shared( ShadowNodeFragment{ @@ -316,7 +332,8 @@ TEST(ShadowNodeTest, handleBacktracking) { /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, - componentDescriptor); + componentDescriptor, + ShadowNodeTraits{}); std::vector> ancestors = {};