diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index cee65a22e..d747032a1 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -39,17 +39,19 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithContextContainer:(std::shared_ptr)contextContatiner; -- (void)registerRootTag:(ReactTag)tag; +- (void)startSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId + moduleName:(NSString *)moduleName + initailProps:(NSDictionary *)initialProps; -- (void)unregisterRootTag:(ReactTag)tag; +- (void)stopSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId; -- (CGSize)measureWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints - layoutContext:(facebook::react::LayoutContext)layoutContext - rootTag:(ReactTag)rootTag; - -- (void)constraintLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints +- (CGSize)measureSurfaceWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints layoutContext:(facebook::react::LayoutContext)layoutContext - rootTag:(ReactTag)rootTag; + surfaceId:(facebook::react::SurfaceId)surfaceId; + +- (void)constraintSurfaceLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints + layoutContext:(facebook::react::LayoutContext)layoutContext + surfaceId:(facebook::react::SurfaceId)surfaceId; @end diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index d1aa3a043..7a1822dd9 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -11,6 +11,8 @@ #import #import +#import + #import "RCTConversions.h" using namespace facebook::react; @@ -55,28 +57,34 @@ private: _scheduler->setDelegate(nullptr); } -- (void)registerRootTag:(ReactTag)tag +- (void)startSurfaceWithSurfaceId:(SurfaceId)surfaceId + moduleName:(NSString *)moduleName + initailProps:(NSDictionary *)initialProps { - _scheduler->registerRootTag(tag); + _scheduler->startSurface( + surfaceId, + RCTStringFromNSString(moduleName), + convertIdToFollyDynamic(initialProps) + ); } -- (void)unregisterRootTag:(ReactTag)tag +- (void)stopSurfaceWithSurfaceId:(SurfaceId)surfaceId { - _scheduler->unregisterRootTag(tag); + _scheduler->stopSurface(surfaceId); } -- (CGSize)measureWithLayoutConstraints:(LayoutConstraints)layoutConstraints - layoutContext:(LayoutContext)layoutContext - rootTag:(ReactTag)rootTag -{ - return RCTCGSizeFromSize(_scheduler->measure(rootTag, layoutConstraints, layoutContext)); -} - -- (void)constraintLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints +- (CGSize)measureSurfaceWithLayoutConstraints:(LayoutConstraints)layoutConstraints layoutContext:(LayoutContext)layoutContext - rootTag:(ReactTag)rootTag + surfaceId:(SurfaceId)surfaceId { - _scheduler->constraintLayout(rootTag, layoutConstraints, layoutContext); + return RCTCGSizeFromSize(_scheduler->measureSurface(surfaceId, layoutConstraints, layoutContext)); +} + +- (void)constraintSurfaceLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints + layoutContext:(LayoutContext)layoutContext + surfaceId:(SurfaceId)surfaceId +{ + _scheduler->constraintSurfaceLayout(surfaceId, layoutConstraints, layoutContext); } @end diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 977cfbbae..d6514f2c9 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -150,9 +150,9 @@ using namespace facebook::react; layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize); layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize); - return [_scheduler measureWithLayoutConstraints:layoutConstraints - layoutContext:layoutContext - rootTag:surface.rootTag]; + return [_scheduler measureSurfaceWithLayoutConstraints:layoutConstraints + layoutContext:layoutContext + surfaceId:surface.rootTag]; } - (void)setMinimumSize:(CGSize)minimumSize @@ -167,9 +167,9 @@ using namespace facebook::react; layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize); layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize); - [_scheduler constraintLayoutWithLayoutConstraints:layoutConstraints - layoutContext:layoutContext - rootTag:surface.rootTag]; + [_scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints + layoutContext:layoutContext + surfaceId:surface.rootTag]; } - (void)startSurface:(RCTFabricSurface *)surface @@ -177,27 +177,21 @@ using namespace facebook::react; [_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag]; [self createSchedulerIfNeeded]; - [_scheduler registerRootTag:surface.rootTag]; + + [_scheduler startSurfaceWithSurfaceId:surface.rootTag + moduleName:surface.moduleName + initailProps:surface.properties]; [self setMinimumSize:surface.minimumSize maximumSize:surface.maximumSize surface:surface]; - - // TODO: Move this down to Scheduler. - NSDictionary *applicationParameters = @{ - @"rootTag": @(surface.rootTag), - @"initialProps": surface.properties, - }; - [self->_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL]; } - (void)stopSurface:(RCTFabricSurface *)surface { - // TODO: Move this down to Scheduler. - [_batchedBridge enqueueJSCall:@"ReactFabric" method:@"unmountComponentAtNode" args:@[@(surface.rootTag)] completion:NULL]; - [self ensureSchedulerDoesExist]; - [_scheduler unregisterRootTag:surface.rootTag]; + + [_scheduler stopSurfaceWithSurfaceId:surface.rootTag]; UIView *rootView = [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag]; [_mountingManager.componentViewRegistry enqueueComponentViewWithName:@"Root" tag:surface.rootTag componentView:rootView]; diff --git a/ReactCommon/fabric/core/primitives/ReactPrimitives.h b/ReactCommon/fabric/core/primitives/ReactPrimitives.h index a68719f72..72ecba50c 100644 --- a/ReactCommon/fabric/core/primitives/ReactPrimitives.h +++ b/ReactCommon/fabric/core/primitives/ReactPrimitives.h @@ -22,6 +22,11 @@ namespace react { using Tag = int32_t; using InstanceHandle = struct InstanceHandleDummyStruct {} *; +/* + * An id of a running Surface instance that is used to refer to the instance. + */ +using SurfaceId = int32_t; + /* * `RawProps` represents untyped map with props comes from JavaScript side. */ diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index 0101bed13..e3e71ac53 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -106,7 +106,7 @@ static const std::string componentNameByReactViewName(std::string viewName) { FabricUIManager::~FabricUIManager() { (*executor_)([this] { uninstaller_(); - }, EventBeatBasedExecutor::Mode::Synchronous); + }); } void FabricUIManager::setComponentDescriptorRegistry(const SharedComponentDescriptorRegistry &componentDescriptorRegistry) { @@ -129,6 +129,14 @@ void FabricUIManager::setDispatchEventToTargetFunction(std::function startSurfaceFunction) { + startSurfaceFunction_ = startSurfaceFunction; +} + +void FabricUIManager::setStopSurfaceFunction(std::function stopSurfaceFunction) { + stopSurfaceFunction_ = stopSurfaceFunction; +} + void FabricUIManager::dispatchEventToTarget(const EventTarget *eventTarget, const std::string &type, const folly::dynamic &payload) const { if (eventTarget) { dispatchEventToTargetFunction_( @@ -146,6 +154,18 @@ void FabricUIManager::dispatchEventToTarget(const EventTarget *eventTarget, cons } } +void FabricUIManager::startSurface(SurfaceId surfaceId, const std::string &moduleName, const folly::dynamic &initialProps) const { + (*executor_)([this, surfaceId, moduleName, initialProps] { + startSurfaceFunction_(surfaceId, moduleName, initialProps); + }); +} + +void FabricUIManager::stopSurface(SurfaceId surfaceId) const { + (*executor_)([this, surfaceId] { + stopSurfaceFunction_(surfaceId); + }); +} + SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, SharedEventTarget eventTarget) const { isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag: " << rootTag << ", props: " << props << ")"; diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.h b/ReactCommon/fabric/uimanager/FabricUIManager.h index 70ae48291..3481faecc 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.h +++ b/ReactCommon/fabric/uimanager/FabricUIManager.h @@ -32,6 +32,9 @@ using UIManagerUninstaller = void (); using DispatchEventToEmptyTargetFunction = void (const EventHandler &eventHandler, const std::string &type, const folly::dynamic &payload); using DispatchEventToTargetFunction = void (const EventHandler &eventHandler, const EventTarget &eventTarget, const std::string &type, const folly::dynamic &payload); +using StartSurface = void (SurfaceId surfaceId, const std::string &moduleName, const folly::dynamic &initalProps); +using StopSurface = void (SurfaceId surfaceId); + class FabricUIManager { public: @@ -61,10 +64,14 @@ public: */ void setDispatchEventToEmptyTargetFunction(std::function dispatchEventFunction); void setDispatchEventToTargetFunction(std::function dispatchEventFunction); + void setStartSurfaceFunction(std::function); + void setStopSurfaceFunction(std::function); #pragma mark - Native-facing Interface void dispatchEventToTarget(const EventTarget *eventTarget, const std::string &type, const folly::dynamic &payload) const; + void startSurface(SurfaceId surfaceId, const std::string &moduleName, const folly::dynamic &initialProps) const; + void stopSurface(SurfaceId surfaceId) const; #pragma mark - JavaScript/React-facing Interface @@ -86,12 +93,13 @@ public: void registerEventHandler(UniqueEventHandler eventHandler) const; private: - SharedComponentDescriptorRegistry componentDescriptorRegistry_; UIManagerDelegate *delegate_; mutable UniqueEventHandler eventHandler_; std::function dispatchEventToEmptyTargetFunction_; std::function dispatchEventToTargetFunction_; + std::function startSurfaceFunction_; + std::function stopSurfaceFunction_; std::unique_ptr executor_; std::function installer_; diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index aeb92eda0..6f73f6314 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -51,14 +51,30 @@ Scheduler::~Scheduler() { uiManager_->setDelegate(nullptr); } -void Scheduler::registerRootTag(Tag rootTag) { - auto shadowTree = std::make_unique(rootTag); +void Scheduler::startSurface( + SurfaceId surfaceId, + const std::string &moduleName, + const folly::dynamic &initialProps +) const { + std::lock_guard lock(mutex_); + + auto shadowTree = std::make_unique(surfaceId); shadowTree->setDelegate(this); - shadowTreeRegistry_.emplace(rootTag, std::move(shadowTree)); + shadowTreeRegistry_.emplace(surfaceId, std::move(shadowTree)); + +#ifndef ANDROID + uiManager_->startSurface(surfaceId, moduleName, initialProps); +#endif } -void Scheduler::unregisterRootTag(Tag rootTag) { - const auto &iterator = shadowTreeRegistry_.find(rootTag); +void Scheduler::stopSurface(SurfaceId surfaceId) const { + std::lock_guard lock(mutex_); + +#ifndef ANDROID + uiManager_->stopSurface(surfaceId); +#endif + + const auto &iterator = shadowTreeRegistry_.find(surfaceId); const auto &shadowTree = iterator->second; assert(shadowTree); // As part of stopping the Surface, we have to commit an empty tree. @@ -67,14 +83,24 @@ void Scheduler::unregisterRootTag(Tag rootTag) { shadowTreeRegistry_.erase(iterator); } -Size Scheduler::measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const { - const auto &shadowTree = shadowTreeRegistry_.at(rootTag); +Size Scheduler::measureSurface( + SurfaceId surfaceId, + const LayoutConstraints &layoutConstraints, + const LayoutContext &layoutContext +) const { + std::lock_guard lock(mutex_); + const auto &shadowTree = shadowTreeRegistry_.at(surfaceId); assert(shadowTree); return shadowTree->measure(layoutConstraints, layoutContext); } -void Scheduler::constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) { - const auto &shadowTree = shadowTreeRegistry_.at(rootTag); +void Scheduler::constraintSurfaceLayout( + SurfaceId surfaceId, + const LayoutConstraints &layoutConstraints, + const LayoutContext &layoutContext +) const { + std::lock_guard lock(mutex_); + const auto &shadowTree = shadowTreeRegistry_.at(surfaceId); assert(shadowTree); return shadowTree->constraintLayout(layoutConstraints, layoutContext); } @@ -91,7 +117,7 @@ SchedulerDelegate *Scheduler::getDelegate() const { #pragma mark - ShadowTreeDelegate -void Scheduler::shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) { +void Scheduler::shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) const { if (delegate_) { delegate_->schedulerDidFinishTransaction(shadowTree.getRootTag(), mutations); } @@ -100,6 +126,8 @@ void Scheduler::shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowVi #pragma mark - UIManagerDelegate void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) { + std::lock_guard lock(mutex_); + const auto iterator = shadowTreeRegistry_.find(rootTag); if (iterator == shadowTreeRegistry_.end()) { // This might happen during surface unmounting/deallocation process diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index aef442d48..87382a195 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -6,6 +6,7 @@ #pragma once #include +#include #include #include @@ -28,17 +29,30 @@ class Scheduler final: public ShadowTreeDelegate { public: - Scheduler(const SharedContextContainer &contextContainer); ~Scheduler(); -#pragma mark - Shadow Tree Management +#pragma mark - Surface Management - void registerRootTag(Tag rootTag); - void unregisterRootTag(Tag rootTag); + void startSurface( + SurfaceId surfaceId, + const std::string &moduleName, + const folly::dynamic &initialProps + ) const; - Size measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const; - void constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext); + void stopSurface(SurfaceId surfaceId) const; + + Size measureSurface( + SurfaceId surfaceId, + const LayoutConstraints &layoutConstraints, + const LayoutContext &layoutContext + ) const; + + void constraintSurfaceLayout( + SurfaceId surfaceId, + const LayoutConstraints &layoutConstraints, + const LayoutContext &layoutContext + ) const; #pragma mark - Delegate @@ -57,7 +71,7 @@ public: #pragma mark - ShadowTreeDelegate - void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) override; + void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) const override; #pragma mark - Deprecated @@ -69,7 +83,8 @@ public: private: SchedulerDelegate *delegate_; std::shared_ptr uiManager_; - std::unordered_map> shadowTreeRegistry_; + mutable std::mutex mutex_; + mutable std::unordered_map> shadowTreeRegistry_; // Protected by `mutex_`. SharedEventDispatcher eventDispatcher_; SharedContextContainer contextContainer_; }; diff --git a/ReactCommon/fabric/uimanager/ShadowTree.cpp b/ReactCommon/fabric/uimanager/ShadowTree.cpp index 4693e70f1..dd8c1e16e 100644 --- a/ReactCommon/fabric/uimanager/ShadowTree.cpp +++ b/ReactCommon/fabric/uimanager/ShadowTree.cpp @@ -165,11 +165,11 @@ void ShadowTree::toggleEventEmitters(const ShadowViewMutationList &mutations) { #pragma mark - Delegate -void ShadowTree::setDelegate(ShadowTreeDelegate *delegate) { +void ShadowTree::setDelegate(ShadowTreeDelegate const *delegate) { delegate_ = delegate; } -ShadowTreeDelegate *ShadowTree::getDelegate() const { +ShadowTreeDelegate const *ShadowTree::getDelegate() const { return delegate_; } diff --git a/ReactCommon/fabric/uimanager/ShadowTree.h b/ReactCommon/fabric/uimanager/ShadowTree.h index 2f7e94049..d7add5ccf 100644 --- a/ReactCommon/fabric/uimanager/ShadowTree.h +++ b/ReactCommon/fabric/uimanager/ShadowTree.h @@ -68,8 +68,8 @@ public: * The delegate is stored as a raw pointer, so the owner must null * the pointer before being destroyed. */ - void setDelegate(ShadowTreeDelegate *delegate); - ShadowTreeDelegate *getDelegate() const; + void setDelegate(ShadowTreeDelegate const *delegate); + ShadowTreeDelegate const *getDelegate() const; private: @@ -85,7 +85,7 @@ private: const Tag rootTag_; SharedRootShadowNode rootShadowNode_; - ShadowTreeDelegate *delegate_; + ShadowTreeDelegate const *delegate_; mutable std::mutex commitMutex_; }; diff --git a/ReactCommon/fabric/uimanager/ShadowTreeDelegate.h b/ReactCommon/fabric/uimanager/ShadowTreeDelegate.h index 71bc3caf9..8d0f7ddea 100644 --- a/ReactCommon/fabric/uimanager/ShadowTreeDelegate.h +++ b/ReactCommon/fabric/uimanager/ShadowTreeDelegate.h @@ -21,7 +21,7 @@ public: /* * Called right after Shadow Tree commit a new state of the the tree. */ - virtual void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) = 0; + virtual void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) const = 0; virtual ~ShadowTreeDelegate() noexcept = default; };