1*4440fb50SKudo Chien #ifdef RCT_NEW_ARCH_ENABLED
2*4440fb50SKudo Chien
3*4440fb50SKudo Chien #include "ShadowTreeCloner.h"
4*4440fb50SKudo Chien #include "FabricUtils.h"
5*4440fb50SKudo Chien
6*4440fb50SKudo Chien namespace reanimated {
7*4440fb50SKudo Chien
ShadowTreeCloner(std::shared_ptr<NewestShadowNodesRegistry> newestShadowNodesRegistry,std::shared_ptr<UIManager> uiManager,SurfaceId surfaceId)8*4440fb50SKudo Chien ShadowTreeCloner::ShadowTreeCloner(
9*4440fb50SKudo Chien std::shared_ptr<NewestShadowNodesRegistry> newestShadowNodesRegistry,
10*4440fb50SKudo Chien std::shared_ptr<UIManager> uiManager,
11*4440fb50SKudo Chien SurfaceId surfaceId)
12*4440fb50SKudo Chien : newestShadowNodesRegistry_{newestShadowNodesRegistry},
13*4440fb50SKudo Chien propsParserContext_{
14*4440fb50SKudo Chien surfaceId,
15*4440fb50SKudo Chien *getContextContainerFromUIManager(&*uiManager)} {}
16*4440fb50SKudo Chien
~ShadowTreeCloner()17*4440fb50SKudo Chien ShadowTreeCloner::~ShadowTreeCloner() {
18*4440fb50SKudo Chien #ifdef DEBUG
19*4440fb50SKudo Chien react_native_assert(
20*4440fb50SKudo Chien yogaChildrenUpdates_.empty() &&
21*4440fb50SKudo Chien "Deallocating `ShadowTreeCloner` without calling `updateYogaChildren`.");
22*4440fb50SKudo Chien #endif
23*4440fb50SKudo Chien }
24*4440fb50SKudo Chien
cloneWithNewProps(const ShadowNode::Shared & oldRootNode,const ShadowNodeFamily & family,RawProps && rawProps)25*4440fb50SKudo Chien ShadowNode::Unshared ShadowTreeCloner::cloneWithNewProps(
26*4440fb50SKudo Chien const ShadowNode::Shared &oldRootNode,
27*4440fb50SKudo Chien const ShadowNodeFamily &family,
28*4440fb50SKudo Chien RawProps &&rawProps) {
29*4440fb50SKudo Chien // adapted from ShadowNode::cloneTree
30*4440fb50SKudo Chien
31*4440fb50SKudo Chien auto ancestors = family.getAncestors(*oldRootNode);
32*4440fb50SKudo Chien
33*4440fb50SKudo Chien if (ancestors.empty()) {
34*4440fb50SKudo Chien return ShadowNode::Unshared{nullptr};
35*4440fb50SKudo Chien }
36*4440fb50SKudo Chien
37*4440fb50SKudo Chien auto &parent = ancestors.back();
38*4440fb50SKudo Chien auto &oldShadowNode = parent.first.get().getChildren().at(parent.second);
39*4440fb50SKudo Chien
40*4440fb50SKudo Chien const auto newest = newestShadowNodesRegistry_->get(oldShadowNode->getTag());
41*4440fb50SKudo Chien
42*4440fb50SKudo Chien const auto &source = newest == nullptr ? oldShadowNode : newest;
43*4440fb50SKudo Chien
44*4440fb50SKudo Chien const auto props = source->getComponentDescriptor().cloneProps(
45*4440fb50SKudo Chien propsParserContext_, source->getProps(), rawProps);
46*4440fb50SKudo Chien
47*4440fb50SKudo Chien auto newChildNode = source->clone({/* .props = */ props});
48*4440fb50SKudo Chien
49*4440fb50SKudo Chien for (auto it = ancestors.rbegin(); it != ancestors.rend(); ++it) {
50*4440fb50SKudo Chien auto &parentNode = it->first.get();
51*4440fb50SKudo Chien auto childIndex = it->second;
52*4440fb50SKudo Chien
53*4440fb50SKudo Chien auto children = parentNode.getChildren();
54*4440fb50SKudo Chien const auto &oldChildNode = *children.at(childIndex);
55*4440fb50SKudo Chien react_native_assert(ShadowNode::sameFamily(oldChildNode, *newChildNode));
56*4440fb50SKudo Chien
57*4440fb50SKudo Chien newestShadowNodesRegistry_->set(newChildNode, parentNode.getTag());
58*4440fb50SKudo Chien
59*4440fb50SKudo Chien if (!parentNode.getSealed()) {
60*4440fb50SKudo Chien // Optimization: if a ShadowNode is unsealed, we can directly update its
61*4440fb50SKudo Chien // children instead of cloning the whole path to the root node.
62*4440fb50SKudo Chien auto &parentNodeNonConst = const_cast<ShadowNode &>(parentNode);
63*4440fb50SKudo Chien parentNodeNonConst.replaceChild(oldChildNode, newChildNode, childIndex);
64*4440fb50SKudo Chien yogaChildrenUpdates_.insert(&parentNodeNonConst);
65*4440fb50SKudo Chien return std::const_pointer_cast<ShadowNode>(oldRootNode);
66*4440fb50SKudo Chien }
67*4440fb50SKudo Chien
68*4440fb50SKudo Chien children[childIndex] = newChildNode;
69*4440fb50SKudo Chien
70*4440fb50SKudo Chien newChildNode = parentNode.clone({
71*4440fb50SKudo Chien ShadowNodeFragment::propsPlaceholder(),
72*4440fb50SKudo Chien std::make_shared<ShadowNode::ListOfShared>(children),
73*4440fb50SKudo Chien });
74*4440fb50SKudo Chien }
75*4440fb50SKudo Chien
76*4440fb50SKudo Chien return std::const_pointer_cast<ShadowNode>(newChildNode);
77*4440fb50SKudo Chien }
78*4440fb50SKudo Chien
updateYogaChildren()79*4440fb50SKudo Chien void ShadowTreeCloner::updateYogaChildren() {
80*4440fb50SKudo Chien // Unfortunately, `replaceChild` does not update Yoga nodes, so we need to
81*4440fb50SKudo Chien // update them manually here.
82*4440fb50SKudo Chien for (ShadowNode *shadowNode : yogaChildrenUpdates_) {
83*4440fb50SKudo Chien static_cast<YogaLayoutableShadowNode *>(shadowNode)->updateYogaChildren();
84*4440fb50SKudo Chien }
85*4440fb50SKudo Chien #ifdef DEBUG
86*4440fb50SKudo Chien yogaChildrenUpdates_.clear();
87*4440fb50SKudo Chien #endif
88*4440fb50SKudo Chien }
89*4440fb50SKudo Chien
90*4440fb50SKudo Chien } // namespace reanimated
91*4440fb50SKudo Chien
92*4440fb50SKudo Chien #endif // RCT_NEW_ARCH_ENABLED
93