Skip to content
This repository has been archived by the owner on Feb 18, 2019. It is now read-only.

Commit

Permalink
Extracted rootview-specific shadowview logic into new class
Browse files Browse the repository at this point in the history
Summary:It was hard to understand which parts of the shadowview API are designed to be called only on the root view, and which were applicable to any view.

This diff extracts rootview-specific logic out into a new RCTRootShadowView class.

Reviewed By: majak

Differential Revision: D3063905

fb-gh-sync-id: ef890cddfd7625fbd4bf5454314b441acdb03ac8
shipit-source-id: ef890cddfd7625fbd4bf5454314b441acdb03ac8
  • Loading branch information
nicklockwood authored and Facebook Github Bot 9 committed Mar 21, 2016
1 parent 7d059a1 commit d033c45
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 85 deletions.
14 changes: 8 additions & 6 deletions Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@
#import <XCTest/XCTest.h>

#import "RCTShadowView.h"
#import "RCTRootShadowView.h"


@interface RCTShadowViewTests : XCTestCase
@property (nonatomic, strong) RCTShadowView *parentView;
@property (nonatomic, strong) RCTRootShadowView *parentView;
@end

@implementation RCTShadowViewTests

- (void)setUp
{
[super setUp];

self.parentView = [self _shadowViewWithStyle:^(css_style_t *style) {
style->flex_direction = CSS_FLEX_DIRECTION_COLUMN;
style->dimensions[0] = 440;
Expand Down Expand Up @@ -90,7 +92,7 @@ - (void)testApplyingLayoutRecursivelyToShadowView
[self.parentView insertReactSubview:mainView atIndex:1];
[self.parentView insertReactSubview:footerView atIndex:2];

[self.parentView collectRootUpdatedFrames];
[self.parentView collectViewsWithUpdatedFrames];

XCTAssertTrue(CGRectEqualToRect([self.parentView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(0, 0, 440, 440)));
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets([self.parentView paddingAsInsets], UIEdgeInsetsMake(10, 10, 10, 10)));
Expand Down Expand Up @@ -156,17 +158,17 @@ - (void)_withShadowViewWithStyle:(void(^)(css_style_t *style))styleBlock
RCTShadowView *view = [self _shadowViewWithStyle:styleBlock];
[self.parentView insertReactSubview:view atIndex:0];
view.intrinsicContentSize = contentSize;
[self.parentView collectRootUpdatedFrames];
[self.parentView collectViewsWithUpdatedFrames];
CGRect actualRect = [view measureLayoutRelativeToAncestor:self.parentView];
XCTAssertTrue(CGRectEqualToRect(expectedRect, actualRect),
@"Expected layout to be %@, got %@",
NSStringFromCGRect(expectedRect),
NSStringFromCGRect(actualRect));
}

- (RCTShadowView *)_shadowViewWithStyle:(void(^)(css_style_t *style))styleBlock
- (RCTRootShadowView *)_shadowViewWithStyle:(void(^)(css_style_t *style))styleBlock
{
RCTShadowView *shadowView = [RCTShadowView new];
RCTRootShadowView *shadowView = [RCTRootShadowView new];

css_style_t style = shadowView.cssNode->style;
styleBlock(&style);
Expand Down
2 changes: 1 addition & 1 deletion React/Base/RCTJavaScriptLoader.m
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ + (void)loadBundleAtURL:(NSURL *)scriptURL onComplete:(RCTSourceLoadBlock)onComp

magicNumber = NSSwapLittleIntToHost(magicNumber);

int32_t sourceLength = 0;
int64_t sourceLength = 0;
if (magicNumber == RCTRAMBundleMagicNumber) {
source = [NSData dataWithBytes:&magicNumber length:sizeof(magicNumber)];

Expand Down
2 changes: 1 addition & 1 deletion React/Base/RCTPerformanceLogger.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#import "RCTProfile.h"

static int64_t RCTPLData[RCTPLSize][2] = {};
static int64_t RCTPLCookies[RCTPLSize] = {};
static NSUInteger RCTPLCookies[RCTPLSize] = {};

void RCTPerformanceLoggerStart(RCTPLTag tag)
{
Expand Down
2 changes: 1 addition & 1 deletion React/Base/RCTRootView.m
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ - (void)setBackgroundColor:(UIColor *)backgroundColor
{
_backgroundColor = backgroundColor;
if (self.reactTag && _bridge.isValid) {
[_bridge.uiManager setBackgroundColor:backgroundColor forRootView:self];
[_bridge.uiManager setBackgroundColor:backgroundColor forView:self];
}
}

Expand Down
28 changes: 20 additions & 8 deletions React/Executors/RCTJSCExecutor.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@

static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";

typedef struct ModuleData
{
typedef struct ModuleData {
uint32_t offset;
uint32_t length;
uint32_t lineNo;
Expand Down Expand Up @@ -706,7 +705,9 @@ - (NSData *)loadRAMBundle:(NSURL *)sourceURL error:(NSError **)error
{
_bundle = fopen(sourceURL.path.UTF8String, "r");
if (!_bundle) {
*error = RCTErrorWithMessage([NSString stringWithFormat:@"Bundle %@ cannot be opened: %d", sourceURL.path, errno]);
if (error) {
*error = RCTErrorWithMessage([NSString stringWithFormat:@"Bundle %@ cannot be opened: %d", sourceURL.path, errno]);
}
return nil;
}

Expand All @@ -721,7 +722,9 @@ - (NSData *)loadRAMBundle:(NSURL *)sourceURL error:(NSError **)error

uint32_t tableLength;
if (readBundle(_bundle, currentOffset, sizeof(tableLength), &tableLength) != 0) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
if (error) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
}
return nil;
}
tableLength = NSSwapLittleIntToHost(tableLength);
Expand All @@ -733,7 +736,9 @@ - (NSData *)loadRAMBundle:(NSURL *)sourceURL error:(NSError **)error

char tableStart[tableLength];
if (readBundle(_bundle, currentOffset, tableLength, tableStart) != 0) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
if (error) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
}
return nil;
}

Expand All @@ -745,7 +750,9 @@ - (NSData *)loadRAMBundle:(NSURL *)sourceURL error:(NSError **)error
char *name = malloc(nameLength + 1);

if (!name) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
if (error) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
}
return nil;
}

Expand All @@ -767,12 +774,17 @@ - (NSData *)loadRAMBundle:(NSURL *)sourceURL error:(NSError **)error

void *startupCode;
if (!(startupCode = malloc(startupData->length))) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
if (error) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
}
return nil;
}

