amis-rpc-design/node_modules/react-native/React/Fabric/Surface/RCTFabricSurface.mm
2023-10-07 19:42:30 +08:00

304 lines
8.6 KiB
Plaintext

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTFabricSurface.h"
#import <mutex>
#import <React/RCTAssert.h>
#import <React/RCTConstants.h>
#import <React/RCTConversions.h>
#import <React/RCTFollyConvert.h>
#import <React/RCTI18nUtil.h>
#import <React/RCTMountingManager.h>
#import <React/RCTSurfaceDelegate.h>
#import <React/RCTSurfaceRootView.h>
#import <React/RCTSurfaceTouchHandler.h>
#import <React/RCTSurfaceView+Internal.h>
#import <React/RCTSurfaceView.h>
#import <React/RCTUIManagerUtils.h>
#import <React/RCTUtils.h>
#import <react/renderer/mounting/MountingCoordinator.h>
#import "RCTSurfacePresenter.h"
using namespace facebook::react;
@implementation RCTFabricSurface {
__weak RCTSurfacePresenter *_surfacePresenter;
// `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.
std::optional<SurfaceHandler> _surfaceHandler;
// Protects Surface's start and stop processes.
// Even though SurfaceHandler is tread-safe, it will crash if we try to stop a surface that is not running.
// To make the API easy to use, we check the status of the surface before calling `start` or `stop`,
// and we need this mutex to prevent races.
std::mutex _surfaceMutex;
// Can be accessed from the main thread only.
RCTSurfaceView *_Nullable _view;
RCTSurfaceTouchHandler *_Nullable _touchHandler;
}
@synthesize delegate = _delegate;
- (instancetype)initWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
{
if (self = [super init]) {
_surfacePresenter = surfacePresenter;
_surfaceHandler =
SurfaceHandler{RCTStringFromNSString(moduleName), (SurfaceId)[RCTAllocateRootViewTag() integerValue]};
_surfaceHandler->setProps(convertIdToFollyDynamic(initialProperties));
[_surfacePresenter registerSurface:self];
[self setMinimumSize:CGSizeZero maximumSize:RCTViewportSize()];
[self _updateLayoutContext];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleContentSizeCategoryDidChangeNotification:)
name:UIContentSizeCategoryDidChangeNotification
object:nil];
}
return self;
}
- (void)resetWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter
{
_view = nil;
_surfacePresenter = surfacePresenter;
[_surfacePresenter registerSurface:self];
}
- (void)dealloc
{
[_surfacePresenter unregisterSurface:self];
}
#pragma mark - Life-cycle management
- (void)start
{
std::lock_guard<std::mutex> lock(_surfaceMutex);
if (_surfaceHandler->getStatus() != SurfaceHandler::Status::Registered) {
return;
}
// We need to register a root view component here synchronously because right after
// we start a surface, it can initiate an update that can query the root component.
RCTUnsafeExecuteOnMainQueueSync(^{
[self->_surfacePresenter.mountingManager attachSurfaceToView:self.view
surfaceId:self->_surfaceHandler->getSurfaceId()];
});
_surfaceHandler->start();
[self _propagateStageChange];
[_surfacePresenter setupAnimationDriverWithSurfaceHandler:*_surfaceHandler];
}
- (void)stop
{
std::lock_guard<std::mutex> lock(_surfaceMutex);
if (_surfaceHandler->getStatus() != SurfaceHandler::Status::Running) {
return;
}
_surfaceHandler->stop();
[self _propagateStageChange];
RCTExecuteOnMainQueue(^{
[self->_surfacePresenter.mountingManager detachSurfaceFromView:self.view
surfaceId:self->_surfaceHandler->getSurfaceId()];
});
}
#pragma mark - Immutable Properties (no need to enforce synchronization)
- (NSString *)moduleName
{
return RCTNSStringFromString(_surfaceHandler->getModuleName());
}
#pragma mark - Main-Threaded Routines
- (RCTSurfaceView *)view
{
RCTAssertMainQueue();
if (!_view) {
_view = [[RCTSurfaceView alloc] initWithSurface:(RCTSurface *)self];
_touchHandler = [RCTSurfaceTouchHandler new];
[_touchHandler attachToView:_view];
}
return _view;
}
#pragma mark - Stage management
- (RCTSurfaceStage)stage
{
return _surfaceHandler->getStatus() == SurfaceHandler::Status::Running ? RCTSurfaceStageRunning
: RCTSurfaceStagePreparing;
}
- (void)_propagateStageChange
{
RCTSurfaceStage stage = self.stage;
// Notifying the `delegate`
id<RCTSurfaceDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(surface:didChangeStage:)]) {
[delegate surface:(RCTSurface *)self didChangeStage:stage];
}
}
- (void)_updateLayoutContext
{
auto layoutConstraints = _surfaceHandler->getLayoutConstraints();
layoutConstraints.layoutDirection = RCTLayoutDirection([[RCTI18nUtil sharedInstance] isRTL]);
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());
}
- (void)setProperties:(NSDictionary *)properties
{
_surfaceHandler->setProps(convertIdToFollyDynamic(properties));
}
#pragma mark - Layout
- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize viewportOffset:(CGPoint)viewportOffset
{
auto layoutConstraints = _surfaceHandler->getLayoutConstraints();
auto layoutContext = _surfaceHandler->getLayoutContext();
layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
if (!isnan(viewportOffset.x) && !isnan(viewportOffset.y)) {
layoutContext.viewportOffset = RCTPointFromCGPoint(viewportOffset);
}
_surfaceHandler->constraintLayout(layoutConstraints, layoutContext);
}
- (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));
}
- (CGSize)minimumSize
{
return RCTCGSizeFromSize(_surfaceHandler->getLayoutConstraints().minimumSize);
}
- (CGSize)maximumSize
{
return RCTCGSizeFromSize(_surfaceHandler->getLayoutConstraints().maximumSize);
}
- (CGPoint)viewportOffset
{
return RCTCGPointFromPoint(_surfaceHandler->getLayoutContext().viewportOffset);
}
#pragma mark - Synchronous Waiting
- (BOOL)synchronouslyWaitFor:(NSTimeInterval)timeout
{
auto mountingCoordinator = _surfaceHandler->getMountingCoordinator();
if (!mountingCoordinator) {
return NO;
}
if (!mountingCoordinator->waitForTransaction(std::chrono::duration<NSTimeInterval>(timeout))) {
return NO;
}
[_surfacePresenter.mountingManager scheduleTransaction:mountingCoordinator];
return YES;
}
- (void)handleContentSizeCategoryDidChangeNotification:(NSNotification *)notification
{
[self _updateLayoutContext];
}
#pragma mark - Private
- (SurfaceHandler const &)surfaceHandler;
{
return *_surfaceHandler;
}
#pragma mark - Deprecated
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
{
return [self initWithSurfacePresenter:bridge.surfacePresenter
moduleName:moduleName
initialProperties:initialProperties];
}
- (NSNumber *)rootViewTag
{
return @(_surfaceHandler->getSurfaceId());
}
- (NSInteger)rootTag
{
return (NSInteger)(_surfaceHandler->getSurfaceId());
}
@end