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