PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/react-native/ReactCommon/react/renderer/uimanager
Просмотр файла: UIManagerUpdateShadowTree.cpp
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "UIManager.h"
#include <glog/logging.h>
#include <react/debug/react_native_assert.h>
#include <react/renderer/components/root/RootShadowNode.h>
#include <react/renderer/core/ShadowNode.h>
#include <deque>
#include <memory>
#include <optional>
#include <ranges>
#include <vector>
namespace facebook::react {
namespace {
struct ShadowNodeUpdateInfo {
Tag tag;
int depth;
std::weak_ptr<const ShadowNode> node;
// populate for node that needs props update
std::optional<folly::dynamic> changedProps;
// populate for node that's also a ancestor node for updated nodes
std::vector<int> updatedChildrenIndices{};
};
void addAncestorsToUpdateList(
std::shared_ptr<const ShadowNode>& shadowNode,
std::shared_ptr<const RootShadowNode>& rootShadowNode,
std::vector<ShadowNodeUpdateInfo>& shadowNodesToUpdate) {
// list of ancestors from root ShadowNode to current ShadowNode's parent
auto ancestors = shadowNode->getFamily().getAncestors(*rootShadowNode);
std::vector<std::shared_ptr<const ShadowNode>> ancestorShadowNodesShared{};
ancestorShadowNodesShared.resize(ancestors.size());
std::shared_ptr<const ShadowNode> currentShadowNode = rootShadowNode;
auto ancestorIndex = 0;
while (!currentShadowNode->getChildren().empty() &&
currentShadowNode->getTag() != shadowNode->getTag()) {
ancestorShadowNodesShared[ancestorIndex] = currentShadowNode;
auto children = currentShadowNode->getChildren();
auto childIndex = ancestors[ancestorIndex].second;
currentShadowNode = children[childIndex];
ancestorIndex++;
}
int ancestorDepth = static_cast<int>(ancestors.size() - 1);
// iterate from current ShadowNode's parent to root ShadowNode
for (auto iter = ancestors.rbegin(); iter != ancestors.rend(); ++iter) {
auto& ancestorShadowNode = iter->first.get();
auto ancestorTag = ancestorShadowNode.getTag();
auto ancestorAddedToUpdateList = std::find_if(
shadowNodesToUpdate.begin(),
shadowNodesToUpdate.end(),
[ancestorTag](const auto& elem) { return elem.tag == ancestorTag; });
if (ancestorAddedToUpdateList == shadowNodesToUpdate.end()) {
react_native_assert(
ancestorShadowNodesShared[ancestorDepth]->getTag() ==
ancestorShadowNode.getTag());
shadowNodesToUpdate.push_back({
.tag = ancestorShadowNode.getTag(),
.depth = ancestorDepth,
.node = ancestorShadowNodesShared[ancestorDepth],
.updatedChildrenIndices = {iter->second},
});
} else {
ancestorAddedToUpdateList->updatedChildrenIndices.push_back(iter->second);
}
ancestorDepth--;
}
}
} // namespace
/* Commit a map of ShadowNode props to ShadowTree, with guarantee that each
* ShadowNode is cloned only once in the commit.
* The tree cloning algorithm is inspired by `cloneShadowTreeWithNewProps` in
* https://github.com/software-mansion/react-native-reanimated/ (under MIT
* license).
*/
void UIManager::updateShadowTree(
const std::unordered_map<Tag, folly::dynamic>& tagToProps) {
const auto& contextContainer = *contextContainer_;
std::unordered_map<Tag, folly::dynamic> remainingTagToProps = tagToProps;
getShadowTreeRegistry().enumerate([&](const ShadowTree& shadowTree,
bool& stop) {
if (remainingTagToProps.empty()) {
stop = true;
return;
}
auto rootShadowNode = shadowTree.getCurrentRevision().rootShadowNode;
auto surfaceId = rootShadowNode->getSurfaceId();
std::vector<ShadowNodeUpdateInfo> shadowNodesToUpdate;
// Step 1: Create a list of shadow nodes to update
// which includes all the ShadowNodes of tags in input map, plus all
// their ancestors
std::deque<std::shared_ptr<const ShadowNode>> deque{rootShadowNode};
int depth = 0;
while (!deque.empty()) {
auto size = deque.size();
for (auto i = 0; i < size; i++) {
auto shadowNode = std::move(deque.front());
deque.pop_front();
if (auto nodesPropsIt = remainingTagToProps.find(shadowNode->getTag());
nodesPropsIt != remainingTagToProps.end()) {
auto shadowNodeTag = shadowNode->getTag();
auto shadowNodeAddedToUpdateList = std::find_if(
shadowNodesToUpdate.begin(),
shadowNodesToUpdate.end(),
[shadowNodeTag](const auto& elem) {
return elem.tag == shadowNodeTag;
});
if (shadowNodeAddedToUpdateList == shadowNodesToUpdate.end()) {
shadowNodesToUpdate.push_back(
{.tag = shadowNodeTag,
.depth = depth,
.node = shadowNode,
.changedProps = nodesPropsIt->second});
} else {
shadowNodeAddedToUpdateList->changedProps = nodesPropsIt->second;
}
remainingTagToProps.erase(nodesPropsIt->first);
// Add all its ancestors to shadowNodesToUpdate list
addAncestorsToUpdateList(
shadowNode, rootShadowNode, shadowNodesToUpdate);
}
for (const auto& child : shadowNode->getChildren()) {
deque.push_back(child);
}
}
depth++;
}
if (shadowNodesToUpdate.empty()) {
return;
}
// Step 2: Clone nodes from children to ancestors
std::sort(
shadowNodesToUpdate.begin(),
shadowNodesToUpdate.end(),
[](const auto& a, const auto& b) { return a.depth > b.depth; });
std::unordered_map<Tag, std::shared_ptr<ShadowNode>> clonedShadowNodes;
for (auto& nodeUpdateInfo : shadowNodesToUpdate) {
if (auto oldShadowNode = nodeUpdateInfo.node.lock()) {
Props::Shared newProps;
if (nodeUpdateInfo.changedProps) {
PropsParserContext propsParserContext{surfaceId, contextContainer};
auto componentDescriptor =
componentDescriptorRegistry_
->findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(
oldShadowNode->getComponentHandle());
newProps = componentDescriptor->cloneProps(
propsParserContext,
oldShadowNode->getProps(),
RawProps(nodeUpdateInfo.changedProps.value()));
} else {
newProps = oldShadowNode->getProps();
}
ShadowNodeFragment fragment;
auto children = oldShadowNode->getChildren();
// If children are previously updated (children should be cloned and
// updated before parents), add it to the children list of ShadowNode
for (auto& updatedChildIndex : nodeUpdateInfo.updatedChildrenIndices) {
if (updatedChildIndex < children.size()) {
auto childTag = children[updatedChildIndex]->getTag();
auto clonedShadowNodesIt = clonedShadowNodes.find(childTag);
if (clonedShadowNodesIt != clonedShadowNodes.end()) {
children[updatedChildIndex] = clonedShadowNodesIt->second;
} else {
LOG(ERROR) << "Child ShadowNode has not been cloned";
}
} else {
LOG(WARNING) << "Child no longer exits";
}
}
auto cloned = oldShadowNode->clone(
{.props = newProps,
.children = std::make_shared<
std::vector<std::shared_ptr<const ShadowNode>>>(children)});
clonedShadowNodes.insert({oldShadowNode->getTag(), std::move(cloned)});
} else {
LOG(ERROR) << "oldShadowNode is null";
continue;
}
}
// Step 3: Commit ShadowTree
if (auto it = clonedShadowNodes.find(rootShadowNode->getTag());
it != clonedShadowNodes.end()) {
shadowTree.commit(
[rootNode =
it->second](const RootShadowNode&) -> RootShadowNode::Unshared {
return std::static_pointer_cast<RootShadowNode>(rootNode);
},
{});
} else {
LOG(ERROR) << "Root ShadowNode has not been cloned";
}
});
if (delegate_ != nullptr) {
delegate_->uiManagerDidUpdateShadowTree(tagToProps);
}
}
} // namespace facebook::react
Выполнить команду
Для локальной разработки. Не используйте в интернете!