// 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 #include #include #include #include #include #include #include namespace facebook { namespace react { Scheduler::Scheduler( SchedulerToolbox schedulerToolbox, SchedulerDelegate *delegate) { runtimeExecutor_ = schedulerToolbox.runtimeExecutor; reactNativeConfig_ = schedulerToolbox.contextContainer ->at>("ReactNativeConfig"); auto uiManager = std::make_shared(); auto eventOwnerBox = std::make_shared(); auto eventPipe = [=](jsi::Runtime &runtime, const EventTarget *eventTarget, const std::string &type, const ValueFactory &payloadFactory) { uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) { uiManagerBinding.dispatchEvent( runtime, eventTarget, type, payloadFactory); }); }; auto statePipe = [=](const StateData::Shared &data, const StateTarget &stateTarget) { uiManager->updateState( stateTarget.getShadowNode().shared_from_this(), data); }; eventDispatcher_ = std::make_shared( eventPipe, statePipe, schedulerToolbox.synchronousEventBeatFactory, schedulerToolbox.asynchronousEventBeatFactory, eventOwnerBox); eventOwnerBox->owner = eventDispatcher_; componentDescriptorRegistry_ = schedulerToolbox.componentRegistryFactory( eventDispatcher_, schedulerToolbox.contextContainer); rootComponentDescriptor_ = std::make_unique(eventDispatcher_); uiManager->setDelegate(this); uiManager->setComponentDescriptorRegistry(componentDescriptorRegistry_); runtimeExecutor_([=](jsi::Runtime &runtime) { auto uiManagerBinding = UIManagerBinding::createAndInstallIfNeeded(runtime); uiManagerBinding->attach(uiManager); }); schedulerToolbox.contextContainer->insert( "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE", std::weak_ptr( componentDescriptorRegistry_)); delegate_ = delegate; uiManager_ = uiManager; } Scheduler::~Scheduler() { uiManager_->setDelegate(nullptr); } 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( surfaceId, layoutConstraints, layoutContext, *rootComponentDescriptor_); shadowTree->setDelegate(this); auto uiManager = uiManager_; uiManager->getShadowTreeRegistry().add(std::move(shadowTree)); runtimeExecutor_([=](jsi::Runtime &runtime) { uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) { uiManagerBinding.startSurface( runtime, surfaceId, moduleName, initialProps); }); }); } void Scheduler::renderTemplateToSurface( SurfaceId surfaceId, const std::string &uiTemplate) { SystraceSection s("Scheduler::renderTemplateToSurface"); try { if (uiTemplate.size() == 0) { return; } NativeModuleRegistry nMR; auto tree = UITemplateProcessor::buildShadowTree( uiTemplate, surfaceId, folly::dynamic::object(), *componentDescriptorRegistry_, nMR, reactNativeConfig_); uiManager_->getShadowTreeRegistry().visit( surfaceId, [=](const ShadowTree &shadowTree) { return shadowTree.tryCommit([&](const SharedRootShadowNode &oldRootShadowNode) { return std::make_shared( *oldRootShadowNode, ShadowNodeFragment{ /* .tag = */ ShadowNodeFragment::tagPlaceholder(), /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), /* .props = */ ShadowNodeFragment::propsPlaceholder(), /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ std::make_shared( SharedShadowNodeList{tree}), }); }); }); } 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"); uiManager_->getShadowTreeRegistry().visit( surfaceId, [](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( *oldRootShadowNode, ShadowNodeFragment{ /* .tag = */ ShadowNodeFragment::tagPlaceholder(), /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), /* .props = */ ShadowNodeFragment::propsPlaceholder(), /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }); }); }); auto shadowTree = uiManager_->getShadowTreeRegistry().remove(surfaceId); shadowTree->setDelegate(nullptr); auto uiManager = uiManager_; runtimeExecutor_([=](jsi::Runtime &runtime) { uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) { uiManagerBinding.stopSurface(runtime, surfaceId); }); }); } Size Scheduler::measureSurface( SurfaceId surfaceId, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const { SystraceSection s("Scheduler::measureSurface"); Size size; uiManager_->getShadowTreeRegistry().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; }); }); return size; } void Scheduler::constraintSurfaceLayout( SurfaceId surfaceId, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const { SystraceSection s("Scheduler::constraintSurfaceLayout"); uiManager_->getShadowTreeRegistry().visit( surfaceId, [&](const ShadowTree &shadowTree) { shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { return oldRootShadowNode->clone(layoutConstraints, layoutContext); }); }); } 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( ShadowTree const &shadowTree, MountingCoordinator::Shared const &mountingCoordinator) const { SystraceSection s("Scheduler::shadowTreeDidCommit"); if (delegate_) { delegate_->schedulerDidFinishTransaction(mountingCoordinator); } } #pragma mark - UIManagerDelegate void Scheduler::uiManagerDidFinishTransaction( SurfaceId surfaceId, const SharedShadowNodeUnsharedList &rootChildNodes) { SystraceSection s("Scheduler::uiManagerDidFinishTransaction"); uiManager_->getShadowTreeRegistry().visit( surfaceId, [&](const ShadowTree &shadowTree) { shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { return std::make_shared( *oldRootShadowNode, ShadowNodeFragment{ /* .tag = */ ShadowNodeFragment::tagPlaceholder(), /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), /* .props = */ ShadowNodeFragment::propsPlaceholder(), /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ rootChildNodes, }); }); }); } void Scheduler::uiManagerDidCreateShadowNode( const SharedShadowNode &shadowNode) { SystraceSection s("Scheduler::uiManagerDidCreateShadowNode"); if (delegate_) { auto shadowView = ShadowView(*shadowNode); delegate_->schedulerDidRequestPreliminaryViewAllocation( shadowNode->getSurfaceId(), shadowView); } } void Scheduler::uiManagerDidDispatchCommand( const SharedShadowNode &shadowNode, std::string const &commandName, folly::dynamic const args) { SystraceSection s("Scheduler::uiManagerDispatchCommand"); if (delegate_) { auto shadowView = ShadowView(*shadowNode); delegate_->schedulerDidDispatchCommand(shadowView, commandName, args); } } /* * Set JS responder for a view */ void Scheduler::uiManagerDidSetJSResponder( SurfaceId surfaceId, const SharedShadowNode &shadowNode, bool blockNativeResponder) { if (delegate_) { // TODO: the first shadowView paramenter, should be the first parent that // is non virtual. auto shadowView = ShadowView(*shadowNode); delegate_->schedulerDidSetJSResponder( surfaceId, shadowView, shadowView, blockNativeResponder); } } /* * Clear the JSResponder for a view */ void Scheduler::uiManagerDidClearJSResponder() { if (delegate_) { delegate_->schedulerDidClearJSResponder(); } } } // namespace react } // namespace facebook