From 1aab70d0e2b2f3b3a134e15f13d6bc45da9ffc29 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 26 Feb 2020 22:03:14 -0800 Subject: [PATCH] Fabric: `RootShadowNode::clone` was renamed/moved to `ShadowNode::cloneTree` Summary: Cloning subtrees is not something specific to a RootNode, so it makes sense to have it in ShadowNode. Soon we will use that to clone subtrees inside Paragraph component to implement Inline Views. Changelog: [Internal] Fabric-specific internal change. Reviewed By: mdvacca Differential Revision: D20090666 fbshipit-source-id: 0a64ef9bda438cd55d5fd21d3ad83b36221fa89e --- .../fabric/components/root/RootShadowNode.cpp | 35 ------ .../fabric/components/root/RootShadowNode.h | 13 --- .../fabric/components/view/tests/ViewTest.cpp | 109 ++++++++++-------- .../fabric/core/shadownode/ShadowNode.cpp | 34 ++++++ .../fabric/core/shadownode/ShadowNode.h | 12 ++ .../mounting/tests/shadowTreeGeneration.h | 9 +- ReactCommon/fabric/uimanager/UIManager.cpp | 19 +-- 7 files changed, 120 insertions(+), 111 deletions(-) diff --git a/ReactCommon/fabric/components/root/RootShadowNode.cpp b/ReactCommon/fabric/components/root/RootShadowNode.cpp index 6d45346d447..99bbfa2a9e6 100644 --- a/ReactCommon/fabric/components/root/RootShadowNode.cpp +++ b/ReactCommon/fabric/components/root/RootShadowNode.cpp @@ -46,40 +46,5 @@ RootShadowNode::Unshared RootShadowNode::clone( return newRootShadowNode; } -RootShadowNode::Unshared RootShadowNode::clone( - ShadowNodeFamily const &shadowNodeFamily, - std::function - callback) const { - auto ancestors = shadowNodeFamily.getAncestors(*this); - - if (ancestors.size() == 0) { - return RootShadowNode::Unshared{nullptr}; - } - - auto &parent = ancestors.back(); - auto &oldShadowNode = parent.first.get().getChildren().at(parent.second); - - auto newShadowNode = callback(*oldShadowNode); - - auto childNode = newShadowNode; - - for (auto it = ancestors.rbegin(); it != ancestors.rend(); ++it) { - auto &parentNode = it->first.get(); - auto childIndex = it->second; - - auto children = parentNode.getChildren(); - assert(ShadowNode::sameFamily(*children.at(childIndex), *childNode)); - children[childIndex] = childNode; - - childNode = parentNode.clone({ - ShadowNodeFragment::propsPlaceholder(), - std::make_shared(children), - }); - } - - return std::const_pointer_cast( - std::static_pointer_cast(childNode)); -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/components/root/RootShadowNode.h b/ReactCommon/fabric/components/root/RootShadowNode.h index cb45c793cf7..f1a7b11d901 100644 --- a/ReactCommon/fabric/components/root/RootShadowNode.h +++ b/ReactCommon/fabric/components/root/RootShadowNode.h @@ -47,19 +47,6 @@ class RootShadowNode final RootShadowNode::Unshared clone( LayoutConstraints const &layoutConstraints, LayoutContext const &layoutContext) const; - - /* - * Clones the node (and partially the tree starting from the node) by - * replacing a `oldShadowNode` (which corresponds to a given `shadowNode`) - * with a node that `callback` returns. `oldShadowNode` might not be the same - * as `shadowNode` but they must share the same family. - * - * Returns `nullptr` if the operation cannot be performed successfully. - */ - RootShadowNode::Unshared clone( - ShadowNodeFamily const &shadowNodeFamily, - std::function - callback) const; }; } // namespace react diff --git a/ReactCommon/fabric/components/view/tests/ViewTest.cpp b/ReactCommon/fabric/components/view/tests/ViewTest.cpp index dd2497b9763..7faa2ace76e 100644 --- a/ReactCommon/fabric/components/view/tests/ViewTest.cpp +++ b/ReactCommon/fabric/components/view/tests/ViewTest.cpp @@ -78,13 +78,15 @@ TEST(ElementTest, testYogaDirtyFlag) { /* * Cloning props without changing them must *not* dirty Yoga nodes. */ - auto newRootShadowNode = rootShadowNode->clone( - innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { - auto &componentDescriptor = oldShadowNode.getComponentDescriptor(); - auto props = componentDescriptor.cloneProps( - oldShadowNode.getProps(), RawProps()); - return oldShadowNode.clone(ShadowNodeFragment{props}); - }); + auto newRootShadowNode = + std::static_pointer_cast(rootShadowNode->cloneTree( + innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { + auto &componentDescriptor = + oldShadowNode.getComponentDescriptor(); + auto props = componentDescriptor.cloneProps( + oldShadowNode.getProps(), RawProps()); + return oldShadowNode.clone(ShadowNodeFragment{props}); + })); EXPECT_FALSE(newRootShadowNode->layoutIfNeeded()); } @@ -93,21 +95,22 @@ TEST(ElementTest, testYogaDirtyFlag) { /* * Changing *non-layout* sub-props must *not* dirty Yoga nodes. */ - auto newRootShadowNode = rootShadowNode->clone( - innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { - auto viewProps = std::make_shared(); - auto &props = *viewProps; + auto newRootShadowNode = + std::static_pointer_cast(rootShadowNode->cloneTree( + innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { + auto viewProps = std::make_shared(); + auto &props = *viewProps; - props.nativeId = "some new native Id"; - props.foregroundColor = whiteColor(); - props.backgroundColor = blackColor(); - props.opacity = props.opacity + 0.042; - props.zIndex = props.zIndex + 42; - props.shouldRasterize = !props.shouldRasterize; - props.collapsable = !props.collapsable; + props.nativeId = "some new native Id"; + props.foregroundColor = whiteColor(); + props.backgroundColor = blackColor(); + props.opacity = props.opacity + 0.042; + props.zIndex = props.zIndex + 42; + props.shouldRasterize = !props.shouldRasterize; + props.collapsable = !props.collapsable; - return oldShadowNode.clone(ShadowNodeFragment{viewProps}); - }); + return oldShadowNode.clone(ShadowNodeFragment{viewProps}); + })); EXPECT_FALSE(newRootShadowNode->layoutIfNeeded()); } @@ -116,16 +119,17 @@ TEST(ElementTest, testYogaDirtyFlag) { /* * Changing *layout* sub-props *must* dirty Yoga nodes. */ - auto newRootShadowNode = rootShadowNode->clone( - innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { - auto viewProps = std::make_shared(); - auto &props = *viewProps; + auto newRootShadowNode = + std::static_pointer_cast(rootShadowNode->cloneTree( + innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { + auto viewProps = std::make_shared(); + auto &props = *viewProps; - props.yogaStyle.alignContent() = YGAlignBaseline; - props.yogaStyle.display() = YGDisplayNone; + props.yogaStyle.alignContent() = YGAlignBaseline; + props.yogaStyle.display() = YGDisplayNone; - return oldShadowNode.clone(ShadowNodeFragment{viewProps}); - }); + return oldShadowNode.clone(ShadowNodeFragment{viewProps}); + })); EXPECT_TRUE(newRootShadowNode->layoutIfNeeded()); } @@ -134,12 +138,13 @@ TEST(ElementTest, testYogaDirtyFlag) { /* * Removing all children *must* dirty Yoga nodes. */ - auto newRootShadowNode = rootShadowNode->clone( - innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { - return oldShadowNode.clone( - {ShadowNodeFragment::propsPlaceholder(), - ShadowNode::emptySharedShadowNodeSharedList()}); - }); + auto newRootShadowNode = + std::static_pointer_cast(rootShadowNode->cloneTree( + innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { + return oldShadowNode.clone( + {ShadowNodeFragment::propsPlaceholder(), + ShadowNode::emptySharedShadowNodeSharedList()}); + })); EXPECT_TRUE(newRootShadowNode->layoutIfNeeded()); } @@ -148,17 +153,18 @@ TEST(ElementTest, testYogaDirtyFlag) { /* * Removing the last child *must* dirty Yoga nodes. */ - auto newRootShadowNode = rootShadowNode->clone( - innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { - auto children = oldShadowNode.getChildren(); - children.pop_back(); + auto newRootShadowNode = + std::static_pointer_cast(rootShadowNode->cloneTree( + innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { + auto children = oldShadowNode.getChildren(); + children.pop_back(); - std::reverse(children.begin(), children.end()); + std::reverse(children.begin(), children.end()); - return oldShadowNode.clone( - {ShadowNodeFragment::propsPlaceholder(), - std::make_shared(children)}); - }); + return oldShadowNode.clone( + {ShadowNodeFragment::propsPlaceholder(), + std::make_shared(children)}); + })); EXPECT_TRUE(newRootShadowNode->layoutIfNeeded()); } @@ -167,16 +173,17 @@ TEST(ElementTest, testYogaDirtyFlag) { /* * Reversing a list of children *must* dirty Yoga nodes. */ - auto newRootShadowNode = rootShadowNode->clone( - innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { - auto children = oldShadowNode.getChildren(); + auto newRootShadowNode = + std::static_pointer_cast(rootShadowNode->cloneTree( + innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) { + auto children = oldShadowNode.getChildren(); - std::reverse(children.begin(), children.end()); + std::reverse(children.begin(), children.end()); - return oldShadowNode.clone( - {ShadowNodeFragment::propsPlaceholder(), - std::make_shared(children)}); - }); + return oldShadowNode.clone( + {ShadowNodeFragment::propsPlaceholder(), + std::make_shared(children)}); + })); EXPECT_TRUE(newRootShadowNode->layoutIfNeeded()); } diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index c9ce6a93fc7..7bfd30bf7a2 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -242,6 +242,40 @@ int ShadowNode::getStateRevision() const { return stateRevision_; } +ShadowNode::Unshared ShadowNode::cloneTree( + ShadowNodeFamily const &shadowNodeFamily, + std::function + callback) const { + auto ancestors = shadowNodeFamily.getAncestors(*this); + + if (ancestors.size() == 0) { + return ShadowNode::Unshared{nullptr}; + } + + auto &parent = ancestors.back(); + auto &oldShadowNode = parent.first.get().getChildren().at(parent.second); + + auto newShadowNode = callback(*oldShadowNode); + + auto childNode = newShadowNode; + + for (auto it = ancestors.rbegin(); it != ancestors.rend(); ++it) { + auto &parentNode = it->first.get(); + auto childIndex = it->second; + + auto children = parentNode.getChildren(); + assert(ShadowNode::sameFamily(*children.at(childIndex), *childNode)); + children[childIndex] = childNode; + + childNode = parentNode.clone({ + ShadowNodeFragment::propsPlaceholder(), + std::make_shared(children), + }); + } + + return std::const_pointer_cast(childNode); +} + #pragma mark - DebugStringConvertible #if RN_DEBUG_STRING_CONVERTIBLE diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index fa62432423b..66d2c6ce218 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -97,6 +97,18 @@ class ShadowNode : public Sealable, public DebugStringConvertible { */ UnsharedShadowNode clone(const ShadowNodeFragment &fragment) const; + /* + * Clones the node (and partially the tree starting from the node) by + * replacing a `oldShadowNode` (which corresponds to a given + * `shadowNodeFamily`) with a node that `callback` returns. + * + * Returns `nullptr` if the operation cannot be performed successfully. + */ + ShadowNode::Unshared cloneTree( + ShadowNodeFamily const &shadowNodeFamily, + std::function + callback) const; + #pragma mark - Getters ComponentName getComponentName() const; diff --git a/ReactCommon/fabric/mounting/tests/shadowTreeGeneration.h b/ReactCommon/fabric/mounting/tests/shadowTreeGeneration.h index a5486e239a6..b542b5d6744 100644 --- a/ReactCommon/fabric/mounting/tests/shadowTreeGeneration.h +++ b/ReactCommon/fabric/mounting/tests/shadowTreeGeneration.h @@ -171,10 +171,11 @@ static void alterShadowTree( ShadowNodeAlteration alteration) { auto edge = findRandomShadowNode(entropy, rootShadowNode); - rootShadowNode = rootShadowNode->clone( - edge.shadowNode->getFamily(), [&](ShadowNode const &oldShadowNode) { - return alteration(entropy, oldShadowNode); - }); + rootShadowNode = + std::static_pointer_cast(rootShadowNode->cloneTree( + edge.shadowNode->getFamily(), [&](ShadowNode const &oldShadowNode) { + return alteration(entropy, oldShadowNode); + })); } static void alterShadowTree( diff --git a/ReactCommon/fabric/uimanager/UIManager.cpp b/ReactCommon/fabric/uimanager/UIManager.cpp index b437064969a..5a93c782118 100644 --- a/ReactCommon/fabric/uimanager/UIManager.cpp +++ b/ReactCommon/fabric/uimanager/UIManager.cpp @@ -146,12 +146,14 @@ void UIManager::setNativeProps( shadowNode.getSurfaceId(), [&](ShadowTree const &shadowTree) { shadowTree.tryCommit( [&](RootShadowNode::Shared const &oldRootShadowNode) { - return oldRootShadowNode->clone( - shadowNode.getFamily(), [&](ShadowNode const &oldShadowNode) { - return oldShadowNode.clone({ - /* .props = */ props, - }); - }); + return std::static_pointer_cast( + oldRootShadowNode->cloneTree( + shadowNode.getFamily(), + [&](ShadowNode const &oldShadowNode) { + return oldShadowNode.clone({ + /* .props = */ props, + }); + })); }, true && stateReconciliationEnabled_); }); @@ -197,7 +199,8 @@ void UIManager::updateState(StateUpdate const &stateUpdate) const { family->getSurfaceId(), [&](ShadowTree const &shadowTree) { shadowTree.tryCommit([&](RootShadowNode::Shared const &oldRootShadowNode) { - return oldRootShadowNode->clone( + return std::static_pointer_cast< + RootShadowNode>(oldRootShadowNode->cloneTree( *family, [&](ShadowNode const &oldShadowNode) { auto newData = callback(oldShadowNode.getState()->getDataPointer()); @@ -209,7 +212,7 @@ void UIManager::updateState(StateUpdate const &stateUpdate) const { /* .children = */ ShadowNodeFragment::childrenPlaceholder(), /* .state = */ newState, }); - }); + })); }); }); }