diff --git a/AsyncDisplayKit/ASImageNode.mm b/AsyncDisplayKit/ASImageNode.mm index 0678a52853..8609bf489f 100644 --- a/AsyncDisplayKit/ASImageNode.mm +++ b/AsyncDisplayKit/ASImageNode.mm @@ -26,46 +26,18 @@ #import "ASInternalHelpers.h" #import "ASEqualityHelpers.h" -@interface _ASImageNodeDrawParameters : NSObject - -@property (nonatomic, retain) UIImage *image; -@property (nonatomic, assign) BOOL opaque; -@property (nonatomic, assign) CGRect bounds; -@property (nonatomic, assign) CGFloat contentsScale; -@property (nonatomic, strong) UIColor *backgroundColor; -@property (nonatomic, assign) UIViewContentMode contentMode; - -@end - -// TODO: eliminate explicit parameters with a set of keys copied from the node -@implementation _ASImageNodeDrawParameters - -- (instancetype)initWithImage:(UIImage *)image - bounds:(CGRect)bounds - opaque:(BOOL)opaque - contentsScale:(CGFloat)contentsScale - backgroundColor:(UIColor *)backgroundColor - contentMode:(UIViewContentMode)contentMode -{ - if (!(self = [self init])) - return nil; - - _image = image; - _opaque = opaque; - _bounds = bounds; - _contentsScale = contentsScale; - _backgroundColor = backgroundColor; - _contentMode = contentMode; - - return self; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"<%@ : %p opaque:%@ bounds:%@ contentsScale:%.2f backgroundColor:%@ contentMode:%@>", [self class], self, @(self.opaque), NSStringFromCGRect(self.bounds), self.contentsScale, self.backgroundColor, ASDisplayNodeNSStringFromUIContentMode(self.contentMode)]; -} - -@end +struct ASImageNodeDrawParameters { + BOOL opaque; + CGRect bounds; + CGFloat contentsScale; + UIColor *backgroundColor; + UIViewContentMode contentMode; + BOOL cropEnabled; + BOOL forceUpscaling; + CGRect cropRect; + CGRect cropDisplayBounds; + asimagenode_modification_block_t imageModificationBlock; +}; @implementation ASImageNode { @@ -75,18 +47,22 @@ void (^_displayCompletionBlock)(BOOL canceled); ASDN::RecursiveMutex _imageLock; + // Drawing + ASImageNodeDrawParameters _drawParameter; + ASTextNode *_debugLabelNode; + // Cropping. BOOL _cropEnabled; // Defaults to YES. BOOL _forceUpscaling; //Defaults to NO. CGRect _cropRect; // Defaults to CGRectMake(0.5, 0.5, 0, 0) - CGRect _cropDisplayBounds; - - ASTextNode *_debugLabelNode; + CGRect _cropDisplayBounds; // Defaults to CGRectNull } @synthesize image = _image; @synthesize imageModificationBlock = _imageModificationBlock; +#pragma mark - NSObject + - (instancetype)init { if (!(self = [super init])) @@ -124,6 +100,8 @@ return nil; } +#pragma mark - Layout and Sizing + - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { ASDN::MutexLocker l(_imageLock); @@ -136,6 +114,8 @@ return CGSizeZero; } +#pragma mark - Setter / Getter + - (void)setImage:(UIImage *)image { _imageLock.lock(); @@ -177,54 +157,72 @@ self.placeholderEnabled = placeholderColor != nil; } +#pragma mark - Drawing + - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer { - return [[_ASImageNodeDrawParameters alloc] initWithImage:self.image - bounds:self.bounds - opaque:self.opaque - contentsScale:self.contentsScaleForDisplay - backgroundColor:self.backgroundColor - contentMode:self.contentMode]; + ASDN::MutexLocker l(_imageLock); + + _drawParameter = { + .bounds = self.bounds, + .opaque = self.opaque, + .contentsScale = _contentsScaleForDisplay, + .backgroundColor = self.backgroundColor, + .contentMode = self.contentMode, + .cropEnabled = _cropEnabled, + .forceUpscaling = _forceUpscaling, + .cropRect = _cropRect, + .cropDisplayBounds = _cropDisplayBounds, + .imageModificationBlock = _imageModificationBlock + }; + + return nil; } - (NSDictionary *)debugLabelAttributes { - return @{ NSFontAttributeName: [UIFont systemFontOfSize:15.0], - NSForegroundColorAttributeName: [UIColor redColor] }; + return @{ + NSFontAttributeName: [UIFont systemFontOfSize:15.0], + NSForegroundColorAttributeName: [UIColor redColor] + }; } -- (UIImage *)displayWithParameters:(_ASImageNodeDrawParameters *)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled +- (UIImage *)displayWithParameters:(id *)parameter isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled { - UIImage *image = parameters.image; - if (!image) { + UIImage *image = self.image; + if (image == nil) { return nil; } + CGRect drawParameterBounds = CGRectZero; BOOL forceUpscaling = NO; - BOOL cropEnabled = NO; - BOOL isOpaque = parameters.opaque; - UIColor *backgroundColor = parameters.backgroundColor; - UIViewContentMode contentMode = parameters.contentMode; + BOOL cropEnabled = YES; + BOOL isOpaque = NO; + UIColor *backgroundColor = nil; + UIViewContentMode contentMode = UIViewContentModeScaleAspectFill; CGFloat contentsScale = 0.0; CGRect cropDisplayBounds = CGRectZero; CGRect cropRect = CGRectZero; asimagenode_modification_block_t imageModificationBlock; - + + ASDN::MutexLocker l(_imageLock); { - ASDN::MutexLocker l(_imageLock); + ASImageNodeDrawParameters drawParameter = _drawParameter; - // FIXME: There is a small risk of these values changing between the main thread creation of drawParameters, and the execution of this method. - // We should package these up into the draw parameters object. Might be easiest to create a struct for the non-objects and make it one property. - cropEnabled = _cropEnabled; - forceUpscaling = _forceUpscaling; - contentsScale = _contentsScaleForDisplay; - cropDisplayBounds = _cropDisplayBounds; - cropRect = _cropRect; - imageModificationBlock = _imageModificationBlock; + drawParameterBounds = drawParameter.bounds; + forceUpscaling = drawParameter.forceUpscaling; + cropEnabled = drawParameter.cropEnabled; + isOpaque = drawParameter.opaque; + backgroundColor = drawParameter.backgroundColor; + contentMode = drawParameter.contentMode; + contentsScale = drawParameter.contentsScale; + cropDisplayBounds = drawParameter.cropDisplayBounds; + cropRect = drawParameter.cropRect; + imageModificationBlock = drawParameter.imageModificationBlock; } BOOL hasValidCropBounds = cropEnabled && !CGRectIsNull(cropDisplayBounds) && !CGRectIsEmpty(cropDisplayBounds); - CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : parameters.bounds); + CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : drawParameterBounds); ASDisplayNodeContextModifier preContextBlock = self.willDisplayNodeContentWithRenderingContext; ASDisplayNodeContextModifier postContextBlock = self.didDisplayNodeContentWithRenderingContext; @@ -359,7 +357,6 @@ } } -#pragma mark - - (void)setNeedsDisplayWithCompletion:(void (^ _Nullable)(BOOL canceled))displayCompletionBlock { if (self.displaySuspended) { @@ -378,6 +375,7 @@ } #pragma mark - Cropping + - (BOOL)isCropEnabled { ASDN::MutexLocker l(_imageLock); @@ -462,6 +460,7 @@ } #pragma mark - Debug + - (void)layout { [super layout]; @@ -477,6 +476,7 @@ @end #pragma mark - Extras + extern asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat borderWidth, UIColor *borderColor) { return ^(UIImage *originalImage) { diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index aba0e7e8c1..9fd9fafb7a 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -32,25 +32,10 @@ static const CGFloat ASTextNodeHighlightLightOpacity = 0.11; static const CGFloat ASTextNodeHighlightDarkOpacity = 0.22; static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncationAttribute"; -@interface ASTextNodeDrawParameters : NSObject - -@property (nonatomic, assign, readonly) CGRect bounds; -@property (nonatomic, strong, readonly) UIColor *backgroundColor; - -@end - -@implementation ASTextNodeDrawParameters - -- (instancetype)initWithBounds:(CGRect)bounds backgroundColor:(UIColor *)backgroundColor -{ - if (self = [super init]) { - _bounds = bounds; - _backgroundColor = backgroundColor; - } - return self; -} - -@end +struct ASTextNodeDrawParameter { + CGRect bounds; + UIColor *backgroundColor; +}; @interface ASTextNode () @@ -78,6 +63,8 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation ASTextKitRenderer *_renderer; + ASTextNodeDrawParameter _drawParameter; + UILongPressGestureRecognizer *_longPressGestureRecognizer; } @dynamic placeholderEnabled; @@ -431,27 +418,37 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; #pragma mark - Drawing -- (void)drawRect:(CGRect)bounds withParameters:(ASTextNodeDrawParameters *)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing +- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer +{ + _drawParameter = { + .backgroundColor = self.backgroundColor, + .bounds = self.bounds + }; + return nil; +} + +- (void)drawRect:(CGRect)bounds withParameters:(id )p isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing; { std::lock_guard l(_textLock); + + ASTextNodeDrawParameter drawParameter = _drawParameter; + CGRect drawParameterBounds = drawParameter.bounds; + UIColor *backgroundColor = isRasterizing ? nil : drawParameter.backgroundColor; CGContextRef context = UIGraphicsGetCurrentContext(); ASDisplayNodeAssert(context, @"This is no good without a context."); CGContextSaveGState(context); - ASTextKitRenderer *renderer = [self _rendererWithBounds:parameters.bounds]; + ASTextKitRenderer *renderer = [self _rendererWithBounds:drawParameterBounds]; UIEdgeInsets shadowPadding = [self shadowPaddingWithRenderer:renderer]; - CGPoint boundsOrigin = parameters.bounds.origin; + CGPoint boundsOrigin = drawParameterBounds.origin; CGPoint textOrigin = CGPointMake(boundsOrigin.x - shadowPadding.left, boundsOrigin.y - shadowPadding.top); // Fill background - if (!isRasterizing) { - UIColor *backgroundColor = parameters.backgroundColor; - if (backgroundColor) { - [backgroundColor setFill]; - UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy); - } + if (backgroundColor != nil) { + [backgroundColor setFill]; + UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy); } // Draw shadow @@ -464,11 +461,6 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; CGContextRestoreGState(context); } -- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer -{ - return [[ASTextNodeDrawParameters alloc] initWithBounds:self.threadSafeBounds backgroundColor:self.backgroundColor]; -} - #pragma mark - Attributes - (id)linkAttributeValueAtPoint:(CGPoint)point