if (readBundle(_bundle, startupData->offset, startupData->length, startupCode) != 0) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
if (error) {
*error = RCTErrorWithMessage(@"Error loading RAM Bundle");
}
free(startupCode);
return nil;
}
return [NSData dataWithBytesNoCopy:startupCode length:startupData->length freeWhenDone:YES];
Expand Down
7 changes: 4 additions & 3 deletions React/Modules/RCTUIManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
- (void)setIntrinsicContentSize:(CGSize)size forView:(UIView *)view;

/**
* Update the background color of a root view. This is usually triggered by
* manually setting the background color of the root view with native code.
* Update the background color of a view. The source of truth for
* backgroundColor is the shadow view, so if to update backgroundColor from
* native code you will need to call this method.
*/
- (void)setBackgroundColor:(UIColor *)color forRootView:(UIView *)rootView;
- (void)setBackgroundColor:(UIColor *)color forView:(UIView *)view;

/**
* Schedule a block to be executed on the UI thread. Useful if you need to execute
Expand Down
35 changes: 19 additions & 16 deletions React/Modules/RCTUIManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#import "RCTModuleMethod.h"
#import "RCTProfile.h"
#import "RCTRootView.h"
#import "RCTRootShadowView.h"
#import "RCTRootViewInternal.h"
#import "RCTScrollableProtocol.h"
#import "RCTShadowView.h"
Expand Down Expand Up @@ -358,7 +359,7 @@ - (void)registerRootView:(UIView *)rootView
if (!_viewRegistry) {
return;
}
RCTShadowView *shadowView = [RCTShadowView new];
RCTRootShadowView *shadowView = [RCTRootShadowView new];
shadowView.reactTag = reactTag;
shadowView.frame = frame;
shadowView.backgroundColor = rootView.backgroundColor;
Expand Down Expand Up @@ -406,9 +407,12 @@ - (void)setFrame:(CGRect)frame forView:(UIView *)view

// Trigger re-layout when size flexibility changes, as the root view might grow or
// shrink in the flexible dimensions.
if (RCTIsReactRootView(reactTag) && shadowView.sizeFlexibility != sizeFlexibility) {
shadowView.sizeFlexibility = sizeFlexibility;
dirtyLayout = YES;
if (RCTIsReactRootView(reactTag)) {
RCTRootShadowView *rootShadowView = (RCTRootShadowView *)shadowView;
if (rootShadowView.sizeFlexibility != sizeFlexibility) {
rootShadowView.sizeFlexibility = sizeFlexibility;
dirtyLayout = YES;
}
}

if (dirtyLayout) {
Expand All @@ -433,23 +437,22 @@ - (void)setIntrinsicContentSize:(CGSize)size forView:(UIView *)view
});
}

- (void)setBackgroundColor:(UIColor *)color forRootView:(UIView *)rootView
- (void)setBackgroundColor:(UIColor *)color forView:(UIView *)view
{
RCTAssertMainThread();

NSNumber *reactTag = rootView.reactTag;
RCTAssert(RCTIsReactRootView(reactTag), @"Specified view %@ is not a root view", reactTag);
NSNumber *reactTag = view.reactTag;

__weak RCTUIManager *weakSelf = self;
dispatch_async(_shadowQueue, ^{
RCTUIManager *strongSelf = weakSelf;
if (!_viewRegistry) {
return;
}
RCTShadowView *rootShadowView = strongSelf->_shadowViewRegistry[reactTag];
RCTAssert(rootShadowView != nil, @"Could not locate root view with tag #%@", reactTag);
rootShadowView.backgroundColor = color;
[self _amendPendingUIBlocksWithStylePropagationUpdateForRootView:rootShadowView];
RCTShadowView *shadowView = strongSelf->_shadowViewRegistry[reactTag];
RCTAssert(shadowView != nil, @"Could not locate root view with tag #%@", reactTag);
shadowView.backgroundColor = color;
[self _amendPendingUIBlocksWithStylePropagationUpdateForShadowView:shadowView];
[self flushUIBlocks];
});
}
Expand Down Expand Up @@ -500,7 +503,7 @@ - (void)addUIBlock:(RCTViewManagerUIBlock)block
[_pendingUIBlocks addObject:outerBlock];
}

- (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)rootShadowView
- (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *)rootShadowView
{
RCTAssert(![NSThread isMainThread], @"Should be called on shadow thread");

Expand All @@ -509,7 +512,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
// these structures in the UI-thread block. `NSMutableArray` is not thread
// safe so we rely on the fact that we never mutate it after it's passed to
// the main thread.
NSSet<RCTShadowView *> *viewsWithNewFrames = [rootShadowView collectRootUpdatedFrames];
NSSet<RCTShadowView *> *viewsWithNewFrames = [rootShadowView collectViewsWithUpdatedFrames];

if (!viewsWithNewFrames.count) {
// no frame change results in no UI update block
Expand Down Expand Up @@ -656,7 +659,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
};
}

- (void)_amendPendingUIBlocksWithStylePropagationUpdateForRootView:(RCTShadowView *)topView
- (void)_amendPendingUIBlocksWithStylePropagationUpdateForShadowView:(RCTShadowView *)topView
{
NSMutableSet<RCTApplierBlock> *applierBlocks = [NSMutableSet setWithCapacity:1];
[topView collectUpdatedProperties:applierBlocks parentProperties:@{}];
Expand Down Expand Up @@ -1015,9 +1018,9 @@ - (void)_layoutAndMount

// Perform layout
for (NSNumber *reactTag in _rootViewTags) {
RCTShadowView *rootView = _shadowViewRegistry[reactTag];
RCTRootShadowView *rootView = (RCTRootShadowView *)_shadowViewRegistry[reactTag];
[self addUIBlock:[self uiBlockWithLayoutUpdateForRootView:rootView]];
[self _amendPendingUIBlocksWithStylePropagationUpdateForRootView:rootView];
[self _amendPendingUIBlocksWithStylePropagationUpdateForShadowView:rootView];
}

// Clear layout animations
Expand Down
6 changes: 6 additions & 0 deletions React/React.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202031BFB948C00C07393 /* RCTMapAnnotation.m */; };
13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
13BCE8091C99CB9D00DD7AAD /* RCTRootShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BCE8081C99CB9D00DD7AAD /* RCTRootShadowView.m */; };
13C156051AB1A2840079392D /* RCTWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156021AB1A2840079392D /* RCTWebView.m */; };
13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156041AB1A2840079392D /* RCTWebViewManager.m */; };
13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */; };
Expand Down Expand Up @@ -186,6 +187,8 @@
13B202031BFB948C00C07393 /* RCTMapAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapAnnotation.m; sourceTree = "<group>"; };
13BB3D001BECD54500932C10 /* RCTImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageSource.h; sourceTree = "<group>"; };
13BB3D011BECD54500932C10 /* RCTImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageSource.m; sourceTree = "<group>"; };
13BCE8071C99CB9D00DD7AAD /* RCTRootShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootShadowView.h; sourceTree = "<group>"; };
13BCE8081C99CB9D00DD7AAD /* RCTRootShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootShadowView.m; sourceTree = "<group>"; };
13C156011AB1A2840079392D /* RCTWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebView.h; sourceTree = "<group>"; };
13C156021AB1A2840079392D /* RCTWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebView.m; sourceTree = "<group>"; };
13C156031AB1A2840079392D /* RCTWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewManager.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -424,6 +427,8 @@
131B6AF31AF1093D00FFC3E0 /* RCTSegmentedControlManager.m */,
13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */,
13E0674C1A70F44B002CDEE1 /* RCTShadowView.m */,
13BCE8071C99CB9D00DD7AAD /* RCTRootShadowView.h */,
13BCE8081C99CB9D00DD7AAD /* RCTRootShadowView.m */,
13AF20431AE707F8005F5298 /* RCTSlider.h */,
13AF20441AE707F9005F5298 /* RCTSlider.m */,
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */,
Expand Down Expand Up @@ -670,6 +675,7 @@
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */,
13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */,
13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */,
13BCE8091C99CB9D00DD7AAD /* RCTRootShadowView.m in Sources */,
14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */,
13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */,
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */,
Expand Down
26 changes: 26 additions & 0 deletions React/Views/RCTRootShadowView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "RCTShadowView.h"

