RCTSurfacePresenter.mm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTSurfacePresenter.h"
  8. #import <mutex>
  9. #import <React/RCTAssert.h>
  10. #import <React/RCTComponentViewFactory.h>
  11. #import <React/RCTComponentViewRegistry.h>
  12. #import <React/RCTFabricSurface.h>
  13. #import <React/RCTFollyConvert.h>
  14. #import <React/RCTI18nUtil.h>
  15. #import <React/RCTMountingManager.h>
  16. #import <React/RCTMountingManagerDelegate.h>
  17. #import <React/RCTScheduler.h>
  18. #import <React/RCTSurfaceRegistry.h>
  19. #import <React/RCTSurfaceView+Internal.h>
  20. #import <React/RCTSurfaceView.h>
  21. #import <React/RCTUtils.h>
  22. #import <react/components/root/RootShadowNode.h>
  23. #import <react/core/LayoutConstraints.h>
  24. #import <react/core/LayoutContext.h>
  25. #import <react/uimanager/ComponentDescriptorFactory.h>
  26. #import <react/uimanager/SchedulerToolbox.h>
  27. #import <react/utils/ContextContainer.h>
  28. #import <react/utils/ManagedObjectWrapper.h>
  29. #import "MainRunLoopEventBeat.h"
  30. #import "RCTConversions.h"
  31. #import "RuntimeEventBeat.h"
  32. using namespace facebook::react;
  33. static inline LayoutConstraints RCTGetLayoutConstraintsForSize(CGSize minimumSize, CGSize maximumSize)
  34. {
  35. return {
  36. .minimumSize = RCTSizeFromCGSize(minimumSize),
  37. .maximumSize = RCTSizeFromCGSize(maximumSize),
  38. .layoutDirection = RCTLayoutDirection([[RCTI18nUtil sharedInstance] isRTL]),
  39. };
  40. }
  41. static inline LayoutContext RCTGetLayoutContext()
  42. {
  43. return {.pointScaleFactor = RCTScreenScale(),
  44. .swapLeftAndRightInRTL =
  45. [[RCTI18nUtil sharedInstance] isRTL] && [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]};
  46. }
  47. @interface RCTSurfacePresenter () <RCTSchedulerDelegate, RCTMountingManagerDelegate>
  48. @end
  49. @implementation RCTSurfacePresenter {
  50. RCTMountingManager *_mountingManager; // Thread-safe.
  51. RCTSurfaceRegistry *_surfaceRegistry; // Thread-safe.
  52. std::mutex _schedulerAccessMutex;
  53. std::mutex _schedulerLifeCycleMutex;
  54. RCTScheduler *_Nullable _scheduler; // Thread-safe. Pointer is protected by `_schedulerAccessMutex`.
  55. ContextContainer::Shared _contextContainer; // Protected by `_schedulerLifeCycleMutex`.
  56. RuntimeExecutor _runtimeExecutor; // Protected by `_schedulerLifeCycleMutex`.
  57. better::shared_mutex _observerListMutex;
  58. NSMutableArray<id<RCTSurfacePresenterObserver>> *_observers;
  59. }
  60. - (instancetype)initWithContextContainer:(ContextContainer::Shared)contextContainer
  61. runtimeExecutor:(RuntimeExecutor)runtimeExecutor
  62. {
  63. if (self = [super init]) {
  64. assert(contextContainer && "RuntimeExecutor must be not null.");
  65. _runtimeExecutor = runtimeExecutor;
  66. _contextContainer = contextContainer;
  67. _surfaceRegistry = [[RCTSurfaceRegistry alloc] init];
  68. _mountingManager = [[RCTMountingManager alloc] init];
  69. _mountingManager.delegate = self;
  70. _observers = [NSMutableArray array];
  71. _scheduler = [self _createScheduler];
  72. }
  73. return self;
  74. }
  75. - (RCTScheduler *_Nullable)_scheduler
  76. {
  77. std::lock_guard<std::mutex> lock(_schedulerAccessMutex);
  78. return _scheduler;
  79. }
  80. - (ContextContainer::Shared)contextContainer
  81. {
  82. std::lock_guard<std::mutex> lock(_schedulerLifeCycleMutex);
  83. return _contextContainer;
  84. }
  85. - (void)setContextContainer:(ContextContainer::Shared)contextContainer
  86. {
  87. std::lock_guard<std::mutex> lock(_schedulerLifeCycleMutex);
  88. _contextContainer = contextContainer;
  89. }
  90. - (RuntimeExecutor)runtimeExecutor
  91. {
  92. std::lock_guard<std::mutex> lock(_schedulerLifeCycleMutex);
  93. return _runtimeExecutor;
  94. }
  95. - (void)setRuntimeExecutor:(RuntimeExecutor)runtimeExecutor
  96. {
  97. std::lock_guard<std::mutex> lock(_schedulerLifeCycleMutex);
  98. _runtimeExecutor = runtimeExecutor;
  99. }
  100. #pragma mark - Internal Surface-dedicated Interface
  101. - (void)registerSurface:(RCTFabricSurface *)surface
  102. {
  103. RCTScheduler *scheduler = [self _scheduler];
  104. [_surfaceRegistry registerSurface:surface];
  105. if (scheduler) {
  106. [self _startSurface:surface scheduler:scheduler];
  107. }
  108. }
  109. - (void)unregisterSurface:(RCTFabricSurface *)surface
  110. {
  111. RCTScheduler *scheduler = [self _scheduler];
  112. if (scheduler) {
  113. [self _stopSurface:surface scheduler:scheduler];
  114. }
  115. [_surfaceRegistry unregisterSurface:surface];
  116. }
  117. - (void)setProps:(NSDictionary *)props surface:(RCTFabricSurface *)surface
  118. {
  119. RCTScheduler *scheduler = [self _scheduler];
  120. if (scheduler) {
  121. [self _stopSurface:surface scheduler:scheduler];
  122. [self _startSurface:surface scheduler:scheduler];
  123. }
  124. }
  125. - (RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag
  126. {
  127. return [_surfaceRegistry surfaceForRootTag:rootTag];
  128. }
  129. - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize
  130. maximumSize:(CGSize)maximumSize
  131. surface:(RCTFabricSurface *)surface
  132. {
  133. RCTScheduler *scheduler = [self _scheduler];
  134. if (!scheduler) {
  135. return minimumSize;
  136. }
  137. LayoutContext layoutContext = RCTGetLayoutContext();
  138. LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(minimumSize, maximumSize);
  139. return [scheduler measureSurfaceWithLayoutConstraints:layoutConstraints
  140. layoutContext:layoutContext
  141. surfaceId:surface.rootTag];
  142. }
  143. - (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize surface:(RCTFabricSurface *)surface
  144. {
  145. RCTScheduler *scheduler = [self _scheduler];
  146. if (!scheduler) {
  147. return;
  148. }
  149. LayoutContext layoutContext = RCTGetLayoutContext();
  150. LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(minimumSize, maximumSize);
  151. [scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints
  152. layoutContext:layoutContext
  153. surfaceId:surface.rootTag];
  154. }
  155. - (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props
  156. {
  157. RCTScheduler *scheduler = [self _scheduler];
  158. if (!scheduler) {
  159. return NO;
  160. }
  161. ReactTag tag = [reactTag integerValue];
  162. UIView<RCTComponentViewProtocol> *componentView =
  163. [_mountingManager.componentViewRegistry findComponentViewWithTag:tag];
  164. if (componentView == nil) {
  165. return NO; // This view probably isn't managed by Fabric
  166. }
  167. ComponentHandle handle = [[componentView class] componentDescriptorProvider].handle;
  168. auto *componentDescriptor = [scheduler findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN:handle];
  169. if (!componentDescriptor) {
  170. return YES;
  171. }
  172. [_mountingManager synchronouslyUpdateViewOnUIThread:tag changedProps:props componentDescriptor:*componentDescriptor];
  173. return YES;
  174. }
  175. - (BOOL)synchronouslyWaitSurface:(RCTFabricSurface *)surface timeout:(NSTimeInterval)timeout
  176. {
  177. RCTScheduler *scheduler = [self _scheduler];
  178. if (!scheduler) {
  179. return NO;
  180. }
  181. auto mountingCoordinator = [scheduler mountingCoordinatorWithSurfaceId:surface.rootTag];
  182. if (!mountingCoordinator->waitForTransaction(std::chrono::duration<NSTimeInterval>(timeout))) {
  183. return NO;
  184. }
  185. [_mountingManager scheduleTransaction:mountingCoordinator];
  186. return YES;
  187. }
  188. - (BOOL)suspend
  189. {
  190. std::lock_guard<std::mutex> lock(_schedulerLifeCycleMutex);
  191. RCTScheduler *scheduler;
  192. {
  193. std::lock_guard<std::mutex> accessLock(_schedulerAccessMutex);
  194. if (!_scheduler) {
  195. return NO;
  196. }
  197. scheduler = _scheduler;
  198. _scheduler = nil;
  199. }
  200. [self _stopAllSurfacesWithScheduler:scheduler];
  201. return YES;
  202. }
  203. - (BOOL)resume
  204. {
  205. std::lock_guard<std::mutex> lock(_schedulerLifeCycleMutex);
  206. RCTScheduler *scheduler;
  207. {
  208. std::lock_guard<std::mutex> accessLock(_schedulerAccessMutex);
  209. if (_scheduler) {
  210. return NO;
  211. }
  212. scheduler = [self _createScheduler];
  213. }
  214. [self _startAllSurfacesWithScheduler:scheduler];
  215. {
  216. std::lock_guard<std::mutex> accessLock(_schedulerAccessMutex);
  217. _scheduler = scheduler;
  218. }
  219. return YES;
  220. }
  221. #pragma mark - Private
  222. - (RCTScheduler *)_createScheduler
  223. {
  224. auto componentRegistryFactory =
  225. [factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
  226. EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
  227. return [(RCTComponentViewFactory *)unwrapManagedObject(factory)
  228. createComponentDescriptorRegistryWithParameters:{eventDispatcher, contextContainer}];
  229. };
  230. auto runtimeExecutor = _runtimeExecutor;
  231. auto toolbox = SchedulerToolbox{};
  232. toolbox.contextContainer = _contextContainer;
  233. toolbox.componentRegistryFactory = componentRegistryFactory;
  234. toolbox.runtimeExecutor = runtimeExecutor;
  235. toolbox.synchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
  236. return std::make_unique<MainRunLoopEventBeat>(ownerBox, runtimeExecutor);
  237. };
  238. toolbox.asynchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) {
  239. return std::make_unique<RuntimeEventBeat>(ownerBox, runtimeExecutor);
  240. };
  241. RCTScheduler *scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox];
  242. scheduler.delegate = self;
  243. return scheduler;
  244. }
  245. - (void)_startSurface:(RCTFabricSurface *)surface scheduler:(RCTScheduler *)scheduler
  246. {
  247. RCTMountingManager *mountingManager = _mountingManager;
  248. RCTExecuteOnMainQueue(^{
  249. [mountingManager.componentViewRegistry dequeueComponentViewWithComponentHandle:RootShadowNode::Handle()
  250. tag:surface.rootTag];
  251. });
  252. LayoutContext layoutContext = RCTGetLayoutContext();
  253. LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(surface.minimumSize, surface.maximumSize);
  254. [scheduler startSurfaceWithSurfaceId:surface.rootTag
  255. moduleName:surface.moduleName
  256. initialProps:surface.properties
  257. layoutConstraints:layoutConstraints
  258. layoutContext:layoutContext];
  259. }
  260. - (void)_stopSurface:(RCTFabricSurface *)surface scheduler:(RCTScheduler *)scheduler
  261. {
  262. [scheduler stopSurfaceWithSurfaceId:surface.rootTag];
  263. RCTMountingManager *mountingManager = _mountingManager;
  264. RCTExecuteOnMainQueue(^{
  265. RCTComponentViewDescriptor rootViewDescriptor =
  266. [mountingManager.componentViewRegistry componentViewDescriptorWithTag:surface.rootTag];
  267. [mountingManager.componentViewRegistry enqueueComponentViewWithComponentHandle:RootShadowNode::Handle()
  268. tag:surface.rootTag
  269. componentViewDescriptor:rootViewDescriptor];
  270. });
  271. [surface _unsetStage:(RCTSurfaceStagePrepared | RCTSurfaceStageMounted)];
  272. }
  273. - (void)_startAllSurfacesWithScheduler:(RCTScheduler *)scheduler
  274. {
  275. [_surfaceRegistry enumerateWithBlock:^(NSEnumerator<RCTFabricSurface *> *enumerator) {
  276. for (RCTFabricSurface *surface in enumerator) {
  277. [self _startSurface:surface scheduler:scheduler];
  278. }
  279. }];
  280. }
  281. - (void)_stopAllSurfacesWithScheduler:(RCTScheduler *)scheduler
  282. {
  283. [_surfaceRegistry enumerateWithBlock:^(NSEnumerator<RCTFabricSurface *> *enumerator) {
  284. for (RCTFabricSurface *surface in enumerator) {
  285. [self _stopSurface:surface scheduler:scheduler];
  286. }
  287. }];
  288. }
  289. #pragma mark - RCTSchedulerDelegate
  290. - (void)schedulerDidFinishTransaction:(MountingCoordinator::Shared const &)mountingCoordinator
  291. {
  292. RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:mountingCoordinator->getSurfaceId()];
  293. [surface _setStage:RCTSurfaceStagePrepared];
  294. [_mountingManager scheduleTransaction:mountingCoordinator];
  295. }
  296. - (void)schedulerDidDispatchCommand:(ShadowView const &)shadowView
  297. commandName:(std::string const &)commandName
  298. args:(folly::dynamic const)args
  299. {
  300. ReactTag tag = shadowView.tag;
  301. NSString *commandStr = [[NSString alloc] initWithUTF8String:commandName.c_str()];
  302. NSArray *argsArray = convertFollyDynamicToId(args);
  303. [self->_mountingManager dispatchCommand:tag commandName:commandStr args:argsArray];
  304. }
  305. - (void)addObserver:(id<RCTSurfacePresenterObserver>)observer
  306. {
  307. std::unique_lock<better::shared_mutex> lock(_observerListMutex);
  308. [self->_observers addObject:observer];
  309. }
  310. - (void)removeObserver:(id<RCTSurfacePresenterObserver>)observer
  311. {
  312. std::unique_lock<better::shared_mutex> lock(_observerListMutex);
  313. [self->_observers removeObject:observer];
  314. }
  315. #pragma mark - RCTMountingManagerDelegate
  316. - (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)rootTag
  317. {
  318. RCTAssertMainQueue();
  319. std::shared_lock<better::shared_mutex> lock(_observerListMutex);
  320. for (id<RCTSurfacePresenterObserver> observer in _observers) {
  321. if ([observer respondsToSelector:@selector(willMountComponentsWithRootTag:)]) {
  322. [observer willMountComponentsWithRootTag:rootTag];
  323. }
  324. }
  325. }
  326. - (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag
  327. {
  328. RCTAssertMainQueue();
  329. RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
  330. RCTSurfaceStage stage = surface.stage;
  331. if (stage & RCTSurfaceStagePrepared) {
  332. // We have to progress the stage only if the preparing phase is done.
  333. if ([surface _setStage:RCTSurfaceStageMounted]) {
  334. auto rootComponentViewDescriptor =
  335. [_mountingManager.componentViewRegistry componentViewDescriptorWithTag:rootTag];
  336. surface.view.rootView = (RCTSurfaceRootView *)rootComponentViewDescriptor.view;
  337. }
  338. }
  339. std::shared_lock<better::shared_mutex> lock(_observerListMutex);
  340. for (id<RCTSurfacePresenterObserver> observer in _observers) {
  341. if ([observer respondsToSelector:@selector(didMountComponentsWithRootTag:)]) {
  342. [observer didMountComponentsWithRootTag:rootTag];
  343. }
  344. }
  345. }
  346. @end