Move drawing parameters in ASTextNode and ASImageNode to structs

This commit is contained in:
Michael Schneider
2016-06-19 14:59:27 -07:00
parent 6dac29a16f
commit 3384297c58
2 changed files with 95 additions and 103 deletions

View File

@@ -26,46 +26,18 @@
#import "ASInternalHelpers.h" #import "ASInternalHelpers.h"
#import "ASEqualityHelpers.h" #import "ASEqualityHelpers.h"
@interface _ASImageNodeDrawParameters : NSObject struct ASImageNodeDrawParameters {
BOOL opaque;
@property (nonatomic, retain) UIImage *image; CGRect bounds;
@property (nonatomic, assign) BOOL opaque; CGFloat contentsScale;
@property (nonatomic, assign) CGRect bounds; UIColor *backgroundColor;
@property (nonatomic, assign) CGFloat contentsScale; UIViewContentMode contentMode;
@property (nonatomic, strong) UIColor *backgroundColor; BOOL cropEnabled;
@property (nonatomic, assign) UIViewContentMode contentMode; BOOL forceUpscaling;
CGRect cropRect;
@end CGRect cropDisplayBounds;
asimagenode_modification_block_t imageModificationBlock;
// 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
@implementation ASImageNode @implementation ASImageNode
{ {
@@ -75,18 +47,22 @@
void (^_displayCompletionBlock)(BOOL canceled); void (^_displayCompletionBlock)(BOOL canceled);
ASDN::RecursiveMutex _imageLock; ASDN::RecursiveMutex _imageLock;
// Drawing
ASImageNodeDrawParameters _drawParameter;
ASTextNode *_debugLabelNode;
// Cropping. // Cropping.
BOOL _cropEnabled; // Defaults to YES. BOOL _cropEnabled; // Defaults to YES.
BOOL _forceUpscaling; //Defaults to NO. BOOL _forceUpscaling; //Defaults to NO.
CGRect _cropRect; // Defaults to CGRectMake(0.5, 0.5, 0, 0) CGRect _cropRect; // Defaults to CGRectMake(0.5, 0.5, 0, 0)
CGRect _cropDisplayBounds; CGRect _cropDisplayBounds; // Defaults to CGRectNull
ASTextNode *_debugLabelNode;
} }
@synthesize image = _image; @synthesize image = _image;
@synthesize imageModificationBlock = _imageModificationBlock; @synthesize imageModificationBlock = _imageModificationBlock;
#pragma mark - NSObject
- (instancetype)init - (instancetype)init
{ {
if (!(self = [super init])) if (!(self = [super init]))
@@ -124,6 +100,8 @@
return nil; return nil;
} }
#pragma mark - Layout and Sizing
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
{ {
ASDN::MutexLocker l(_imageLock); ASDN::MutexLocker l(_imageLock);
@@ -136,6 +114,8 @@
return CGSizeZero; return CGSizeZero;
} }
#pragma mark - Setter / Getter
- (void)setImage:(UIImage *)image - (void)setImage:(UIImage *)image
{ {
_imageLock.lock(); _imageLock.lock();
@@ -177,54 +157,72 @@
self.placeholderEnabled = placeholderColor != nil; self.placeholderEnabled = placeholderColor != nil;
} }
#pragma mark - Drawing
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
{ {
return [[_ASImageNodeDrawParameters alloc] initWithImage:self.image ASDN::MutexLocker l(_imageLock);
bounds:self.bounds
opaque:self.opaque _drawParameter = {
contentsScale:self.contentsScaleForDisplay .bounds = self.bounds,
backgroundColor:self.backgroundColor .opaque = self.opaque,
contentMode:self.contentMode]; .contentsScale = _contentsScaleForDisplay,
.backgroundColor = self.backgroundColor,
.contentMode = self.contentMode,
.cropEnabled = _cropEnabled,
.forceUpscaling = _forceUpscaling,
.cropRect = _cropRect,
.cropDisplayBounds = _cropDisplayBounds,
.imageModificationBlock = _imageModificationBlock
};
return nil;
} }
- (NSDictionary *)debugLabelAttributes - (NSDictionary *)debugLabelAttributes
{ {
return @{ NSFontAttributeName: [UIFont systemFontOfSize:15.0], return @{
NSForegroundColorAttributeName: [UIColor redColor] }; NSFontAttributeName: [UIFont systemFontOfSize:15.0],
NSForegroundColorAttributeName: [UIColor redColor]
};
} }
- (UIImage *)displayWithParameters:(_ASImageNodeDrawParameters *)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled - (UIImage *)displayWithParameters:(id<NSObject> *)parameter isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled
{ {
UIImage *image = parameters.image; UIImage *image = self.image;
if (!image) { if (image == nil) {
return nil; return nil;
} }
CGRect drawParameterBounds = CGRectZero;
BOOL forceUpscaling = NO; BOOL forceUpscaling = NO;
BOOL cropEnabled = NO; BOOL cropEnabled = YES;
BOOL isOpaque = parameters.opaque; BOOL isOpaque = NO;
UIColor *backgroundColor = parameters.backgroundColor; UIColor *backgroundColor = nil;
UIViewContentMode contentMode = parameters.contentMode; UIViewContentMode contentMode = UIViewContentModeScaleAspectFill;
CGFloat contentsScale = 0.0; CGFloat contentsScale = 0.0;
CGRect cropDisplayBounds = CGRectZero; CGRect cropDisplayBounds = CGRectZero;
CGRect cropRect = CGRectZero; CGRect cropRect = CGRectZero;
asimagenode_modification_block_t imageModificationBlock; 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. drawParameterBounds = drawParameter.bounds;
// 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. forceUpscaling = drawParameter.forceUpscaling;
cropEnabled = _cropEnabled; cropEnabled = drawParameter.cropEnabled;
forceUpscaling = _forceUpscaling; isOpaque = drawParameter.opaque;
contentsScale = _contentsScaleForDisplay; backgroundColor = drawParameter.backgroundColor;
cropDisplayBounds = _cropDisplayBounds; contentMode = drawParameter.contentMode;
cropRect = _cropRect; contentsScale = drawParameter.contentsScale;
imageModificationBlock = _imageModificationBlock; cropDisplayBounds = drawParameter.cropDisplayBounds;
cropRect = drawParameter.cropRect;
imageModificationBlock = drawParameter.imageModificationBlock;
} }
BOOL hasValidCropBounds = cropEnabled && !CGRectIsNull(cropDisplayBounds) && !CGRectIsEmpty(cropDisplayBounds); BOOL hasValidCropBounds = cropEnabled && !CGRectIsNull(cropDisplayBounds) && !CGRectIsEmpty(cropDisplayBounds);
CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : parameters.bounds); CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : drawParameterBounds);
ASDisplayNodeContextModifier preContextBlock = self.willDisplayNodeContentWithRenderingContext; ASDisplayNodeContextModifier preContextBlock = self.willDisplayNodeContentWithRenderingContext;
ASDisplayNodeContextModifier postContextBlock = self.didDisplayNodeContentWithRenderingContext; ASDisplayNodeContextModifier postContextBlock = self.didDisplayNodeContentWithRenderingContext;
@@ -359,7 +357,6 @@
} }
} }
#pragma mark -
- (void)setNeedsDisplayWithCompletion:(void (^ _Nullable)(BOOL canceled))displayCompletionBlock - (void)setNeedsDisplayWithCompletion:(void (^ _Nullable)(BOOL canceled))displayCompletionBlock
{ {
if (self.displaySuspended) { if (self.displaySuspended) {
@@ -378,6 +375,7 @@
} }
#pragma mark - Cropping #pragma mark - Cropping
- (BOOL)isCropEnabled - (BOOL)isCropEnabled
{ {
ASDN::MutexLocker l(_imageLock); ASDN::MutexLocker l(_imageLock);
@@ -462,6 +460,7 @@
} }
#pragma mark - Debug #pragma mark - Debug
- (void)layout - (void)layout
{ {
[super layout]; [super layout];
@@ -477,6 +476,7 @@
@end @end
#pragma mark - Extras #pragma mark - Extras
extern asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat borderWidth, UIColor *borderColor) extern asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat borderWidth, UIColor *borderColor)
{ {
return ^(UIImage *originalImage) { return ^(UIImage *originalImage) {

View File

@@ -32,25 +32,10 @@ static const CGFloat ASTextNodeHighlightLightOpacity = 0.11;
static const CGFloat ASTextNodeHighlightDarkOpacity = 0.22; static const CGFloat ASTextNodeHighlightDarkOpacity = 0.22;
static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncationAttribute"; static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncationAttribute";
@interface ASTextNodeDrawParameters : NSObject struct ASTextNodeDrawParameter {
CGRect bounds;
@property (nonatomic, assign, readonly) CGRect bounds; UIColor *backgroundColor;
@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
@interface ASTextNode () <UIGestureRecognizerDelegate, NSLayoutManagerDelegate> @interface ASTextNode () <UIGestureRecognizerDelegate, NSLayoutManagerDelegate>
@@ -78,6 +63,8 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
ASTextKitRenderer *_renderer; ASTextKitRenderer *_renderer;
ASTextNodeDrawParameter _drawParameter;
UILongPressGestureRecognizer *_longPressGestureRecognizer; UILongPressGestureRecognizer *_longPressGestureRecognizer;
} }
@dynamic placeholderEnabled; @dynamic placeholderEnabled;
@@ -431,28 +418,38 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
#pragma mark - Drawing #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 <NSObject>)p isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
{ {
std::lock_guard<std::recursive_mutex> l(_textLock); std::lock_guard<std::recursive_mutex> l(_textLock);
ASTextNodeDrawParameter drawParameter = _drawParameter;
CGRect drawParameterBounds = drawParameter.bounds;
UIColor *backgroundColor = isRasterizing ? nil : drawParameter.backgroundColor;
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRef context = UIGraphicsGetCurrentContext();
ASDisplayNodeAssert(context, @"This is no good without a context."); ASDisplayNodeAssert(context, @"This is no good without a context.");
CGContextSaveGState(context); CGContextSaveGState(context);
ASTextKitRenderer *renderer = [self _rendererWithBounds:parameters.bounds]; ASTextKitRenderer *renderer = [self _rendererWithBounds:drawParameterBounds];
UIEdgeInsets shadowPadding = [self shadowPaddingWithRenderer:renderer]; 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); CGPoint textOrigin = CGPointMake(boundsOrigin.x - shadowPadding.left, boundsOrigin.y - shadowPadding.top);
// Fill background // Fill background
if (!isRasterizing) { if (backgroundColor != nil) {
UIColor *backgroundColor = parameters.backgroundColor;
if (backgroundColor) {
[backgroundColor setFill]; [backgroundColor setFill];
UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy); UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy);
} }
}
// Draw shadow // Draw shadow
[renderer.shadower setShadowInContext:context]; [renderer.shadower setShadowInContext:context];
@@ -464,11 +461,6 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
CGContextRestoreGState(context); CGContextRestoreGState(context);
} }
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
{
return [[ASTextNodeDrawParameters alloc] initWithBounds:self.threadSafeBounds backgroundColor:self.backgroundColor];
}
#pragma mark - Attributes #pragma mark - Attributes
- (id)linkAttributeValueAtPoint:(CGPoint)point - (id)linkAttributeValueAtPoint:(CGPoint)point