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
This commit is contained in:
Valentin Shergin
2020-02-26 22:08:22 -08:00
committed by Facebook Github Bot
parent 011b470961
commit 1aab70d0e2
7 changed files with 120 additions and 111 deletions
@@ -46,40 +46,5 @@ RootShadowNode::Unshared RootShadowNode::clone(
return newRootShadowNode;
}
RootShadowNode::Unshared RootShadowNode::clone(
ShadowNodeFamily const &shadowNodeFamily,
std::function<ShadowNode::Unshared(ShadowNode const &oldShadowNode)>
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<SharedShadowNodeList>(children),
});
}
return std::const_pointer_cast<RootShadowNode>(
std::static_pointer_cast<RootShadowNode const>(childNode));
}
} // namespace react
} // namespace facebook
@@ -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<ShadowNode::Unshared(ShadowNode const &oldShadowNode)>
callback) const;
};
} // namespace react
@@ -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>(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<ViewProps>();
auto &props = *viewProps;
auto newRootShadowNode =
std::static_pointer_cast<RootShadowNode>(rootShadowNode->cloneTree(
innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) {
auto viewProps = std::make_shared<ViewProps>();
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<ViewProps>();
auto &props = *viewProps;
auto newRootShadowNode =
std::static_pointer_cast<RootShadowNode>(rootShadowNode->cloneTree(
innerShadowNode->getFamily(), [](ShadowNode const &oldShadowNode) {
auto viewProps = std::make_shared<ViewProps>();
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>(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>(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<ShadowNode::ListOfShared const>(children)});
});
return oldShadowNode.clone(
{ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared const>(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>(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<ShadowNode::ListOfShared const>(children)});
});
return oldShadowNode.clone(
{ShadowNodeFragment::propsPlaceholder(),
std::make_shared<ShadowNode::ListOfShared const>(children)});
}));
EXPECT_TRUE(newRootShadowNode->layoutIfNeeded());
}
@@ -242,6 +242,40 @@ int ShadowNode::getStateRevision() const {
return stateRevision_;
}
ShadowNode::Unshared ShadowNode::cloneTree(
ShadowNodeFamily const &shadowNodeFamily,
std::function<ShadowNode::Unshared(ShadowNode const &oldShadowNode)>
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<SharedShadowNodeList>(children),
});
}
return std::const_pointer_cast<ShadowNode>(childNode);
}
#pragma mark - DebugStringConvertible
#if RN_DEBUG_STRING_CONVERTIBLE
@@ -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<ShadowNode::Unshared(ShadowNode const &oldShadowNode)>
callback) const;
#pragma mark - Getters
ComponentName getComponentName() const;
@@ -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>(rootShadowNode->cloneTree(
edge.shadowNode->getFamily(), [&](ShadowNode const &oldShadowNode) {
return alteration(entropy, oldShadowNode);
}));
}
static void alterShadowTree(
+11 -8
View File
@@ -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<RootShadowNode>(
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,
});
});
}));
});
});
}