1 #ifdef RCT_NEW_ARCH_ENABLED 2 3 #include "ShadowTreeCloner.h" 4 #include "FabricUtils.h" 5 6 namespace reanimated { 7 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 17 ShadowTreeCloner::~ShadowTreeCloner() { 18 #ifdef DEBUG 19 react_native_assert( 20 yogaChildrenUpdates_.empty() && 21 "Deallocating `ShadowTreeCloner` without calling `updateYogaChildren`."); 22 #endif 23 } 24 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 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