@interface RCTRootShadowView : RCTShadowView

/**
* Size flexibility type used to find size constraints.
* Default to RCTRootViewSizeFlexibilityNone
*/
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;

/**
* Calculate all views whose frame needs updating after layout has been calculated.
* Returns a set contains the shadowviews that need updating.
*/
- (NSSet<RCTShadowView *> *)collectViewsWithUpdatedFrames;

@end
44 changes: 44 additions & 0 deletions React/Views/RCTRootShadowView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "RCTRootShadowView.h"

@implementation RCTRootShadowView

- (void)applySizeConstraints
{
switch (_sizeFlexibility) {
case RCTRootViewSizeFlexibilityNone:
break;
case RCTRootViewSizeFlexibilityWidth:
self.cssNode->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
break;
case RCTRootViewSizeFlexibilityHeight:
self.cssNode->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
break;
case RCTRootViewSizeFlexibilityWidthAndHeight:
self.cssNode->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
self.cssNode->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
break;
}
}

- (NSSet<RCTShadowView *> *)collectViewsWithUpdatedFrames
{
[self applySizeConstraints];

[self fillCSSNode:self.cssNode];
layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);

NSMutableSet<RCTShadowView *> *viewsWithNewFrame = [NSMutableSet set];
[self applyLayoutNode:self.cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:CGPointZero];
return viewsWithNewFrame;
}

@end
Loading

0 comments on commit d033c45

Please sign in to comment.