Files
react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp
T
Samuel Susla 4f94d7da81 Back out "Use ShadowTree::commit if failureCallback is nullptr"
Summary:
Changelog: [internal]

Original commit changeset: 5cb78a3a75a7

In D23151218 (https://github.com/facebook/react-native/commit/dffec8bc7bee4d05b72d19b4efe4aeab980f4cd5) we switched from `ShadowTree::tryCommit` to `ShadowTree::commit` inside `UIManager::updateState`.
It fixes update state being dropped but can cause an infinite loop inside `ShadowTree::commit` because the shadow node that triggered `UIManager::updateState` can been removed before the `updateState` call is dispatched..

Reviewed By: JoshuaGross

Differential Revision: D23155228

fbshipit-source-id: f3339a4e4798880972366d6f894c14a58be1b9b2
2020-08-16 10:33:11 -07:00

350 lines
11 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its 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 <react/renderer/core/ShadowNodeFragment.h>
#include <react/renderer/debug/SystraceSection.h>
#include <react/renderer/graphics/Geometry.h>
#include <glog/logging.h>
namespace facebook {
namespace react {
UIManager::~UIManager() {
LOG(WARNING) << "UIManager::~UIManager() was called (address: " << this
<< ").";
}
SharedShadowNode UIManager::createNode(
Tag tag,
std::string const &name,
SurfaceId surfaceId,
const RawProps &rawProps,
SharedEventTarget eventTarget) const {
SystraceSection s("UIManager::createNode");
auto &componentDescriptor = componentDescriptorRegistry_->at(name);
auto fallbackDescriptor =
componentDescriptorRegistry_->getFallbackComponentDescriptor();
auto family = componentDescriptor.createFamily(
ShadowNodeFamilyFragment{tag, surfaceId, nullptr},
std::move(eventTarget));
auto const props = componentDescriptor.cloneProps(nullptr, rawProps);
auto const state =
componentDescriptor.createInitialState(ShadowNodeFragment{props}, family);
auto shadowNode = componentDescriptor.createShadowNode(
ShadowNodeFragment{
/* .props = */
fallbackDescriptor != nullptr &&
fallbackDescriptor->getComponentHandle() ==
componentDescriptor.getComponentHandle()
? componentDescriptor.cloneProps(
props, RawProps(folly::dynamic::object("name", name)))
: props,
/* .children = */ ShadowNodeFragment::childrenPlaceholder(),
/* .state = */ state,
},
family);
if (delegate_) {
delegate_->uiManagerDidCreateShadowNode(shadowNode);
}
return shadowNode;
}
SharedShadowNode UIManager::cloneNode(
const ShadowNode::Shared &shadowNode,
const SharedShadowNodeSharedList &children,
const RawProps *rawProps) const {
SystraceSection s("UIManager::cloneNode");
auto &componentDescriptor = shadowNode->getComponentDescriptor();
auto clonedShadowNode = componentDescriptor.cloneShadowNode(
*shadowNode,
{
/* .props = */
rawProps ? componentDescriptor.cloneProps(
shadowNode->getProps(), *rawProps)
: ShadowNodeFragment::propsPlaceholder(),
/* .children = */ children,
});
return clonedShadowNode;
}
void UIManager::appendChild(
const ShadowNode::Shared &parentShadowNode,
const ShadowNode::Shared &childShadowNode) const {
SystraceSection s("UIManager::appendChild");
auto &componentDescriptor = parentShadowNode->getComponentDescriptor();
componentDescriptor.appendChild(parentShadowNode, childShadowNode);
}
void UIManager::completeSurface(
SurfaceId surfaceId,
const SharedShadowNodeUnsharedList &rootChildren) const {
SystraceSection s("UIManager::completeSurface");
shadowTreeRegistry_.visit(surfaceId, [&](ShadowTree const &shadowTree) {
shadowTree.commit(
[&](RootShadowNode::Shared const &oldRootShadowNode) {
return std::make_shared<RootShadowNode>(
*oldRootShadowNode,
ShadowNodeFragment{
/* .props = */ ShadowNodeFragment::propsPlaceholder(),
/* .children = */ rootChildren,
});
},
true);
});
}
void UIManager::setJSResponder(
const ShadowNode::Shared &shadowNode,
const bool blockNativeResponder) const {
if (delegate_) {
delegate_->uiManagerDidSetJSResponder(
shadowNode->getSurfaceId(), shadowNode, blockNativeResponder);
}
}
void UIManager::clearJSResponder() const {
if (delegate_) {
delegate_->uiManagerDidClearJSResponder();
}
}
ShadowNode::Shared UIManager::getNewestCloneOfShadowNode(
ShadowNode const &shadowNode) const {
auto findNewestChildInParent =
[&](auto const &parentNode) -> ShadowNode::Shared {
for (auto const &child : parentNode.getChildren()) {
if (ShadowNode::sameFamily(*child, shadowNode)) {
return child;
}
}
return nullptr;
};
auto ancestorShadowNode = ShadowNode::Shared{};
shadowTreeRegistry_.visit(
shadowNode.getSurfaceId(), [&](ShadowTree const &shadowTree) {
shadowTree.tryCommit(
[&](RootShadowNode::Shared const &oldRootShadowNode) {
ancestorShadowNode = oldRootShadowNode;
return nullptr;
},
true);
});
if (!ancestorShadowNode) {
return nullptr;
}
auto ancestors = shadowNode.getFamily().getAncestors(*ancestorShadowNode);
if (ancestors.empty()) {
return nullptr;
}
return findNewestChildInParent(ancestors.rbegin()->first.get());
}
ShadowNode::Shared UIManager::findNodeAtPoint(
ShadowNode::Shared const &node,
Point point) const {
return LayoutableShadowNode::findNodeAtPoint(
getNewestCloneOfShadowNode(*node), point);
}
void UIManager::setNativeProps(
ShadowNode const &shadowNode,
RawProps const &rawProps) const {
SystraceSection s("UIManager::setNativeProps");
auto &componentDescriptor = shadowNode.getComponentDescriptor();
auto props = componentDescriptor.cloneProps(shadowNode.getProps(), rawProps);
shadowTreeRegistry_.visit(
shadowNode.getSurfaceId(), [&](ShadowTree const &shadowTree) {
shadowTree.tryCommit(
[&](RootShadowNode::Shared const &oldRootShadowNode) {
return std::static_pointer_cast<RootShadowNode>(
oldRootShadowNode->cloneTree(
shadowNode.getFamily(),
[&](ShadowNode const &oldShadowNode) {
return oldShadowNode.clone({
/* .props = */ props,
});
}));
},
true);
});
}
LayoutMetrics UIManager::getRelativeLayoutMetrics(
ShadowNode const &shadowNode,
ShadowNode const *ancestorShadowNode,
LayoutableShadowNode::LayoutInspectingPolicy policy) const {
SystraceSection s("UIManager::getRelativeLayoutMetrics");
// We might store here an owning pointer to `ancestorShadowNode` to ensure
// that the node is not deallocated during method execution lifetime.
auto owningAncestorShadowNode = ShadowNode::Shared{};
if (!ancestorShadowNode) {
shadowTreeRegistry_.visit(
shadowNode.getSurfaceId(), [&](ShadowTree const &shadowTree) {
shadowTree.tryCommit(
[&](RootShadowNode::Shared const &oldRootShadowNode) {
ancestorShadowNode = oldRootShadowNode.get();
return nullptr;
},
true);
});
} else {
// It is possible for JavaScript (or other callers) to have a reference
// to a previous version of ShadowNodes, but we enforce that
// metrics are only calculated on most recently committed versions.
owningAncestorShadowNode = getNewestCloneOfShadowNode(*ancestorShadowNode);
ancestorShadowNode = owningAncestorShadowNode.get();
}
auto layoutableAncestorShadowNode =
traitCast<LayoutableShadowNode const *>(ancestorShadowNode);
if (!layoutableAncestorShadowNode) {
return EmptyLayoutMetrics;
}
return LayoutableShadowNode::computeRelativeLayoutMetrics(
shadowNode.getFamily(), *layoutableAncestorShadowNode, policy);
}
void UIManager::updateState(StateUpdate const &stateUpdate) const {
auto &callback = stateUpdate.callback;
auto &family = stateUpdate.family;
auto &componentDescriptor = family->getComponentDescriptor();
shadowTreeRegistry_.visit(
family->getSurfaceId(), [&](ShadowTree const &shadowTree) {
bool updateSucceeded = shadowTree.tryCommit(
[&](RootShadowNode::Shared const &oldRootShadowNode) {
return std::static_pointer_cast<
RootShadowNode>(oldRootShadowNode->cloneTree(
*family, [&](ShadowNode const &oldShadowNode) {
auto newData =
callback(oldShadowNode.getState()->getDataPointer());
auto newState =
componentDescriptor.createState(*family, newData);
return oldShadowNode.clone({
/* .props = */ ShadowNodeFragment::propsPlaceholder(),
/* .children = */
ShadowNodeFragment::childrenPlaceholder(),
/* .state = */ newState,
});
}));
});
if (!updateSucceeded && stateUpdate.failureCallback) {
stateUpdate.failureCallback();
}
});
}
void UIManager::dispatchCommand(
const ShadowNode::Shared &shadowNode,
std::string const &commandName,
folly::dynamic const args) const {
if (delegate_) {
delegate_->uiManagerDidDispatchCommand(shadowNode, commandName, args);
}
}
void UIManager::configureNextLayoutAnimation(
jsi::Runtime &runtime,
RawValue const &config,
const jsi::Value &successCallback,
const jsi::Value &failureCallback) const {
if (animationDelegate_) {
animationDelegate_->uiManagerDidConfigureNextLayoutAnimation(
runtime,
config,
std::move(successCallback),
std::move(failureCallback));
}
}
void UIManager::setComponentDescriptorRegistry(
const SharedComponentDescriptorRegistry &componentDescriptorRegistry) {
componentDescriptorRegistry_ = componentDescriptorRegistry;
}
void UIManager::setDelegate(UIManagerDelegate *delegate) {
delegate_ = delegate;
}
UIManagerDelegate *UIManager::getDelegate() {
return delegate_;
}
void UIManager::setBackgroundExecutor(
BackgroundExecutor const &backgroundExecutor) {
backgroundExecutor_ = backgroundExecutor;
}
void UIManager::visitBinding(
std::function<void(UIManagerBinding const &uiManagerBinding)> callback)
const {
if (!uiManagerBinding_) {
return;
}
callback(*uiManagerBinding_);
}
ShadowTreeRegistry const &UIManager::getShadowTreeRegistry() const {
return shadowTreeRegistry_;
}
#pragma mark - ShadowTreeDelegate
void UIManager::shadowTreeDidFinishTransaction(
ShadowTree const &shadowTree,
MountingCoordinator::Shared const &mountingCoordinator) const {
SystraceSection s("UIManager::shadowTreeDidFinishTransaction");
if (delegate_) {
delegate_->uiManagerDidFinishTransaction(mountingCoordinator);
}
}
#pragma mark - UIManagerAnimationDelegate
void UIManager::setAnimationDelegate(UIManagerAnimationDelegate *delegate) {
animationDelegate_ = delegate;
}
void UIManager::animationTick() {
if (animationDelegate_ != nullptr &&
animationDelegate_->shouldAnimateFrame()) {
shadowTreeRegistry_.enumerate(
[&](ShadowTree const &shadowTree, bool &stop) {
shadowTree.notifyDelegatesOfUpdates();
});
}
}
} // namespace react
} // namespace facebook