From a4b5f1bf10020ee7f46fc3629d1cbb0e6d6dca4b Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Fri, 27 May 2016 09:49:15 -0700 Subject: [PATCH] Test perf effect of reverting D3269333 Reviewed By: javache Differential Revision: D3346235 fbshipit-source-id: 2008f8fb9df5d61da59bb0067b25acd5a71f256f --- Examples/UIExplorer/TextExample.ios.js | 5 +- Libraries/Image/Image.ios.js | 12 ++ .../Image/RCTImage.xcodeproj/project.pbxproj | 10 ++ Libraries/Image/RCTImageView.h | 3 +- Libraries/Image/RCTShadowVirtualImage.h | 28 ++++ Libraries/Image/RCTShadowVirtualImage.m | 82 ++++++++++++ Libraries/Image/RCTVirtualImageManager.h | 14 ++ Libraries/Image/RCTVirtualImageManager.m | 25 ++++ Libraries/Text/RCTShadowText.m | 121 +++++------------- Libraries/Text/RCTText.m | 20 --- Libraries/Text/RCTTextManager.m | 13 -- React/React.xcodeproj/project.pbxproj | 2 + React/Views/RCTImageComponent.h | 19 +++ React/Views/RCTShadowView.h | 20 --- React/Views/RCTShadowView.m | 39 ------ docs/Text.md | 14 -- 16 files changed, 225 insertions(+), 202 deletions(-) create mode 100644 Libraries/Image/RCTShadowVirtualImage.h create mode 100644 Libraries/Image/RCTShadowVirtualImage.m create mode 100644 Libraries/Image/RCTVirtualImageManager.h create mode 100644 Libraries/Image/RCTVirtualImageManager.m create mode 100644 React/Views/RCTImageComponent.h diff --git a/Examples/UIExplorer/TextExample.ios.js b/Examples/UIExplorer/TextExample.ios.js index 8c7b4ff86ef..e21b7c3bfd2 100644 --- a/Examples/UIExplorer/TextExample.ios.js +++ b/Examples/UIExplorer/TextExample.ios.js @@ -422,13 +422,12 @@ exports.examples = [ ); }, }, { - title: 'Inline views', + title: 'Inline images', render: function() { return ( - This text contains an inline blue view and - an inline image . Neat, huh? + This text contains an inline image . Neat, huh? ); diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index b2f4718f7f1..7c496656869 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -201,6 +201,10 @@ var Image = React.createClass({ validAttributes: ReactNativeViewAttributes.UIView }, + contextTypes: { + isInAParentText: React.PropTypes.bool + }, + render: function() { var source = resolveAssetSource(this.props.source) || {}; var {width, height, uri} = source; @@ -221,6 +225,13 @@ var Image = React.createClass({ console.warn('The component requires a `source` property rather than `src`.'); } + if (this.context.isInAParentText) { + RawImage = RCTVirtualImage; + if (!width || !height) { + console.warn('You must specify a width and height for the image %s', uri); + } + } + return ( +#import "RCTImageComponent.h" #import "RCTResizeMode.h" @class RCTBridge; @class RCTImageSource; -@interface RCTImageView : UIImageView +@interface RCTImageView : UIImageView - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER; diff --git a/Libraries/Image/RCTShadowVirtualImage.h b/Libraries/Image/RCTShadowVirtualImage.h new file mode 100644 index 00000000000..b9623f736f2 --- /dev/null +++ b/Libraries/Image/RCTShadowVirtualImage.h @@ -0,0 +1,28 @@ +/** + * 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" +#import "RCTImageComponent.h" +#import "RCTImageSource.h" +#import "RCTResizeMode.h" + +@class RCTBridge; + +/** + * Shadow image component, used for embedding images in non-view contexts such + * as text. This is NOT used for ordinary views. + */ +@interface RCTShadowVirtualImage : RCTShadowView + +- (instancetype)initWithBridge:(RCTBridge *)bridge; + +@property (nonatomic, strong) RCTImageSource *source; +@property (nonatomic, assign) RCTResizeMode resizeMode; + +@end diff --git a/Libraries/Image/RCTShadowVirtualImage.m b/Libraries/Image/RCTShadowVirtualImage.m new file mode 100644 index 00000000000..757a48c24ea --- /dev/null +++ b/Libraries/Image/RCTShadowVirtualImage.m @@ -0,0 +1,82 @@ +/** + * 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 "RCTShadowVirtualImage.h" +#import "RCTImageLoader.h" +#import "RCTImageUtils.h" +#import "RCTBridge.h" +#import "RCTConvert.h" +#import "RCTUIManager.h" +#import "RCTUtils.h" + +@implementation RCTShadowVirtualImage +{ + RCTBridge *_bridge; + RCTImageLoaderCancellationBlock _cancellationBlock; +} + +@synthesize image = _image; + +- (instancetype)initWithBridge:(RCTBridge *)bridge +{ + if ((self = [super init])) { + _bridge = bridge; + } + return self; +} + +RCT_NOT_IMPLEMENTED(-(instancetype)init) + +- (void)didSetProps:(NSArray *)changedProps +{ + [super didSetProps:changedProps]; + + if (changedProps.count == 0) { + // No need to reload image + return; + } + + // Cancel previous request + if (_cancellationBlock) { + _cancellationBlock(); + } + + CGSize imageSize = { + RCTZeroIfNaN(self.width), + RCTZeroIfNaN(self.height), + }; + + __weak RCTShadowVirtualImage *weakSelf = self; + _cancellationBlock = [_bridge.imageLoader loadImageWithTag:_source.imageURL.absoluteString + size:imageSize + scale:RCTScreenScale() + resizeMode:_resizeMode + progressBlock:nil + completionBlock:^(NSError *error, UIImage *image) { + + dispatch_async(_bridge.uiManager.methodQueue, ^{ + RCTShadowVirtualImage *strongSelf = weakSelf; + if (![_source isEqual:strongSelf.source]) { + // Bail out if source has changed since we started loading + return; + } + strongSelf->_image = image; + [strongSelf dirtyText]; + }); + }]; +} + +- (void)dealloc +{ + if (_cancellationBlock) { + _cancellationBlock(); + } +} + +@end diff --git a/Libraries/Image/RCTVirtualImageManager.h b/Libraries/Image/RCTVirtualImageManager.h new file mode 100644 index 00000000000..b92896235d7 --- /dev/null +++ b/Libraries/Image/RCTVirtualImageManager.h @@ -0,0 +1,14 @@ +/** + * 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 "RCTViewManager.h" + +@interface RCTVirtualImageManager : RCTViewManager + +@end diff --git a/Libraries/Image/RCTVirtualImageManager.m b/Libraries/Image/RCTVirtualImageManager.m new file mode 100644 index 00000000000..6311010f4ce --- /dev/null +++ b/Libraries/Image/RCTVirtualImageManager.m @@ -0,0 +1,25 @@ +/** + * 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 "RCTVirtualImageManager.h" +#import "RCTShadowVirtualImage.h" + +@implementation RCTVirtualImageManager + +RCT_EXPORT_MODULE() + +- (RCTShadowView *)shadowView +{ + return [[RCTShadowVirtualImage alloc] initWithBridge:self.bridge]; +} + +RCT_EXPORT_SHADOW_PROPERTY(source, RCTImageSource) +RCT_EXPORT_SHADOW_PROPERTY(resizeMode, UIViewContentMode) + +@end diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m index 3220cca7615..adf7be667d5 100644 --- a/Libraries/Text/RCTShadowText.m +++ b/Libraries/Text/RCTShadowText.m @@ -13,12 +13,12 @@ #import "RCTUIManager.h" #import "RCTBridge.h" #import "RCTConvert.h" +#import "RCTImageComponent.h" #import "RCTLog.h" #import "RCTShadowRawText.h" #import "RCTText.h" #import "RCTUtils.h" -NSString *const RCTShadowViewAttributeName = @"RCTShadowViewAttributeName"; NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName"; NSString *const RCTReactTagAttributeName = @"ReactTagAttributeName"; @@ -114,45 +114,6 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width [self dirtyPropagation]; } -- (void)applyLayoutToChildren:(css_node_t *)node - viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame - absolutePosition:(CGPoint)absolutePosition -{ - // Run layout on subviews. - NSTextStorage *textStorage = [self buildTextStorageForWidth:self.frame.size.width widthMode:CSS_MEASURE_MODE_EXACTLY]; - NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; - NSTextContainer *textContainer = layoutManager.textContainers.firstObject; - NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; - NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL]; - [layoutManager.textStorage enumerateAttribute:RCTShadowViewAttributeName inRange:characterRange options:0 usingBlock:^(RCTShadowView *child, NSRange range, BOOL *_) { - if (child != nil) { - css_node_t *childNode = child.cssNode; - float width = childNode->style.dimensions[CSS_WIDTH]; - float height = childNode->style.dimensions[CSS_HEIGHT]; - if (isUndefined(width) || isUndefined(height)) { - RCTLogError(@"Views nested within a must have a width and height"); - } - UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil]; - CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer]; - CGRect childFrame = {{ - RCTRoundPixelValue(glyphRect.origin.x), - RCTRoundPixelValue(glyphRect.origin.y + glyphRect.size.height - height + font.descender) - }, { - RCTRoundPixelValue(width), - RCTRoundPixelValue(height) - }}; - - NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:range.location]; - BOOL childIsTruncated = NSIntersectionRange(range, truncatedGlyphRange).length != 0; - - [child collectUpdatedFrames:viewsWithNewFrame - withFrame:childFrame - hidden:childIsTruncated - absolutePosition:absolutePosition]; - } - }]; -} - - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(css_measure_mode_t)widthMode { if (_cachedTextStorage && width == _cachedTextStorageWidth && widthMode == _cachedTextStorageWidthMode) { @@ -238,48 +199,33 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width _effectiveLetterSpacing = letterSpacing.doubleValue; - UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily - size:fontSize weight:fontWeight style:fontStyle - scaleMultiplier:_allowFontScaling ? _fontSizeMultiplier : 1.0]; - - CGFloat heightOfTallestSubview = 0.0; NSMutableAttributedString *attributedString = [NSMutableAttributedString new]; for (RCTShadowView *child in [self reactSubviews]) { if ([child isKindOfClass:[RCTShadowText class]]) { RCTShadowText *shadowText = (RCTShadowText *)child; [attributedString appendAttributedString: - [shadowText _attributedStringWithFontFamily:fontFamily - fontSize:fontSize - fontWeight:fontWeight - fontStyle:fontStyle - letterSpacing:letterSpacing - useBackgroundColor:YES - foregroundColor:shadowText.color ?: foregroundColor - backgroundColor:shadowText.backgroundColor ?: backgroundColor - opacity:opacity * shadowText.opacity]]; - [child setTextComputed]; + [shadowText _attributedStringWithFontFamily:fontFamily + fontSize:fontSize + fontWeight:fontWeight + fontStyle:fontStyle + letterSpacing:letterSpacing + useBackgroundColor:YES + foregroundColor:shadowText.color ?: foregroundColor + backgroundColor:shadowText.backgroundColor ?: backgroundColor + opacity:opacity * shadowText.opacity]]; } else if ([child isKindOfClass:[RCTShadowRawText class]]) { RCTShadowRawText *shadowRawText = (RCTShadowRawText *)child; [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:shadowRawText.text ?: @""]]; - [child setTextComputed]; + } else if ([child conformsToProtocol:@protocol(RCTImageComponent)]) { + NSTextAttachment *imageAttachment = [NSTextAttachment new]; + imageAttachment.image = ((id)child).image; + imageAttachment.bounds = (CGRect){CGPointZero, {RCTZeroIfNaN(child.width), RCTZeroIfNaN(child.height)}}; + [attributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:imageAttachment]]; } else { - float width = child.cssNode->style.dimensions[CSS_WIDTH]; - float height = child.cssNode->style.dimensions[CSS_HEIGHT]; - if (isUndefined(width) || isUndefined(height)) { - RCTLogError(@"Views nested within a must have a width and height"); - } - NSTextAttachment *attachment = [NSTextAttachment new]; - attachment.bounds = (CGRect){CGPointZero, {width, height}}; - NSMutableAttributedString *attachmentString = [NSMutableAttributedString new]; - [attachmentString appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]]; - [attachmentString addAttribute:RCTShadowViewAttributeName value:child range:(NSRange){0, attachmentString.length}]; - [attributedString appendAttributedString:attachmentString]; - if (height > heightOfTallestSubview) { - heightOfTallestSubview = height; - } - // Don't call setTextComputed on this child. RCTTextManager takes care of - // processing inline UIViews. + RCTLogError(@" can't have any children except , or raw strings"); } + + [child setTextComputed]; } [self _addAttribute:NSForegroundColorAttributeName @@ -295,10 +241,13 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width toAttributedString:attributedString]; } + UIFont *font = [RCTConvert UIFont:nil withFamily:fontFamily + size:fontSize weight:fontWeight style:fontStyle + scaleMultiplier:_allowFontScaling ? _fontSizeMultiplier : 1.0]; [self _addAttribute:NSFontAttributeName withValue:font toAttributedString:attributedString]; [self _addAttribute:NSKernAttributeName withValue:letterSpacing toAttributedString:attributedString]; [self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString]; - [self _setParagraphStyleOnAttributedString:attributedString heightOfTallestSubview:heightOfTallestSubview]; + [self _setParagraphStyleOnAttributedString:attributedString]; // create a non-mutable attributedString for use by the Text system which avoids copies down the line _cachedAttributedString = [[NSAttributedString alloc] initWithAttributedString:attributedString]; @@ -321,7 +270,6 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width * varying lineHeights, we simply take the max. */ - (void)_setParagraphStyleOnAttributedString:(NSMutableAttributedString *)attributedString - heightOfTallestSubview:(CGFloat)heightOfTallestSubview { // check if we have lineHeight set on self __block BOOL hasParagraphStyle = NO; @@ -329,7 +277,9 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width hasParagraphStyle = YES; } - __block float newLineHeight = _lineHeight ?: 0.0; + if (!_lineHeight) { + self.lineHeight = 0.0; + } CGFloat fontSizeMultiplier = _allowFontScaling ? _fontSizeMultiplier : 1.0; @@ -338,25 +288,15 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width if (value) { NSParagraphStyle *paragraphStyle = (NSParagraphStyle *)value; CGFloat maximumLineHeight = round(paragraphStyle.maximumLineHeight / fontSizeMultiplier); - if (maximumLineHeight > newLineHeight) { - newLineHeight = maximumLineHeight; + if (maximumLineHeight > self.lineHeight) { + self.lineHeight = maximumLineHeight; } hasParagraphStyle = YES; } }]; - if (self.lineHeight != newLineHeight) { - self.lineHeight = newLineHeight; - } - - NSTextAlignment newTextAlign = _textAlign ?: NSTextAlignmentNatural; - if (self.textAlign != newTextAlign) { - self.textAlign = newTextAlign; - } - NSWritingDirection newWritingDirection = _writingDirection ?: NSWritingDirectionNatural; - if (self.writingDirection != newWritingDirection) { - self.writingDirection = newWritingDirection; - } + self.textAlign = _textAlign ?: NSTextAlignmentNatural; + self.writingDirection = _writingDirection ?: NSWritingDirectionNatural; // if we found anything, set it :D if (hasParagraphStyle) { @@ -364,9 +304,6 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width paragraphStyle.alignment = _textAlign; paragraphStyle.baseWritingDirection = _writingDirection; CGFloat lineHeight = round(_lineHeight * fontSizeMultiplier); - if (heightOfTallestSubview > lineHeight) { - lineHeight = ceilf(heightOfTallestSubview); - } paragraphStyle.minimumLineHeight = lineHeight; paragraphStyle.maximumLineHeight = lineHeight; [attributedString addAttribute:NSParagraphStyleAttributeName diff --git a/Libraries/Text/RCTText.m b/Libraries/Text/RCTText.m index fd37c4b75ff..e57b93aa191 100644 --- a/Libraries/Text/RCTText.m +++ b/Libraries/Text/RCTText.m @@ -13,17 +13,6 @@ #import "RCTUtils.h" #import "UIView+React.h" -static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDescendants) -{ - for (UIView *child in view.reactSubviews) { - if ([child isKindOfClass:[RCTText class]]) { - collectNonTextDescendants((RCTText *)child, nonTextDescendants); - } else { - [nonTextDescendants addObject:child]; - } - } -} - @implementation RCTText { NSTextStorage *_textStorage; @@ -130,15 +119,6 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc [_highlightLayer removeFromSuperlayer]; _highlightLayer = nil; } - - for (UIView *child in [self subviews]) { - [child removeFromSuperview]; - } - NSMutableArray *nonTextDescendants = [NSMutableArray new]; - collectNonTextDescendants(self, nonTextDescendants); - for (UIView *child in nonTextDescendants) { - [self addSubview:child]; - } } - (NSNumber *)reactTagAtPoint:(CGPoint)point diff --git a/Libraries/Text/RCTTextManager.m b/Libraries/Text/RCTTextManager.m index 9104ea72c07..92fa589496d 100644 --- a/Libraries/Text/RCTTextManager.m +++ b/Libraries/Text/RCTTextManager.m @@ -20,18 +20,6 @@ #import "RCTTextView.h" #import "UIView+React.h" -static void collectDirtyNonTextDescendants(RCTShadowText *shadowView, NSMutableArray *nonTextDescendants) { - for (RCTShadowView *child in shadowView.reactSubviews) { - if ([child isKindOfClass:[RCTShadowText class]]) { - collectDirtyNonTextDescendants((RCTShadowText *)child, nonTextDescendants); - } else if ([child isKindOfClass:[RCTShadowRawText class]]) { - // no-op - } else if ([child isTextDirty]) { - [nonTextDescendants addObject:child]; - } - } -} - @interface RCTShadowText (Private) - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(css_measure_mode_t)widthMode; @@ -97,7 +85,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor) if ([shadowView isKindOfClass:[RCTShadowText class]]) { ((RCTShadowText *)shadowView).fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; [(RCTShadowText *)shadowView recomputeText]; - collectDirtyNonTextDescendants((RCTShadowText *)shadowView, queue); } else if ([shadowView isKindOfClass:[RCTShadowRawText class]]) { RCTLogError(@"Raw text cannot be used outside of a tag. Not rendering string: '%@'", [(RCTShadowRawText *)shadowView text]); diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index c967aea8534..ed4eaa24323 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -216,6 +216,7 @@ 13E067501A70F44B002CDEE1 /* RCTView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTView.m; sourceTree = ""; }; 13E067531A70F44B002CDEE1 /* UIView+React.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+React.h"; sourceTree = ""; }; 13E067541A70F44B002CDEE1 /* UIView+React.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+React.m"; sourceTree = ""; }; + 13EF7F441BC69646003F47DD /* RCTImageComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTImageComponent.h; sourceTree = ""; }; 13F17A831B8493E5007D4C75 /* RCTRedBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRedBox.h; sourceTree = ""; }; 13F17A841B8493E5007D4C75 /* RCTRedBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRedBox.m; sourceTree = ""; }; 14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptLoader.h; sourceTree = ""; }; @@ -384,6 +385,7 @@ 13AB90BF1B6FA36700713B4F /* RCTComponentData.h */, 13456E941ADAD482009F94A7 /* RCTConvert+MapKit.h */, 13AB90C01B6FA36700713B4F /* RCTComponentData.m */, + 13EF7F441BC69646003F47DD /* RCTImageComponent.h */, 13456E911ADAD2DE009F94A7 /* RCTConvert+CoreLocation.h */, 13456E921ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m */, 13456E951ADAD482009F94A7 /* RCTConvert+MapKit.m */, diff --git a/React/Views/RCTImageComponent.h b/React/Views/RCTImageComponent.h new file mode 100644 index 00000000000..a6916c9aa63 --- /dev/null +++ b/React/Views/RCTImageComponent.h @@ -0,0 +1,19 @@ +/** + * 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 + +/** + * Generic interface for components that contain an image. + */ +@protocol RCTImageComponent + +@property (nonatomic, strong, readonly) UIImage *image; + +@end diff --git a/React/Views/RCTShadowView.h b/React/Views/RCTShadowView.h index 95bae0e21b3..ad09ae9f061 100644 --- a/React/Views/RCTShadowView.h +++ b/React/Views/RCTShadowView.h @@ -139,32 +139,12 @@ typedef void (^RCTApplierBlock)(NSDictionary *viewRegistry - (NSDictionary *)processUpdatedProperties:(NSMutableSet *)applierBlocks parentProperties:(NSDictionary *)parentProperties NS_REQUIRES_SUPER; -/** - * Can be called by a parent on a child in order to calculate all views whose frame needs - * updating in that branch. Adds these frames to `viewsWithNewFrame`. Useful if layout - * enters a view where flex doesn't apply (e.g. Text) and then you want to resume flex - * layout on a subview. - */ -- (void)collectUpdatedFrames:(NSMutableSet *)viewsWithNewFrame - withFrame:(CGRect)frame - hidden:(BOOL)hidden - absolutePosition:(CGPoint)absolutePosition; - /** * Recursively apply layout to children. - * The job of applyLayoutNode:viewsWithNewFrame:absolutePosition is to apply the layout to - * this node. - * The job of applyLayoutToChildren:viewsWithNewFrame:absolutePosition is to enumerate the - * children and tell them to apply layout. - * The functionality is split into two methods so subclasses can override applyLayoutToChildren - * while using the default implementation of applyLayoutNode. */ - (void)applyLayoutNode:(css_node_t *)node viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame absolutePosition:(CGPoint)absolutePosition NS_REQUIRES_SUPER; -- (void)applyLayoutToChildren:(css_node_t *)node - viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame - absolutePosition:(CGPoint)absolutePosition; /** * The following are implementation details exposed to subclasses. Do not call them directly diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m index 0472b272c7d..d55e80c624c 100644 --- a/React/Views/RCTShadowView.m +++ b/React/Views/RCTShadowView.m @@ -157,13 +157,6 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st absolutePosition.x += node->layout.position[CSS_LEFT]; absolutePosition.y += node->layout.position[CSS_TOP]; - [self applyLayoutToChildren:node viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition]; -} - -- (void)applyLayoutToChildren:(css_node_t *)node - viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame - absolutePosition:(CGPoint)absolutePosition -{ for (int i = 0; i < node->children_count; ++i) { RCTShadowView *child = (RCTShadowView *)_reactSubviews[i]; [child applyLayoutNode:node->get_child(node->context, i) @@ -216,37 +209,6 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st } } -- (void)collectUpdatedFrames:(NSMutableSet *)viewsWithNewFrame - withFrame:(CGRect)frame - hidden:(BOOL)hidden - absolutePosition:(CGPoint)absolutePosition -{ - if (_hidden != hidden) { - // The hidden state has changed. Even if the frame hasn't changed, add - // this ShadowView to viewsWithNewFrame so the UIManager will process - // this ShadowView's UIView and update its hidden state. - _hidden = hidden; - [viewsWithNewFrame addObject:self]; - } - - if (!CGRectEqualToRect(frame, _frame)) { - _cssNode->style.position_type = CSS_POSITION_ABSOLUTE; - _cssNode->style.dimensions[CSS_WIDTH] = frame.size.width; - _cssNode->style.dimensions[CSS_HEIGHT] = frame.size.height; - _cssNode->style.position[CSS_LEFT] = frame.origin.x; - _cssNode->style.position[CSS_TOP] = frame.origin.y; - // Our parent has asked us to change our cssNode->styles. Dirty the layout - // so that we can rerun layout on this node. The request came from our parent - // so there's no need to dirty our ancestors by calling dirtyLayout. - _layoutLifecycle = RCTUpdateLifecycleDirtied; - } - - [self fillCSSNode:_cssNode]; - resetNodeLayout(self.cssNode); - layoutNode(_cssNode, frame.size.width, frame.size.height, CSS_DIRECTION_INHERIT); - [self applyLayoutNode:_cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition]; -} - - (CGRect)measureLayoutRelativeToAncestor:(RCTShadowView *)ancestor { CGPoint offset = CGPointZero; @@ -497,7 +459,6 @@ RCT_BORDER_PROPERTY(Right, RIGHT) { \ _cssNode->style.dimensions[CSS_##cssProp] = value; \ [self dirtyLayout]; \ - [self dirtyText]; \ } \ - (CGFloat)getProp \ { \ diff --git a/docs/Text.md b/docs/Text.md index 48853606e43..800137b03b0 100644 --- a/docs/Text.md +++ b/docs/Text.md @@ -21,20 +21,6 @@ Behind the scenes, React Native converts this to a flat `NSAttributedString` or 9-17: bold, red ``` -## Nested Views (iOS Only) - -On iOS, you can nest views within your Text component. Here's an example: - -```javascript - - There is a blue square - - in between my text. - -``` - -In order to use this feature, you must give the view a `width` and a `height`. - ## Containers The `` element is special relative to layout: everything inside is no longer using the flexbox layout but using text layout. This means that elements inside of a `` are no longer rectangles, but wrap when they see the end of the line.