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