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