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