-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[ASCornerRounding] Introduce .cornerRoundingType: CALayer, Precomposited, or Clip Corners. #465
Changes from 7 commits
0f18715
86238ed
704c8e6
646ff7d
94c8a42
273025d
82eaa1c
c102dd2
cd62d4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -161,6 +161,8 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro | |
isCancelledBlock:(asdisplaynode_iscancelled_block_t)isCancelledBlock | ||
rasterizing:(BOOL)rasterizing | ||
{ | ||
ASDisplayNodeAssertMainThread(); | ||
|
||
asyncdisplaykit_async_transaction_operation_block_t displayBlock = nil; | ||
ASDisplayNodeFlags flags; | ||
|
||
|
@@ -182,6 +184,9 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro | |
|
||
BOOL opaque = self.opaque; | ||
CGRect bounds = self.bounds; | ||
UIColor *backgroundColor = self.backgroundColor; | ||
CGColorRef borderColor = self.borderColor; | ||
CGFloat borderWidth = self.borderWidth; | ||
CGFloat contentsScaleForDisplay = _contentsScaleForDisplay; | ||
|
||
__instanceLock__.unlock(); | ||
|
@@ -206,7 +211,7 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro | |
|
||
// If [UIColor clearColor] or another semitransparent background color is used, include alpha channel when rasterizing. | ||
// Unlike CALayer drawing, we include the backgroundColor as a base during rasterization. | ||
opaque = opaque && CGColorGetAlpha(self.backgroundColor.CGColor) == 1.0f; | ||
opaque = opaque && CGColorGetAlpha(backgroundColor.CGColor) == 1.0f; | ||
|
||
displayBlock = ^id{ | ||
CHECK_CANCELLED_AND_RETURN_NIL(); | ||
|
@@ -235,32 +240,18 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro | |
|
||
CGContextRef currentContext = UIGraphicsGetCurrentContext(); | ||
UIImage *image = nil; | ||
|
||
ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext = nil; | ||
ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext = nil; | ||
if (currentContext) { | ||
__instanceLock__.lock(); | ||
willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext; | ||
didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext; | ||
__instanceLock__.unlock(); | ||
} | ||
|
||
|
||
|
||
// For -display methods, we don't have a context, and thus will not call the _willDisplayNodeContentWithRenderingContext or | ||
// _didDisplayNodeContentWithRenderingContext blocks. It's up to the implementation of -display... to do what it needs. | ||
if (willDisplayNodeContentWithRenderingContext != nil) { | ||
willDisplayNodeContentWithRenderingContext(currentContext, drawParameters); | ||
} | ||
[self __willDisplayNodeContentWithRenderingContext:currentContext drawParameters:drawParameters]; | ||
|
||
if (usesImageDisplay) { // If we are using a display method, we'll get an image back directly. | ||
image = [self.class displayWithParameters:drawParameters isCancelled:isCancelledBlock]; | ||
} else if (usesDrawRect) { // If we're using a draw method, this will operate on the currentContext. | ||
[self.class drawRect:bounds withParameters:drawParameters isCancelled:isCancelledBlock isRasterizing:rasterizing]; | ||
} | ||
|
||
if (didDisplayNodeContentWithRenderingContext != nil) { | ||
didDisplayNodeContentWithRenderingContext(currentContext, drawParameters); | ||
} | ||
[self __didDisplayNodeContentWithRenderingContext:currentContext image:&image drawParameters:drawParameters backgroundColor:backgroundColor borderWidth:borderWidth borderColor:borderColor]; | ||
|
||
if (shouldCreateGraphicsContext) { | ||
CHECK_CANCELLED_AND_RETURN_NIL( UIGraphicsEndImageContext(); ); | ||
|
@@ -290,6 +281,91 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro | |
return displayBlock; | ||
} | ||
|
||
- (void)__willDisplayNodeContentWithRenderingContext:(CGContextRef)context drawParameters:(id _Nullable)drawParameters | ||
{ | ||
if (context) { | ||
__instanceLock__.lock(); | ||
ASCornerRoundingType cornerRoundingType = _cornerRoundingType; | ||
CGFloat cornerRadius = _cornerRadius; | ||
ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext; | ||
__instanceLock__.unlock(); | ||
|
||
if (cornerRoundingType == ASCornerRoundingTypePrecomposited && cornerRadius > 0.0) { | ||
ASDisplayNodeAssert(context == UIGraphicsGetCurrentContext(), @"context is expected to be pushed on UIGraphics stack %@", self); | ||
// TODO: This clip path should be removed if we are rasterizing. | ||
CGRect boundingBox = CGContextGetClipBoundingBox(context); | ||
[[UIBezierPath bezierPathWithRoundedRect:boundingBox cornerRadius:cornerRadius] addClip]; | ||
} | ||
|
||
if (willDisplayNodeContentWithRenderingContext) { | ||
willDisplayNodeContentWithRenderingContext(context, drawParameters); | ||
} | ||
} | ||
|
||
} | ||
- (void)__didDisplayNodeContentWithRenderingContext:(CGContextRef)context image:(UIImage **)image drawParameters:(id _Nullable)drawParameters backgroundColor:(UIColor *)backgroundColor borderWidth:(CGFloat)borderWidth borderColor:(CGColorRef)borderColor | ||
{ | ||
if (context == NULL && *image == NULL) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure whether you're looking for |
||
return; | ||
} | ||
|
||
__instanceLock__.lock(); | ||
ASCornerRoundingType cornerRoundingType = _cornerRoundingType; | ||
CGFloat cornerRadius = _cornerRadius; | ||
CGFloat contentsScale = _contentsScaleForDisplay; | ||
ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext; | ||
__instanceLock__.unlock(); | ||
|
||
if (context != NULL) { | ||
if (didDisplayNodeContentWithRenderingContext) { | ||
didDisplayNodeContentWithRenderingContext(context, drawParameters); | ||
} | ||
} | ||
|
||
if (cornerRoundingType == ASCornerRoundingTypePrecomposited && cornerRadius > 0.0f) { | ||
CGRect bounds = CGRectZero; | ||
if (context == NULL) { | ||
bounds = self.threadSafeBounds; | ||
bounds.size.width *= contentsScale; | ||
bounds.size.height *= contentsScale; | ||
CGFloat white = 0.0f, alpha = 0.0f; | ||
[backgroundColor getWhite:&white alpha:&alpha]; | ||
UIGraphicsBeginImageContextWithOptions(bounds.size, (alpha == 1.0f), contentsScale); | ||
[*image drawInRect:bounds]; | ||
} else { | ||
bounds = CGContextGetClipBoundingBox(context); | ||
} | ||
|
||
ASDisplayNodeAssert(UIGraphicsGetCurrentContext(), @"context is expected to be pushed on UIGraphics stack %@", self); | ||
|
||
UIBezierPath *roundedHole = [UIBezierPath bezierPathWithRect:bounds]; | ||
[roundedHole appendPath:[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:cornerRadius * contentsScale]]; | ||
roundedHole.usesEvenOddFillRule = YES; | ||
|
||
UIBezierPath *roundedPath = nil; | ||
if (borderWidth > 0.0f) { // Don't create roundedPath and stroke if borderWidth is 0.0 | ||
CGFloat strokeThickness = borderWidth * contentsScale; | ||
CGFloat strokeInset = ((strokeThickness + 1.0f) / 2.0f) - 1.0f; | ||
roundedPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(bounds, strokeInset, strokeInset) | ||
cornerRadius:_cornerRadius * contentsScale]; | ||
roundedPath.lineWidth = strokeThickness; | ||
[[UIColor colorWithCGColor:borderColor] setStroke]; | ||
} | ||
|
||
// Punch out the corners by copying the backgroundColor over them. | ||
// This works for everything from clearColor to opaque colors. | ||
[backgroundColor setFill]; | ||
[roundedHole fillWithBlendMode:kCGBlendModeCopy alpha:1.0f]; | ||
|
||
[roundedPath stroke]; // Won't do anything if borderWidth is 0 and roundedPath is nil. | ||
|
||
if (*image) { | ||
*image = UIGraphicsGetImageFromCurrentImageContext(); | ||
UIGraphicsEndImageContext(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be |
||
} | ||
} | ||
|
||
- (void)displayAsyncLayer:(_ASDisplayLayer *)asyncLayer asynchronously:(BOOL)asynchronously | ||
{ | ||
ASDisplayNodeAssertMainThread(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think following code will be better performance.
It reduce accessing to array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@appleguy
Thanks! I understand.
Sorry, I may be misunderstanding about retain and release.
Does returning by subscript of NSArray not create a retain?