Files
react-native/ReactCommon/fabric/uimanager/Scheduler.cpp
Valentin Shergin 00eab3d6fb Fabric: Introducing ComponentDescriptorProvider
Summary:
ComponentDescriptorProvider represents unified way to create a particular descriptor.
Now all ComponentViews (which support RCTComponentViewProtocol) expose a `ComponentDescriptorProvider` which will allow creating and registering ComponentDescriptor instances for all visual components automatically as a part of ComponentView registration process.
Don't panic, everything is still being as explicit as it always was, no magic involved; we just will have only one registration step instead of two parallel.

That also opens a way to register components on the fly.

Reviewed By: JoshuaGross

Differential Revision: D14963488

fbshipit-source-id: 9e9d9166fabaf7b30b35b8647faa6e3a19cd2435
2019-04-17 22:44:20 -07:00

295 lines
9.5 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 "Scheduler.h"
#include <glog/logging.h>
#include <jsi/jsi.h>
#include <react/core/LayoutContext.h>
#include <react/debug/SystraceSection.h>
#include <react/uimanager/ComponentDescriptorRegistry.h>
#include <react/uimanager/UIManager.h>
#include <react/uimanager/UIManagerBinding.h>
#include <react/uimanager/UITemplateProcessor.h>
#include <react/utils/TimeUtils.h>
namespace facebook {
namespace react {
Scheduler::Scheduler(
ContextContainer::Shared const &contextContainer,
ComponentRegistryFactory buildRegistryFunction) {
const auto asynchronousEventBeatFactory =
contextContainer->getInstance<EventBeatFactory>("asynchronous");
const auto synchronousEventBeatFactory =
contextContainer->getInstance<EventBeatFactory>("synchronous");
runtimeExecutor_ =
contextContainer->getInstance<RuntimeExecutor>("runtime-executor");
reactNativeConfig_ =
contextContainer->getInstance<std::shared_ptr<const ReactNativeConfig>>(
"ReactNativeConfig");
auto uiManager = std::make_unique<UIManager>();
auto &uiManagerRef = *uiManager;
uiManagerBinding_ = std::make_shared<UIManagerBinding>(std::move(uiManager));
auto eventPipe = [uiManagerBinding = uiManagerBinding_.get()](
jsi::Runtime &runtime,
const EventTarget *eventTarget,
const std::string &type,
const ValueFactory &payloadFactory) {
uiManagerBinding->dispatchEvent(runtime, eventTarget, type, payloadFactory);
};
auto statePipe = [uiManager = &uiManagerRef](
const StateData::Shared &data,
const StateTarget &stateTarget) {
uiManager->updateState(
stateTarget.getShadowNode().shared_from_this(), data);
};
auto eventDispatcher = std::make_shared<EventDispatcher>(
eventPipe,
statePipe,
synchronousEventBeatFactory,
asynchronousEventBeatFactory);
componentDescriptorRegistry_ =
buildRegistryFunction(eventDispatcher, contextContainer);
rootComponentDescriptor_ =
std::make_unique<const RootComponentDescriptor>(eventDispatcher);
uiManagerRef.setDelegate(this);
uiManagerRef.setShadowTreeRegistry(&shadowTreeRegistry_);
uiManagerRef.setComponentDescriptorRegistry(componentDescriptorRegistry_);
runtimeExecutor_([=](jsi::Runtime &runtime) {
UIManagerBinding::install(runtime, uiManagerBinding_);
});
contextContainer->registerInstance(
std::weak_ptr<ComponentDescriptorRegistry const>(
componentDescriptorRegistry_),
"ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE");
}
Scheduler::~Scheduler() {
uiManagerBinding_->invalidate();
}
void Scheduler::startSurface(
SurfaceId surfaceId,
const std::string &moduleName,
const folly::dynamic &initialProps,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext) const {
SystraceSection s("Scheduler::startSurface");
auto shadowTree = std::make_unique<ShadowTree>(
surfaceId, layoutConstraints, layoutContext, *rootComponentDescriptor_);
shadowTree->setDelegate(this);
shadowTreeRegistry_.add(std::move(shadowTree));
#ifndef ANDROID
runtimeExecutor_([=](jsi::Runtime &runtime) {
uiManagerBinding_->startSurface(
runtime, surfaceId, moduleName, initialProps);
});
#endif
}
void Scheduler::renderTemplateToSurface(
SurfaceId surfaceId,
const std::string &uiTemplate) {
SystraceSection s("Scheduler::renderTemplateToSurface");
long commitStartTime = getTime();
try {
if (uiTemplate.size() == 0) {
return;
}
NativeModuleRegistry nMR;
auto tree = UITemplateProcessor::buildShadowTree(
uiTemplate,
surfaceId,
folly::dynamic::object(),
*componentDescriptorRegistry_,
nMR,
reactNativeConfig_);
shadowTreeRegistry_.visit(surfaceId, [=](const ShadowTree &shadowTree) {
return shadowTree.tryCommit(
[&](const SharedRootShadowNode &oldRootShadowNode) {
return std::make_shared<RootShadowNode>(
*oldRootShadowNode,
ShadowNodeFragment{
/* .tag = */ ShadowNodeFragment::tagPlaceholder(),
/* .rootTag = */ ShadowNodeFragment::surfaceIdPlaceholder(),
/* .props = */ ShadowNodeFragment::propsPlaceholder(),
/* .eventEmitter = */
ShadowNodeFragment::eventEmitterPlaceholder(),
/* .children = */
std::make_shared<SharedShadowNodeList>(
SharedShadowNodeList{tree}),
});
},
commitStartTime);
});
} catch (const std::exception &e) {
LOG(ERROR) << " >>>> EXCEPTION <<< rendering uiTemplate in "
<< "Scheduler::renderTemplateToSurface: " << e.what();
}
}
void Scheduler::stopSurface(SurfaceId surfaceId) const {
SystraceSection s("Scheduler::stopSurface");
long commitStartTime = getTime();
shadowTreeRegistry_.visit(
surfaceId, [commitStartTime](const ShadowTree &shadowTree) {
// As part of stopping the Surface, we have to commit an empty tree.
return shadowTree.tryCommit(
[&](const SharedRootShadowNode &oldRootShadowNode) {
return std::make_shared<RootShadowNode>(
*oldRootShadowNode,
ShadowNodeFragment{
/* .tag = */ ShadowNodeFragment::tagPlaceholder(),
/* .rootTag = */
ShadowNodeFragment::surfaceIdPlaceholder(),
/* .props = */ ShadowNodeFragment::propsPlaceholder(),
/* .eventEmitter = */
ShadowNodeFragment::eventEmitterPlaceholder(),
/* .children = */
ShadowNode::emptySharedShadowNodeSharedList(),
});
},
commitStartTime);
});
auto shadowTree = shadowTreeRegistry_.remove(surfaceId);
shadowTree->setDelegate(nullptr);
#ifndef ANDROID
runtimeExecutor_([=](jsi::Runtime &runtime) {
uiManagerBinding_->stopSurface(runtime, surfaceId);
});
#endif
}
Size Scheduler::measureSurface(
SurfaceId surfaceId,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext) const {
SystraceSection s("Scheduler::measureSurface");
long commitStartTime = getTime();
Size size;
shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
shadowTree.tryCommit(
[&](const SharedRootShadowNode &oldRootShadowNode) {
auto rootShadowNode =
oldRootShadowNode->clone(layoutConstraints, layoutContext);
rootShadowNode->layout();
size = rootShadowNode->getLayoutMetrics().frame.size;
return nullptr;
},
commitStartTime);
});
return size;
}
void Scheduler::constraintSurfaceLayout(
SurfaceId surfaceId,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext) const {
SystraceSection s("Scheduler::constraintSurfaceLayout");
long commitStartTime = getTime();
shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
shadowTree.commit(
[&](const SharedRootShadowNode &oldRootShadowNode) {
return oldRootShadowNode->clone(layoutConstraints, layoutContext);
},
commitStartTime);
});
}
const ComponentDescriptor &Scheduler::getComponentDescriptor(
ComponentHandle handle) {
return componentDescriptorRegistry_->at(handle);
}
#pragma mark - Delegate
void Scheduler::setDelegate(SchedulerDelegate *delegate) {
delegate_ = delegate;
}
SchedulerDelegate *Scheduler::getDelegate() const {
return delegate_;
}
#pragma mark - ShadowTreeDelegate
void Scheduler::shadowTreeDidCommit(
const ShadowTree &shadowTree,
const ShadowViewMutationList &mutations,
long commitStartTime,
long layoutTime) const {
SystraceSection s("Scheduler::shadowTreeDidCommit");
if (delegate_) {
delegate_->schedulerDidFinishTransaction(
shadowTree.getSurfaceId(), mutations, commitStartTime, layoutTime);
}
}
#pragma mark - UIManagerDelegate
void Scheduler::uiManagerDidFinishTransaction(
SurfaceId surfaceId,
const SharedShadowNodeUnsharedList &rootChildNodes,
long startCommitTime) {
SystraceSection s("Scheduler::uiManagerDidFinishTransaction");
shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
shadowTree.commit(
[&](const SharedRootShadowNode &oldRootShadowNode) {
return std::make_shared<RootShadowNode>(
*oldRootShadowNode,
ShadowNodeFragment{
/* .tag = */ ShadowNodeFragment::tagPlaceholder(),
/* .rootTag = */ ShadowNodeFragment::surfaceIdPlaceholder(),
/* .props = */ ShadowNodeFragment::propsPlaceholder(),
/* .eventEmitter = */
ShadowNodeFragment::eventEmitterPlaceholder(),
/* .children = */ rootChildNodes,
});
},
startCommitTime);
});
}
void Scheduler::uiManagerDidCreateShadowNode(
const SharedShadowNode &shadowNode) {
SystraceSection s("Scheduler::uiManagerDidCreateShadowNode");
if (delegate_) {
auto shadowView = ShadowView(*shadowNode);
delegate_->schedulerDidRequestPreliminaryViewAllocation(
shadowNode->getSurfaceId(), shadowView);
}
}
} // namespace react
} // namespace facebook