Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ASTextNode] Move to class method of drawRect:withParameters:isCancelled:isRasterizing: for drawing #232

Merged
merged 1 commit into from
May 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
- Add ASPageTable - A map table for fast retrieval of objects within a certain page [Huy Nguyen](https://github.com/nguyenhuy)
- [ASDisplayNode] Pass drawParameter in rendering context callbacks [Michael Schneider](https://github.com/maicki)[#248](https://github.com/TextureGroup/Texture/pull/248)
- [ASTextNode] Move to class method of drawRect:withParameters:isCancelled:isRasterizing: for drawing [Michael Schneider] (https://github.com/maicki)[#232](https://github.com/TextureGroup/Texture/pull/232)
- [ASDisplayNode] Remove instance:-drawRect:withParameters:isCancelled:isRasterizing: (https://github.com/maicki)[#232](https://github.com/TextureGroup/Texture/pull/232)
4 changes: 2 additions & 2 deletions Source/ASDisplayNode+Subclasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ NS_ASSUME_NONNULL_BEGIN
*
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
*/
+ (void)drawRect:(CGRect)bounds withParameters:(nullable id <NSObject>)parameters
+ (void)drawRect:(CGRect)bounds withParameters:(nullable id)parameters
isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock
isRasterizing:(BOOL)isRasterizing;

Expand All @@ -296,7 +296,7 @@ NS_ASSUME_NONNULL_BEGIN
*
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
*/
+ (nullable UIImage *)displayWithParameters:(nullable id<NSObject>)parameters
+ (nullable UIImage *)displayWithParameters:(nullable id)parameters
isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock;

/**
Expand Down
6 changes: 3 additions & 3 deletions Source/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ static struct ASDisplayNodeFlags GetASDisplayNodeFlags(Class c, ASDisplayNode *i
flags.implementsImageDisplay = ([c respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0);
if (instance) {
flags.implementsDrawParameters = ([instance respondsToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
flags.implementsInstanceDrawRect = ([instance respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] ? 1 : 0);
} else {
flags.implementsDrawParameters = ([c instancesRespondToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
flags.implementsInstanceDrawRect = ([c instancesRespondToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] ? 1 : 0);
}


return flags;
}

Expand Down Expand Up @@ -2004,7 +2004,7 @@ - (BOOL)_implementsDisplay
{
ASDN::MutexLocker l(__instanceLock__);

return _flags.implementsDrawRect || _flags.implementsImageDisplay || _flags.rasterizesSubtree || _flags.implementsInstanceDrawRect;
return _flags.implementsDrawRect || _flags.implementsImageDisplay || _flags.rasterizesSubtree;
}

// Track that a node will be displayed as part of the current node hierarchy.
Expand Down
136 changes: 72 additions & 64 deletions Source/ASTextNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@
static const CGFloat ASTextNodeHighlightDarkOpacity = 0.22;
static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncationAttribute";

struct ASTextNodeDrawParameter {
CGRect bounds;
UIColor *backgroundColor;
};

#pragma mark - ASTextKitRenderer

@interface ASTextNodeRendererKey : NSObject
Expand Down Expand Up @@ -123,6 +118,42 @@ - (BOOL)isEqual:(ASTextNodeRendererKey *)object
return renderer;
}

#pragma mark - ASTextNodeDrawParameter

@interface ASTextNodeDrawParameter : NSObject {
@package
ASTextKitAttributes _rendererAttributes;
UIColor *_backgroundColor;
UIEdgeInsets _textContainerInsets;
}
@end

@implementation ASTextNodeDrawParameter

- (instancetype)initWithRendererAttributes:(ASTextKitAttributes)rendererAttributes
backgroundColor:(/*nullable*/ UIColor *)backgroundColor
textContainerInsets:(UIEdgeInsets)textContainerInsets
{
self = [super init];
if (self != nil) {
_rendererAttributes = rendererAttributes;
_backgroundColor = backgroundColor;
_textContainerInsets = textContainerInsets;
}
return self;
}

- (ASTextKitRenderer *)rendererForBounds:(CGRect)bounds
{
CGRect rect = UIEdgeInsetsInsetRect(bounds, _textContainerInsets);
return rendererForAttributes(_rendererAttributes, rect.size);
}

@end


#pragma mark - ASTextNode

@interface ASTextNode () <UIGestureRecognizerDelegate>

@end
Expand All @@ -147,24 +178,10 @@ @implementation ASTextNode {
NSRange _highlightRange;
ASHighlightOverlayLayer *_activeHighlightLayer;

ASTextNodeDrawParameter _drawParameter;

UILongPressGestureRecognizer *_longPressGestureRecognizer;
}
@dynamic placeholderEnabled;

#pragma mark - NSObject

+ (void)initialize
{
[super initialize];

if (self != [ASTextNode class]) {
// Prevent custom drawing in subclasses
ASDisplayNodeAssert(!ASSubclassOverridesClassSelector([ASTextNode class], self, @selector(drawRect:withParameters:isCancelled:isRasterizing:)), @"Subclass %@ must not override drawRect:withParameters:isCancelled:isRasterizing: method. Custom drawing in %@ subclass is not supported.", NSStringFromClass(self), NSStringFromClass([ASTextNode class]));
}
}

static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];

- (instancetype)init
Expand Down Expand Up @@ -294,23 +311,29 @@ - (BOOL)supportsLayerBacking

- (ASTextKitRenderer *)_renderer
{
CGSize constrainedSize = self.threadSafeBounds.size;
return [self _rendererWithBoundsSlow:{.size = constrainedSize}];
ASDN::MutexLocker l(__instanceLock__);
return [self _locked_renderer];
}

- (ASTextKitRenderer *)_rendererWithBoundsSlow:(CGRect)bounds
- (ASTextKitRenderer *)_rendererWithBounds:(CGRect)bounds
{
ASDN::MutexLocker l(__instanceLock__);
bounds.size.width -= (_textContainerInset.left + _textContainerInset.right);
bounds.size.height -= (_textContainerInset.top + _textContainerInset.bottom);
return rendererForAttributes([self _rendererAttributes], bounds.size);
return [self _locked_rendererWithBounds:bounds];
}

- (ASTextKitRenderer *)_locked_renderer
{
return [self _locked_rendererWithBounds:[self _locked_threadSafeBounds]];
}

- (ASTextKitAttributes)_rendererAttributes
- (ASTextKitRenderer *)_locked_rendererWithBounds:(CGRect)bounds
{
bounds = UIEdgeInsetsInsetRect(bounds, _textContainerInset);
return rendererForAttributes([self _locked_rendererAttributes], bounds.size);
}

- (ASTextKitAttributes)_locked_rendererAttributes
{
ASDN::MutexLocker l(__instanceLock__);

return {
.attributedString = _attributedText,
.truncationAttributedString = [self _locked_composedTruncationText],
Expand Down Expand Up @@ -360,7 +383,7 @@ - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize

[self setNeedsDisplay];

ASTextKitRenderer *renderer = [self _rendererWithBoundsSlow:{.size = constrainedSize}];
ASTextKitRenderer *renderer = [self _locked_rendererWithBounds:{.size = constrainedSize}];
CGSize size = renderer.size;
if (_attributedText.length > 0) {
self.style.ascender = [[self class] ascenderWithAttributedString:_attributedText];
Expand Down Expand Up @@ -475,30 +498,23 @@ - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
{
ASDN::MutexLocker l(__instanceLock__);

_drawParameter = {
.backgroundColor = self.backgroundColor,
.bounds = self.bounds
};
return nil;
return [[ASTextNodeDrawParameter alloc] initWithRendererAttributes:[self _locked_rendererAttributes]
backgroundColor:self.backgroundColor
textContainerInsets:_textContainerInset];
}


- (void)drawRect:(CGRect)bounds withParameters:(id <NSObject>)p isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
+ (void)drawRect:(CGRect)bounds withParameters:(id)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing
{
ASDN::MutexLocker l(__instanceLock__);

ASTextNodeDrawParameter drawParameter = _drawParameter;
CGRect drawParameterBounds = drawParameter.bounds;
UIColor *backgroundColor = isRasterizing ? nil : drawParameter.backgroundColor;
ASTextNodeDrawParameter *drawParameter = (ASTextNodeDrawParameter *)parameters;
UIColor *backgroundColor = (isRasterizing || drawParameter == nil) ? nil : drawParameter->_backgroundColor;
UIEdgeInsets textContainerInsets = drawParameter ? drawParameter->_textContainerInsets : UIEdgeInsetsZero;
ASTextKitRenderer *renderer = [drawParameter rendererForBounds:bounds];

CGContextRef context = UIGraphicsGetCurrentContext();
ASDisplayNodeAssert(context, @"This is no good without a context.");

CGContextSaveGState(context);

CGContextTranslateCTM(context, _textContainerInset.left, _textContainerInset.top);

ASTextKitRenderer *renderer = [self _rendererWithBoundsSlow:drawParameterBounds];
CGContextTranslateCTM(context, textContainerInsets.left, textContainerInsets.top);

// Fill background
if (backgroundColor != nil) {
Expand All @@ -507,8 +523,7 @@ - (void)drawRect:(CGRect)bounds withParameters:(id <NSObject>)p isCancelled:(asd
}

// Draw text
[renderer drawInContext:context bounds:drawParameterBounds];

[renderer drawInContext:context bounds:bounds];
CGContextRestoreGState(context);
}

Expand All @@ -535,7 +550,7 @@ - (id)_linkAttributeValueAtPoint:(CGPoint)point

ASDN::MutexLocker l(__instanceLock__);

ASTextKitRenderer *renderer = [self _renderer];
ASTextKitRenderer *renderer = [self _locked_renderer];
NSRange visibleRange = renderer.firstVisibleRange;
NSAttributedString *attributedString = _attributedText;
NSRange clampedRange = NSIntersectionRange(visibleRange, NSMakeRange(0, attributedString.length));
Expand Down Expand Up @@ -841,7 +856,7 @@ - (NSArray *)_rectsForTextRange:(NSRange)textRange measureOption:(ASTextKitRende
{
ASDN::MutexLocker l(__instanceLock__);

NSArray *rects = [[self _renderer] rectsForTextRange:textRange measureOption:measureOption];
NSArray *rects = [[self _locked_renderer] rectsForTextRange:textRange measureOption:measureOption];
NSMutableArray *adjustedRects = [NSMutableArray array];

for (NSValue *rectValue in rects) {
Expand All @@ -859,15 +874,15 @@ - (CGRect)trailingRect
{
ASDN::MutexLocker l(__instanceLock__);

CGRect rect = [[self _renderer] trailingRect];
CGRect rect = [[self _locked_renderer] trailingRect];
return ASTextNodeAdjustRenderRectForShadowPadding(rect, self.shadowPadding);
}

- (CGRect)frameForTextRange:(NSRange)textRange
{
ASDN::MutexLocker l(__instanceLock__);

CGRect frame = [[self _renderer] frameForTextRange:textRange];
CGRect frame = [[self _locked_renderer] frameForTextRange:textRange];
return ASTextNodeAdjustRenderRectForShadowPadding(frame, self.shadowPadding);
}

Expand Down Expand Up @@ -897,7 +912,7 @@ - (UIImage *)placeholderImage
UIGraphicsBeginImageContext(size);
[self.placeholderColor setFill];

ASTextKitRenderer *renderer = [self _renderer];
ASTextKitRenderer *renderer = [self _locked_renderer];
NSRange visibleRange = renderer.firstVisibleRange;

// cap height is both faster and creates less subpixel blending
Expand Down Expand Up @@ -975,7 +990,7 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
NSRange visibleRange = NSMakeRange(0, 0);
{
ASDN::MutexLocker l(__instanceLock__);
visibleRange = [self _renderer].firstVisibleRange;
visibleRange = [self _locked_renderer].firstVisibleRange;
}
NSRange truncationMessageRange = [self _additionalTruncationMessageRangeWithVisibleRange:visibleRange];
[self _setHighlightRange:truncationMessageRange forAttributeName:ASTextNodeTruncationTokenAttributeName value:nil animated:YES];
Expand Down Expand Up @@ -1157,15 +1172,9 @@ - (void)setShadowRadius:(CGFloat)shadowRadius
}

- (UIEdgeInsets)shadowPadding
{
return [self shadowPaddingWithRenderer:[self _renderer]];
}

- (UIEdgeInsets)shadowPaddingWithRenderer:(ASTextKitRenderer *)renderer
{
ASDN::MutexLocker l(__instanceLock__);

return renderer.shadower.shadowPadding;
return [self _locked_renderer].shadower.shadowPadding;
}

#pragma mark - Truncation Message
Expand Down Expand Up @@ -1229,8 +1238,7 @@ - (BOOL)isTruncated
{
ASDN::MutexLocker l(__instanceLock__);

ASTextKitRenderer *renderer = [self _renderer];
return renderer.isTruncated;
return [[self _locked_renderer] isTruncated];
}

- (void)setPointSizeScaleFactors:(NSArray *)pointSizeScaleFactors
Expand Down Expand Up @@ -1266,7 +1274,7 @@ - (NSUInteger)lineCount
{
ASDN::MutexLocker l(__instanceLock__);

return [[self _renderer] lineCount];
return [[self _locked_renderer] lineCount];
}

#pragma mark - Truncation Message
Expand Down
8 changes: 1 addition & 7 deletions Source/Details/_ASDisplayLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
@param isCancelledBlock Execute this block to check whether the current drawing operation has been cancelled to avoid unnecessary work. A return value of YES means cancel drawing and return.
@param isRasterizing YES if the layer is being rasterized into another layer, in which case drawRect: probably wants to avoid doing things like filling its bounds with a zero-alpha color to clear the backing store.
*/
+ (void)drawRect:(CGRect)bounds withParameters:(id<NSObject>)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
+ (void)drawRect:(CGRect)bounds withParameters:(id)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;

/**
@summary Delegate override to provide new layer contents as a UIImage.
Expand All @@ -119,12 +119,6 @@
*/
+ (UIImage *)displayWithParameters:(id<NSObject>)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock;

/**
* @abstract instance version of drawRect class method
* @see drawRect:withParameters:isCancelled:isRasterizing class method
*/
- (void)drawRect:(CGRect)bounds withParameters:(id <NSObject>)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;

// Called on the main thread only

/**
Expand Down
2 changes: 1 addition & 1 deletion Source/Private/ASDefaultPlayButton.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ - (instancetype)init
return self;
}

+ (void)drawRect:(CGRect)bounds withParameters:(id<NSObject>)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing
+ (void)drawRect:(CGRect)bounds withParameters:(id)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing
{
CGFloat originX = bounds.size.width/4;
CGRect buttonBounds = CGRectMake(originX, bounds.size.height/4, bounds.size.width/2, bounds.size.height/2);
Expand Down
2 changes: 1 addition & 1 deletion Source/Private/ASDefaultPlaybackButton.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ - (void)setButtonType:(ASDefaultPlaybackButtonType)buttonType
};
}

+ (void)drawRect:(CGRect)bounds withParameters:(id<NSObject>)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing
+ (void)drawRect:(CGRect)bounds withParameters:(id)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing
{
ASDefaultPlaybackButtonType buttonType = (ASDefaultPlaybackButtonType)[parameters[@"buttonType"] intValue];
UIColor *color = parameters[@"color"];
Expand Down
16 changes: 4 additions & 12 deletions Source/Private/ASDisplayNode+AsyncDisplay.mm
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,8 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro
// We always create a graphics context, unless a -display method is used, OR if we are a subnode drawing into a rasterized parent.
BOOL shouldCreateGraphicsContext = (flags.implementsImageDisplay == NO && rasterizing == NO);
BOOL shouldBeginRasterizing = (rasterizing == NO && flags.rasterizesSubtree);
BOOL usesInstanceMethodDisplay = (flags.implementsInstanceDrawRect);
BOOL usesImageDisplay = (flags.implementsImageDisplay);
BOOL usesDrawRect = (flags.implementsDrawRect || flags.implementsInstanceDrawRect);
BOOL usesImageDisplay = flags.implementsImageDisplay;
BOOL usesDrawRect = flags.implementsDrawRect;

if (usesImageDisplay == NO && usesDrawRect == NO && shouldBeginRasterizing == NO) {
// Early exit before requesting more expensive properties like bounds and opaque from the layer.
Expand All @@ -195,8 +194,6 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro
}

ASDisplayNodeAssert(contentsScaleForDisplay != 0.0, @"Invalid contents scale");
ASDisplayNodeAssert(usesInstanceMethodDisplay == NO || (flags.implementsDrawRect == NO && flags.implementsImageDisplay == NO),
@"Node %@ should not implement both class and instance method display or draw", self);
ASDisplayNodeAssert(rasterizing || !(_hierarchyState & ASHierarchyStateRasterized),
@"Rasterized descendants should never display unless being drawn into the rasterized container.");

Expand Down Expand Up @@ -254,15 +251,10 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro
willDisplayNodeContentWithRenderingContext(currentContext, drawParameters);
}

// Decide if we use a class or instance method to draw or display.
id object = usesInstanceMethodDisplay ? self : [self class];

if (usesImageDisplay) { // If we are using a display method, we'll get an image back directly.
image = [object displayWithParameters:drawParameters
isCancelled:isCancelledBlock];
image = [self.class displayWithParameters:drawParameters isCancelled:isCancelledBlock];
} else if (usesDrawRect) { // If we're using a draw method, this will operate on the currentContext.
[object drawRect:bounds withParameters:drawParameters
isCancelled:isCancelledBlock isRasterizing:rasterizing];
[self.class drawRect:bounds withParameters:drawParameters isCancelled:isCancelledBlock isRasterizing:rasterizing];
}

if (didDisplayNodeContentWithRenderingContext != nil) {
Expand Down
Loading