UNPKG

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