From 0bb459b149e736cd84c7b7f7c9bdc01a9ec14dc5 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 18 Feb 2021 12:37:05 -0800 Subject: [PATCH] Back out "Fabric: Using `SurfaceHandler` on iOS" Summary: This is a backout of D24290778 (https://github.com/facebook/react-native/commit/33d6091cac5ed2f8cef06d4740c8b42fcd107271). The original diff causes T85097896 and probably T85069775. For now I am going to unland this, and then I will re-land this after the cut with a fix. Original commit changeset: 62b600c3f1b2 Changelog: [Internal] Fabric-specific internal change. Reviewed By: sammy-SC Differential Revision: D26515027 fbshipit-source-id: 057663b092e6b1d74db83c40d656b2ae142bd622 --- React/Fabric/RCTScheduler.h | 20 +- React/Fabric/RCTScheduler.mm | 41 +++- React/Fabric/RCTSurfacePresenter.h | 24 +- React/Fabric/RCTSurfacePresenter.mm | 141 ++++++++++-- React/Fabric/Surface/RCTFabricSurface.h | 8 +- React/Fabric/Surface/RCTFabricSurface.mm | 266 ++++++++++++----------- 6 files changed, 344 insertions(+), 156 deletions(-) diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index 6eca003c03..55670daca6 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -14,7 +14,6 @@ #import #import #import -#import #import NS_ASSUME_NONNULL_BEGIN @@ -48,13 +47,26 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithToolbox:(facebook::react::SchedulerToolbox)toolbox; -- (void)registerSurface:(facebook::react::SurfaceHandler const &)surfaceHandler; -- (void)unregisterSurface:(facebook::react::SurfaceHandler const &)surfaceHandler; +- (void)startSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId + moduleName:(NSString *)moduleName + initialProps:(NSDictionary *)initialProps + layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints + layoutContext:(facebook::react::LayoutContext)layoutContext; + +- (void)stopSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId; + +- (CGSize)measureSurfaceWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints + layoutContext:(facebook::react::LayoutContext)layoutContext + surfaceId:(facebook::react::SurfaceId)surfaceId; + +- (void)constraintSurfaceLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints + layoutContext:(facebook::react::LayoutContext)layoutContext + surfaceId:(facebook::react::SurfaceId)surfaceId; - (facebook::react::ComponentDescriptor const *)findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN: (facebook::react::ComponentHandle)handle; -- (void)setupAnimationDriver:(facebook::react::SurfaceHandler const &)surfaceHandler; +- (facebook::react::MountingCoordinator::Shared)mountingCoordinatorWithSurfaceId:(facebook::react::SurfaceId)surfaceId; - (void)onAnimationStarted; diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index b9d38d6cd8..3e7281be63 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -139,14 +139,43 @@ class LayoutAnimationDelegateProxy : public LayoutAnimationStatusDelegate, publi _animationDriver = nullptr; } -- (void)registerSurface:(facebook::react::SurfaceHandler const &)surfaceHandler +- (void)startSurfaceWithSurfaceId:(SurfaceId)surfaceId + moduleName:(NSString *)moduleName + initialProps:(NSDictionary *)initialProps + layoutConstraints:(LayoutConstraints)layoutConstraints + layoutContext:(LayoutContext)layoutContext { - _scheduler->registerSurface(surfaceHandler); + SystraceSection s("-[RCTScheduler startSurfaceWithSurfaceId:...]"); + + auto props = convertIdToFollyDynamic(initialProps); + _scheduler->startSurface(surfaceId, RCTStringFromNSString(moduleName), props, layoutConstraints, layoutContext); + + _scheduler->findMountingCoordinator(surfaceId)->setMountingOverrideDelegate(_animationDriver); + + _scheduler->renderTemplateToSurface( + surfaceId, props.getDefault("navigationConfig").getDefault("initialUITemplate", "").getString()); } -- (void)unregisterSurface:(facebook::react::SurfaceHandler const &)surfaceHandler +- (void)stopSurfaceWithSurfaceId:(SurfaceId)surfaceId { - _scheduler->unregisterSurface(surfaceHandler); + SystraceSection s("-[RCTScheduler stopSurfaceWithSurfaceId:]"); + _scheduler->stopSurface(surfaceId); +} + +- (CGSize)measureSurfaceWithLayoutConstraints:(LayoutConstraints)layoutConstraints + layoutContext:(LayoutContext)layoutContext + surfaceId:(SurfaceId)surfaceId +{ + SystraceSection s("-[RCTScheduler measureSurfaceWithLayoutConstraints:]"); + return RCTCGSizeFromSize(_scheduler->measureSurface(surfaceId, layoutConstraints, layoutContext)); +} + +- (void)constraintSurfaceLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints + layoutContext:(LayoutContext)layoutContext + surfaceId:(SurfaceId)surfaceId +{ + SystraceSection s("-[RCTScheduler constraintSurfaceLayoutWithLayoutConstraints:]"); + _scheduler->constraintSurfaceLayout(surfaceId, layoutConstraints, layoutContext); } - (ComponentDescriptor const *)findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN:(ComponentHandle)handle @@ -154,9 +183,9 @@ class LayoutAnimationDelegateProxy : public LayoutAnimationStatusDelegate, publi return _scheduler->findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(handle); } -- (void)setupAnimationDriver:(facebook::react::SurfaceHandler const &)surfaceHandler +- (MountingCoordinator::Shared)mountingCoordinatorWithSurfaceId:(SurfaceId)surfaceId { - surfaceHandler.getMountingCoordinator()->setMountingOverrideDelegate(_animationDriver); + return _scheduler->findMountingCoordinator(surfaceId); } - (void)onAnimationStarted diff --git a/React/Fabric/RCTSurfacePresenter.h b/React/Fabric/RCTSurfacePresenter.h index 0053a376ee..6293ef6167 100644 --- a/React/Fabric/RCTSurfacePresenter.h +++ b/React/Fabric/RCTSurfacePresenter.h @@ -11,7 +11,6 @@ #import #import #import -#import #import NS_ASSUME_NONNULL_BEGIN @@ -46,25 +45,34 @@ NS_ASSUME_NONNULL_BEGIN @interface RCTSurfacePresenter (Surface) -/* +/** * Surface uses these methods to register itself in the Presenter. */ - (void)registerSurface:(RCTFabricSurface *)surface; - (void)unregisterSurface:(RCTFabricSurface *)surface; -@property (readonly) RCTMountingManager *mountingManager; +- (void)setProps:(NSDictionary *)props surface:(RCTFabricSurface *)surface; - (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag; +/** + * Measures the Surface with given constraints. + */ +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize + surface:(RCTFabricSurface *)surface; + +/** + * Sets `minimumSize` and `maximumSize` layout constraints for the Surface. + */ +- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize surface:(RCTFabricSurface *)surface; + - (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props; -- (void)setupAnimationDriverWithSurfaceHandler:(facebook::react::SurfaceHandler const &)surfaceHandler; +- (BOOL)synchronouslyWaitSurface:(RCTFabricSurface *)surface timeout:(NSTimeInterval)timeout; -/* - * Deprecated. - * Use `RCTMountingTransactionObserverCoordinator` instead. - */ - (void)addObserver:(id)observer; + - (void)removeObserver:(id)observer; /* diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index bd11901c67..e982243d62 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -40,6 +40,25 @@ using namespace facebook::react; +static inline LayoutConstraints RCTGetLayoutConstraintsForSize(CGSize minimumSize, CGSize maximumSize) +{ + return { + .minimumSize = RCTSizeFromCGSize(minimumSize), + .maximumSize = RCTSizeFromCGSize(maximumSize), + .layoutDirection = RCTLayoutDirection([[RCTI18nUtil sharedInstance] isRTL]), + }; +} + +static inline LayoutContext RCTGetLayoutContext(CGPoint viewportOffset) +{ + return { + .pointScaleFactor = RCTScreenScale(), + .swapLeftAndRightInRTL = + [[RCTI18nUtil sharedInstance] isRTL] && [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL], + .fontSizeMultiplier = RCTFontSizeMultiplier(), + .viewportOffset = RCTPointFromCGPoint(viewportOffset)}; +} + static dispatch_queue_t RCTGetBackgroundQueue() { static dispatch_queue_t queue; @@ -100,16 +119,16 @@ static BackgroundExecutor RCTGetBackgroundExecutor() _observers = [NSMutableArray array]; _scheduler = [self _createScheduler]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_handleContentSizeCategoryDidChangeNotification:) + name:UIContentSizeCategoryDidChangeNotification + object:nil]; } return self; } -- (RCTMountingManager *)mountingManager -{ - return _mountingManager; -} - - (RCTScheduler *_Nullable)_scheduler { std::lock_guard lock(_schedulerAccessMutex); @@ -144,10 +163,10 @@ static BackgroundExecutor RCTGetBackgroundExecutor() - (void)registerSurface:(RCTFabricSurface *)surface { - [_surfaceRegistry registerSurface:surface]; RCTScheduler *scheduler = [self _scheduler]; + [_surfaceRegistry registerSurface:surface]; if (scheduler) { - [scheduler registerSurface:surface.surfaceHandler]; + [self _startSurface:surface scheduler:scheduler]; } } @@ -155,16 +174,54 @@ static BackgroundExecutor RCTGetBackgroundExecutor() { RCTScheduler *scheduler = [self _scheduler]; if (scheduler) { - [scheduler unregisterSurface:surface.surfaceHandler]; + [self _stopSurface:surface scheduler:scheduler]; } [_surfaceRegistry unregisterSurface:surface]; } +- (void)setProps:(NSDictionary *)props surface:(RCTFabricSurface *)surface +{ + RCTScheduler *scheduler = [self _scheduler]; + if (scheduler) { + [self _stopSurface:surface scheduler:scheduler]; + [self _startSurface:surface scheduler:scheduler]; + } +} + - (RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag { return [_surfaceRegistry surfaceForRootTag:rootTag]; } +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize + surface:(RCTFabricSurface *)surface +{ + RCTScheduler *scheduler = [self _scheduler]; + if (!scheduler) { + return minimumSize; + } + LayoutContext layoutContext = RCTGetLayoutContext(surface.viewportOffset); + LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(minimumSize, maximumSize); + return [scheduler measureSurfaceWithLayoutConstraints:layoutConstraints + layoutContext:layoutContext + surfaceId:surface.rootTag]; +} + +- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize surface:(RCTFabricSurface *)surface +{ + RCTScheduler *scheduler = [self _scheduler]; + if (!scheduler) { + return; + } + + LayoutContext layoutContext = RCTGetLayoutContext(surface.viewportOffset); + LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(minimumSize, maximumSize); + [scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints + layoutContext:layoutContext + surfaceId:surface.rootTag]; +} + - (UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag { UIView *componentView = @@ -196,9 +253,22 @@ static BackgroundExecutor RCTGetBackgroundExecutor() return YES; } -- (void)setupAnimationDriverWithSurfaceHandler:(facebook::react::SurfaceHandler const &)surfaceHandler +- (BOOL)synchronouslyWaitSurface:(RCTFabricSurface *)surface timeout:(NSTimeInterval)timeout { - [[self _scheduler] setupAnimationDriver:surfaceHandler]; + RCTScheduler *scheduler = [self _scheduler]; + if (!scheduler) { + return NO; + } + + auto mountingCoordinator = [scheduler mountingCoordinatorWithSurfaceId:surface.rootTag]; + + if (!mountingCoordinator->waitForTransaction(std::chrono::duration(timeout))) { + return NO; + } + + [_mountingManager scheduleTransaction:mountingCoordinator]; + + return YES; } - (BOOL)suspend @@ -307,12 +377,39 @@ static BackgroundExecutor RCTGetBackgroundExecutor() return scheduler; } +- (void)_startSurface:(RCTFabricSurface *)surface scheduler:(RCTScheduler *)scheduler +{ + RCTMountingManager *mountingManager = _mountingManager; + RCTExecuteOnMainQueue(^{ + [mountingManager attachSurfaceToView:surface.view surfaceId:surface.rootTag]; + }); + + LayoutContext layoutContext = RCTGetLayoutContext(surface.viewportOffset); + + LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(surface.minimumSize, surface.maximumSize); + + [scheduler startSurfaceWithSurfaceId:surface.rootTag + moduleName:surface.moduleName + initialProps:surface.properties + layoutConstraints:layoutConstraints + layoutContext:layoutContext]; +} + +- (void)_stopSurface:(RCTFabricSurface *)surface scheduler:(RCTScheduler *)scheduler +{ + [scheduler stopSurfaceWithSurfaceId:surface.rootTag]; + + RCTMountingManager *mountingManager = _mountingManager; + RCTExecuteOnMainQueue(^{ + [mountingManager detachSurfaceFromView:surface.view surfaceId:surface.rootTag]; + }); +} + - (void)_startAllSurfacesWithScheduler:(RCTScheduler *)scheduler { [_surfaceRegistry enumerateWithBlock:^(NSEnumerator *enumerator) { for (RCTFabricSurface *surface in enumerator) { - [scheduler registerSurface:surface.surfaceHandler]; - [surface start]; + [self _startSurface:surface scheduler:scheduler]; } }]; } @@ -321,8 +418,24 @@ static BackgroundExecutor RCTGetBackgroundExecutor() { [_surfaceRegistry enumerateWithBlock:^(NSEnumerator *enumerator) { for (RCTFabricSurface *surface in enumerator) { - [surface stop]; - [scheduler unregisterSurface:surface.surfaceHandler]; + [self _stopSurface:surface scheduler:scheduler]; + } + }]; +} + +- (void)_handleContentSizeCategoryDidChangeNotification:(NSNotification *)notification +{ + RCTScheduler *scheduler = [self _scheduler]; + + [_surfaceRegistry enumerateWithBlock:^(NSEnumerator *enumerator) { + for (RCTFabricSurface *surface in enumerator) { + LayoutContext layoutContext = RCTGetLayoutContext(surface.viewportOffset); + + LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(surface.minimumSize, surface.maximumSize); + + [scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints + layoutContext:layoutContext + surfaceId:surface.rootTag]; } }]; } diff --git a/React/Fabric/Surface/RCTFabricSurface.h b/React/Fabric/Surface/RCTFabricSurface.h index 77b3c906cc..1c3e4af43f 100644 --- a/React/Fabric/Surface/RCTFabricSurface.h +++ b/React/Fabric/Surface/RCTFabricSurface.h @@ -8,7 +8,6 @@ #import #import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -129,7 +128,12 @@ NS_ASSUME_NONNULL_BEGIN @interface RCTFabricSurface (Internal) -- (facebook::react::SurfaceHandler const &)surfaceHandler; +/** + * Sets and clears given stage flags (bitmask). + * Returns `YES` if the actual state was changed. + */ +- (BOOL)_setStage:(RCTSurfaceStage)stage; +- (BOOL)_unsetStage:(RCTSurfaceStage)stage; @end diff --git a/React/Fabric/Surface/RCTFabricSurface.mm b/React/Fabric/Surface/RCTFabricSurface.mm index c137f42282..616945339c 100644 --- a/React/Fabric/Surface/RCTFabricSurface.mm +++ b/React/Fabric/Surface/RCTFabricSurface.mm @@ -10,10 +10,6 @@ #import #import -#import -#import -#import -#import #import #import #import @@ -27,19 +23,26 @@ using namespace facebook::react; @implementation RCTFabricSurface { + // Immutable __weak RCTSurfacePresenter *_surfacePresenter; + NSString *_moduleName; - // `SurfaceHandler` is a thread-safe object, so we don't need additional synchronization. - // Objective-C++ classes cannot have instance variables without default constructors, - // hence we wrap a value into `optional` to workaround it. - better::optional _surfaceHandler; + // Protected by the `_mutex` + std::mutex _mutex; + RCTSurfaceStage _stage; + NSDictionary *_properties; + CGSize _minimumSize; + CGSize _maximumSize; + CGPoint _viewportOffset; + CGSize _intrinsicSize; - // Can be accessed from the main thread only. + // The Main thread only RCTSurfaceView *_Nullable _view; RCTSurfaceTouchHandler *_Nullable _touchHandler; } @synthesize delegate = _delegate; +@synthesize rootTag = _rootTag; - (instancetype)initWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter moduleName:(NSString *)moduleName @@ -47,19 +50,15 @@ using namespace facebook::react; { if (self = [super init]) { _surfacePresenter = surfacePresenter; + _moduleName = moduleName; + _properties = [initialProperties copy]; + _rootTag = [RCTAllocateRootViewTag() integerValue]; - _surfaceHandler = - SurfaceHandler{RCTStringFromNSString(moduleName), (SurfaceId)[RCTAllocateRootViewTag() integerValue]}; - _surfaceHandler->setProps(convertIdToFollyDynamic(initialProperties)); + _minimumSize = CGSizeZero; - [_surfacePresenter registerSurface:self]; + _maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); - [self _updateLayoutContext]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleContentSizeCategoryDidChangeNotification:) - name:UIContentSizeCategoryDidChangeNotification - object:nil]; + _stage = RCTSurfaceStageSurfaceDidInitialize; } return self; @@ -67,50 +66,41 @@ using namespace facebook::react; - (void)resetWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter { - _view = nil; _surfacePresenter = surfacePresenter; - [_surfacePresenter registerSurface:self]; + _stage = RCTSurfaceStageSurfaceDidInitialize; + _view = nil; } -- (void)dealloc -{ - [_surfacePresenter unregisterSurface:self]; -} - -#pragma mark - Life-cycle management - - (BOOL)start { - _surfaceHandler->start(); - [self _propagateStageChange]; + if (![self _setStage:RCTSurfaceStageRunning]) { + return NO; + } - RCTExecuteOnMainQueue(^{ - [self->_surfacePresenter.mountingManager attachSurfaceToView:self.view - surfaceId:self->_surfaceHandler->getSurfaceId()]; - }); - - [_surfacePresenter setupAnimationDriverWithSurfaceHandler:*_surfaceHandler]; + [_surfacePresenter registerSurface:self]; return YES; } - (BOOL)stop { - _surfaceHandler->stop(); - [self _propagateStageChange]; - - RCTExecuteOnMainQueue(^{ - [self->_surfacePresenter.mountingManager detachSurfaceFromView:self.view - surfaceId:self->_surfaceHandler->getSurfaceId()]; - }); + if (![self _unsetStage:RCTSurfaceStageRunning]) { + return NO; + } + [_surfacePresenter unregisterSurface:self]; return YES; } +- (void)dealloc +{ + [self stop]; +} + #pragma mark - Immutable Properties (no need to enforce synchronization) - (NSString *)moduleName { - return RCTNSStringFromString(_surfaceHandler->getModuleName()); + return _moduleName; } #pragma mark - Main-Threaded Routines @@ -132,13 +122,49 @@ using namespace facebook::react; - (RCTSurfaceStage)stage { - return _surfaceHandler->getStatus() == SurfaceHandler::Status::Running ? RCTSurfaceStageRunning - : RCTSurfaceStagePreparing; + std::lock_guard lock(_mutex); + return _stage; } -- (void)_propagateStageChange +- (BOOL)_setStage:(RCTSurfaceStage)stage { - RCTSurfaceStage stage = self.stage; + return [self _setStage:stage setOrUnset:YES]; +} + +- (BOOL)_unsetStage:(RCTSurfaceStage)stage +{ + return [self _setStage:stage setOrUnset:NO]; +} + +- (BOOL)_setStage:(RCTSurfaceStage)stage setOrUnset:(BOOL)setOrUnset +{ + RCTSurfaceStage updatedStage; + { + std::lock_guard lock(_mutex); + + if (setOrUnset) { + updatedStage = (RCTSurfaceStage)(_stage | stage); + } else { + updatedStage = (RCTSurfaceStage)(_stage & ~stage); + } + + if (updatedStage == _stage) { + return NO; + } + + _stage = updatedStage; + } + + [self _propagateStageChange:updatedStage]; + return YES; +} + +- (void)_propagateStageChange:(RCTSurfaceStage)stage +{ + // Updating the `view` + RCTExecuteOnMainQueue(^{ + self->_view.stage = stage; + }); // Notifying the `delegate` id delegate = self.delegate; @@ -147,113 +173,114 @@ using namespace facebook::react; } } -- (void)_updateLayoutContext -{ - auto layoutConstraints = _surfaceHandler->getLayoutConstraints(); - auto layoutContext = _surfaceHandler->getLayoutContext(); - - layoutContext.pointScaleFactor = RCTScreenScale(); - layoutContext.swapLeftAndRightInRTL = - [[RCTI18nUtil sharedInstance] isRTL] && [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]; - layoutContext.fontSizeMultiplier = RCTFontSizeMultiplier(); - - _surfaceHandler->constraintLayout(layoutConstraints, layoutContext); -} - #pragma mark - Properties Management - (NSDictionary *)properties { - return convertFollyDynamicToId(_surfaceHandler->getProps()); + std::lock_guard lock(_mutex); + return _properties; } - (void)setProperties:(NSDictionary *)properties { - _surfaceHandler->setProps(convertIdToFollyDynamic(properties)); + { + std::lock_guard lock(_mutex); + + if ([properties isEqualToDictionary:_properties]) { + return; + } + + _properties = [properties copy]; + } + + [_surfacePresenter setProps:properties surface:self]; } #pragma mark - Layout +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize +{ + return [_surfacePresenter sizeThatFitsMinimumSize:minimumSize maximumSize:maximumSize surface:self]; +} + +#pragma mark - Size Constraints + +- (void)setSize:(CGSize)size +{ + [self setMinimumSize:size maximumSize:size viewportOffset:_viewportOffset]; +} + - (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize viewportOffset:(CGPoint)viewportOffset { - auto layoutConstraints = _surfaceHandler->getLayoutConstraints(); - auto layoutContext = _surfaceHandler->getLayoutContext(); + { + std::lock_guard lock(_mutex); + if (CGSizeEqualToSize(minimumSize, _minimumSize) && CGSizeEqualToSize(maximumSize, _maximumSize) && + CGPointEqualToPoint(viewportOffset, _viewportOffset)) { + return; + } - layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize); - layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize); - - if (!isnan(viewportOffset.x) && !isnan(viewportOffset.y)) { - layoutContext.viewportOffset = RCTPointFromCGPoint(viewportOffset); + _maximumSize = maximumSize; + _minimumSize = minimumSize; + _viewportOffset = viewportOffset; } - _surfaceHandler->constraintLayout(layoutConstraints, layoutContext); + [_surfacePresenter setMinimumSize:minimumSize maximumSize:maximumSize surface:self]; } - (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize { - [self setMinimumSize:minimumSize maximumSize:maximumSize viewportOffset:CGPointMake(NAN, NAN)]; -} - -- (void)setSize:(CGSize)size -{ - [self setMinimumSize:size maximumSize:size]; -} - -- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize -{ - auto layoutConstraints = _surfaceHandler->getLayoutConstraints(); - auto layoutContext = _surfaceHandler->getLayoutContext(); - - layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize); - layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize); - - return RCTCGSizeFromSize(_surfaceHandler->measure(layoutConstraints, layoutContext)); + [self setMinimumSize:minimumSize maximumSize:maximumSize viewportOffset:_viewportOffset]; } - (CGSize)minimumSize { - return RCTCGSizeFromSize(_surfaceHandler->getLayoutConstraints().minimumSize); + std::lock_guard lock(_mutex); + return _minimumSize; } - (CGSize)maximumSize { - return RCTCGSizeFromSize(_surfaceHandler->getLayoutConstraints().maximumSize); + std::lock_guard lock(_mutex); + return _maximumSize; } - (CGPoint)viewportOffset { - return RCTCGPointFromPoint(_surfaceHandler->getLayoutContext().viewportOffset); + std::lock_guard lock(_mutex); + return _viewportOffset; +} + +#pragma mark - intrinsicSize + +- (void)setIntrinsicSize:(CGSize)intrinsicSize +{ + { + std::lock_guard lock(_mutex); + if (CGSizeEqualToSize(intrinsicSize, _intrinsicSize)) { + return; + } + + _intrinsicSize = intrinsicSize; + } + + // Notifying `delegate` + id delegate = self.delegate; + if ([delegate respondsToSelector:@selector(surface:didChangeIntrinsicSize:)]) { + [delegate surface:(RCTSurface *)(id)self didChangeIntrinsicSize:intrinsicSize]; + } +} + +- (CGSize)intrinsicSize +{ + std::lock_guard lock(_mutex); + return _intrinsicSize; } #pragma mark - Synchronous Waiting - (BOOL)synchronouslyWaitFor:(NSTimeInterval)timeout { - auto mountingCoordinator = _surfaceHandler->getMountingCoordinator(); - - if (!mountingCoordinator) { - return NO; - } - - if (!mountingCoordinator->waitForTransaction(std::chrono::duration(timeout))) { - return NO; - } - - [_surfacePresenter.mountingManager scheduleTransaction:mountingCoordinator]; - - return YES; -} - -- (void)handleContentSizeCategoryDidChangeNotification:(NSNotification *)notification -{ - [self _updateLayoutContext]; -} - -#pragma mark - Private - -- (SurfaceHandler const &)surfaceHandler; -{ - return *_surfaceHandler; + return [_surfacePresenter synchronouslyWaitSurface:self timeout:timeout]; } #pragma mark - Deprecated @@ -269,12 +296,7 @@ using namespace facebook::react; - (NSNumber *)rootViewTag { - return @(_surfaceHandler->getSurfaceId()); -} - -- (NSInteger)rootTag -{ - return (NSInteger)(_surfaceHandler->getSurfaceId()); + return @(_rootTag); } @end