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