diff --git a/React/Fabric/Mounting/RCTMountingManager.h b/React/Fabric/Mounting/RCTMountingManager.h new file mode 100644 index 000000000..bf66ac7f5 --- /dev/null +++ b/React/Fabric/Mounting/RCTMountingManager.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTComponentViewRegistry; + +/** + * Manages mounting process. + */ +@interface RCTMountingManager : NSObject + +@property (nonatomic, weak) id delegate; +@property (nonatomic, strong) RCTComponentViewRegistry *componentViewRegistry; + +/** + * Transfroms mutation insturctions to mount items and execute them. + * The order of mutation tnstructions matters. + */ +- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions + rootTag:(ReactTag)rootTag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm new file mode 100644 index 000000000..5f16ac251 --- /dev/null +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTMountingManager.h" + +#import +#import +#import + +#import "RCTComponentViewProtocol.h" +#import "RCTComponentViewRegistry.h" +#import "RCTMountItemProtocol.h" + +#import "RCTCreateMountItem.h" +#import "RCTDeleteMountItem.h" +#import "RCTInsertMountItem.h" +#import "RCTRemoveMountItem.h" +#import "RCTUpdatePropsMountItem.h" +#import "RCTUpdateLayoutMetricsMountItem.h" + +using namespace facebook::react; + +@implementation RCTMountingManager + +- (instancetype)init +{ + if (self = [super init]) { + _componentViewRegistry = [[RCTComponentViewRegistry alloc] init]; + } + + return self; +} + +- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions + rootTag:(ReactTag)rootTag +{ + NSMutableArray *mountItems = + [[NSMutableArray alloc] initWithCapacity:instructions.size() * 2 /* ~ the worst case */]; + + for (auto instruction : instructions) { + switch (instruction.getType()) { + case TreeMutationInstruction::Creation: { + NSString *componentName = [NSString stringWithCString:instruction.getNewChildNode()->getComponentName().c_str() + encoding:NSASCIIStringEncoding]; + RCTCreateMountItem *mountItem = + [[RCTCreateMountItem alloc] initWithComponentName:componentName + tag:instruction.getNewChildNode()->getTag()]; + [mountItems addObject:mountItem]; + break; + } + case TreeMutationInstruction::Deletion: { + NSString *componentName = [NSString stringWithCString:instruction.getOldChildNode()->getComponentName().c_str() + encoding:NSASCIIStringEncoding]; + RCTDeleteMountItem *mountItem = + [[RCTDeleteMountItem alloc] initWithComponentName:componentName + tag:instruction.getOldChildNode()->getTag()]; + [mountItems addObject:mountItem]; + break; + } + + case TreeMutationInstruction::Insertion: { + RCTInsertMountItem *mountItem = + [[RCTInsertMountItem alloc] initWithChildTag:instruction.getNewChildNode()->getTag() + parentTag:instruction.getParentNode()->getTag() + index:instruction.getIndex()]; + [mountItems addObject:mountItem]; + + // Props + [mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag() + oldProps:nullptr + newProps:instruction.getNewChildNode()->getProps()]]; + + // Layout + SharedLayoutableShadowNode layoutableNewShadowNode = + std::dynamic_pointer_cast(instruction.getNewChildNode()); + + if (layoutableNewShadowNode) { + [mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag() + oldLayoutMetrics:{} + newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()]]; + } + break; + } + + case TreeMutationInstruction::Removal: { + RCTRemoveMountItem *mountItem = + [[RCTRemoveMountItem alloc] initWithChildTag:instruction.getOldChildNode()->getTag() + parentTag:instruction.getParentNode()->getTag() + index:instruction.getIndex()]; + [mountItems addObject:mountItem]; + break; + } + + case TreeMutationInstruction::Replacement: { + SharedShadowNode oldShadowNode = instruction.getOldChildNode(); + SharedShadowNode newShadowNode = instruction.getNewChildNode(); + + // Props + if (oldShadowNode->getProps() != newShadowNode->getProps()) { + RCTUpdatePropsMountItem *mountItem = + [[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag() + oldProps:instruction.getOldChildNode()->getProps() + newProps:instruction.getNewChildNode()->getProps()]; + [mountItems addObject:mountItem]; + } + + // Layout + SharedLayoutableShadowNode layoutableOldShadowNode = + std::dynamic_pointer_cast(oldShadowNode); + + if (layoutableOldShadowNode) { + SharedLayoutableShadowNode layoutableNewShadowNode = + std::dynamic_pointer_cast(newShadowNode); + + if (layoutableOldShadowNode->getLayoutMetrics() != layoutableNewShadowNode->getLayoutMetrics()) { + RCTUpdateLayoutMetricsMountItem *mountItem = + [[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag() + oldLayoutMetrics:layoutableOldShadowNode->getLayoutMetrics() + newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()]; + [mountItems addObject:mountItem]; + } + } + + break; + } + } + } + + RCTExecuteOnMainQueue(^{ + [self _performMountItems:mountItems rootTag:rootTag]; + }); +} + +- (void)_performMountItems:(NSArray *)mountItems + rootTag:(ReactTag)rootTag +{ + RCTAssertMainQueue(); + + [self.delegate mountingManager:self willMountComponentsWithRootTag:rootTag]; + + for (id mountItem in mountItems) { + [mountItem executeWithRegistry:_componentViewRegistry]; + } + + [self.delegate mountingManager:self didMountComponentsWithRootTag:rootTag]; +} + +@end diff --git a/React/Fabric/Mounting/RCTMountingManagerDelegate.h b/React/Fabric/Mounting/RCTMountingManagerDelegate.h new file mode 100644 index 000000000..90ef6cecf --- /dev/null +++ b/React/Fabric/Mounting/RCTMountingManagerDelegate.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTMountingManager; + +/** + * MountingManager's delegate. + */ +@protocol RCTMountingManagerDelegate + +/* + * Called right *before* execution of mount items which affect a Surface with + * given `rootTag`. + * Always called on the main queue. + */ +- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)MountingManager; + +/* + * Called right *after* execution of mount items which affect a Surface with + * given `rootTag`. + * Always called on the main queue. + */ +- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag; + +@end + +NS_ASSUME_NONNULL_END