This repository was archived by the owner on Feb 2, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
[ASDisplayNode+AsyncDisplay.mm] Refactor display block creation method for conciseness and readability. #1933
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
4ff6a54
[ASDisplayNode+AsyncDisplay.mm] Refactor display block creation metho…
appleguy 7a5346b
[ASDisplayNode+AsyncDisplay.mm] Some additional fixes / improvements …
appleguy e456df2
Merge branch 'master' into RefactorAsyncDisplay
appleguy a096e5b
Fix one last spot of the merge with __instanceLock__.unlock();
appleguy fc13812
Merge branch 'master' into RefactorAsyncDisplay
appleguy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,6 +75,20 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync, | |
} | ||
} | ||
|
||
#define DISPLAY_COUNT_INCREMENT() __ASDisplayLayerIncrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
#define DISPLAY_COUNT_DECREMENT() __ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
#define CHECK_CANCELLED_AND_RETURN_NIL_WITH_DECREMENT(expr) if (isCancelledBlock()) { \ | ||
expr; \ | ||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); \ | ||
return nil; \ | ||
} \ | ||
|
||
#define CHECK_CANCELLED_AND_RETURN_NIL(expr) if (isCancelledBlock()) { \ | ||
expr; \ | ||
return nil; \ | ||
} \ | ||
|
||
|
||
- (NSObject *)drawParameters | ||
{ | ||
if (_flags.implementsDrawParameters) { | ||
|
@@ -179,141 +193,122 @@ - (void)_recursivelyRasterizeSelfAndSublayersWithIsCancelledBlock:(asdisplaynode | |
} | ||
} | ||
|
||
- (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchronous:(BOOL)asynchronous isCancelledBlock:(asdisplaynode_iscancelled_block_t)isCancelledBlock rasterizing:(BOOL)rasterizing | ||
- (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchronous:(BOOL)asynchronous | ||
isCancelledBlock:(asdisplaynode_iscancelled_block_t)isCancelledBlock | ||
rasterizing:(BOOL)rasterizing | ||
{ | ||
asyncdisplaykit_async_transaction_operation_block_t displayBlock = nil; | ||
ASDisplayNodeFlags flags; | ||
|
||
__instanceLock__.lock(); | ||
|
||
flags = _flags; | ||
__instanceLock__.unlock(); | ||
|
||
ASDisplayNodeAssert(rasterizing || !(_hierarchyState & ASHierarchyStateRasterized), @"Rasterized descendants should never display unless being drawn into the rasterized container."); | ||
// 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.implementsInstanceImageDisplay == NO && flags.implementsImageDisplay == NO && rasterizing == NO); | ||
BOOL shouldBeginRasterizing = (rasterizing == NO && flags.shouldRasterizeDescendants); | ||
BOOL usesInstanceMethodDisplay = (flags.implementsInstanceDrawRect || flags.implementsInstanceImageDisplay); | ||
BOOL usesImageDisplay = (flags.implementsImageDisplay || flags.implementsInstanceImageDisplay); | ||
BOOL usesDrawRect = (flags.implementsDrawRect || flags.implementsInstanceDrawRect); | ||
|
||
if (usesImageDisplay == NO && usesDrawRect == NO && shouldBeginRasterizing == NO) { | ||
// Early exit before requesting more expensive properties like bounds and opaque from the layer. | ||
__instanceLock__.unlock(); | ||
return nil; | ||
} | ||
|
||
BOOL opaque = self.opaque; | ||
CGRect bounds = self.bounds; | ||
CGFloat contentsScaleForDisplay = _contentsScaleForDisplay; | ||
|
||
if (!rasterizing && self.shouldRasterizeDescendants) { | ||
CGRect bounds = self.bounds; | ||
if (CGRectIsEmpty(bounds)) { | ||
return nil; | ||
} | ||
// Capture drawParameters from delegate on main thread, if this node is displaying itself rather than recursively rasterizing. | ||
id drawParameters = (shouldBeginRasterizing == NO ? [self drawParameters] : nil); | ||
|
||
__instanceLock__.unlock(); | ||
|
||
// Only the -display methods should be called if we can't size the graphics buffer to use. | ||
if (CGRectIsEmpty(bounds) && (shouldBeginRasterizing || shouldCreateGraphicsContext)) { | ||
return nil; | ||
} | ||
|
||
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."); | ||
|
||
if (shouldBeginRasterizing == YES) { | ||
// Collect displayBlocks for all descendants. | ||
NSMutableArray *displayBlocks = [NSMutableArray array]; | ||
[self _recursivelyRasterizeSelfAndSublayersWithIsCancelledBlock:isCancelledBlock displayBlocks:displayBlocks]; | ||
|
||
CGFloat contentsScaleForDisplay = self.contentsScaleForDisplay; | ||
BOOL opaque = self.opaque && CGColorGetAlpha(self.backgroundColor.CGColor) == 1.0f; | ||
|
||
ASDisplayNodeAssert(self.contentsScaleForDisplay != 0.0, @"Invalid contents scale"); | ||
CHECK_CANCELLED_AND_RETURN_NIL(); | ||
|
||
// 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; | ||
|
||
displayBlock = ^id{ | ||
__ASDisplayLayerIncrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
if (isCancelledBlock()) { | ||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
return nil; | ||
} | ||
|
||
ASDN_DELAY_FOR_DISPLAY(); | ||
DISPLAY_COUNT_INCREMENT(); | ||
CHECK_CANCELLED_AND_RETURN_NIL_WITH_DECREMENT(); | ||
|
||
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, contentsScaleForDisplay); | ||
|
||
for (dispatch_block_t block in displayBlocks) { | ||
if (isCancelledBlock()) { | ||
UIGraphicsEndImageContext(); | ||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
return nil; | ||
} | ||
CHECK_CANCELLED_AND_RETURN_NIL_WITH_DECREMENT(UIGraphicsEndImageContext()); | ||
block(); | ||
} | ||
|
||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); | ||
UIGraphicsEndImageContext(); | ||
|
||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
|
||
return image; | ||
}; | ||
} else if (flags.implementsInstanceImageDisplay || flags.implementsImageDisplay) { | ||
// Capture drawParameters from delegate on main thread | ||
id drawParameters = [self drawParameters]; | ||
|
||
displayBlock = ^id{ | ||
__ASDisplayLayerIncrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
if (isCancelledBlock()) { | ||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
return nil; | ||
} | ||
|
||
ASDN_DELAY_FOR_DISPLAY(); | ||
|
||
UIImage *result = nil; | ||
//We can't call _willDisplayNodeContentWithRenderingContext or _didDisplayNodeContentWithRenderingContext because we don't | ||
//have a context. We rely on implementors of displayWithParameters:isCancelled: to call | ||
if (flags.implementsInstanceImageDisplay) { | ||
result = [self displayWithParameters:drawParameters isCancelled:isCancelledBlock]; | ||
} else { | ||
result = [[self class] displayWithParameters:drawParameters isCancelled:isCancelledBlock]; | ||
} | ||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
return result; | ||
DISPLAY_COUNT_DECREMENT(); | ||
return image; | ||
}; | ||
|
||
} else if (flags.implementsInstanceDrawRect || flags.implementsDrawRect) { | ||
|
||
CGRect bounds = self.bounds; | ||
if (CGRectIsEmpty(bounds)) { | ||
return nil; | ||
} | ||
|
||
// Capture drawParameters from delegate on main thread | ||
id drawParameters = [self drawParameters]; | ||
CGFloat contentsScaleForDisplay = self.contentsScaleForDisplay; | ||
BOOL opaque = self.opaque; | ||
|
||
} else { | ||
displayBlock = ^id{ | ||
__ASDisplayLayerIncrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
if (isCancelledBlock()) { | ||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
return nil; | ||
} | ||
DISPLAY_COUNT_INCREMENT(); | ||
CHECK_CANCELLED_AND_RETURN_NIL_WITH_DECREMENT(); | ||
|
||
ASDN_DELAY_FOR_DISPLAY(); | ||
|
||
if (!rasterizing) { | ||
if (shouldCreateGraphicsContext) { | ||
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, contentsScaleForDisplay); | ||
CHECK_CANCELLED_AND_RETURN_NIL_WITH_DECREMENT( UIGraphicsEndImageContext(); ); | ||
} | ||
|
||
CGContextRef currentContext = UIGraphicsGetCurrentContext(); | ||
UIImage *image = nil; | ||
|
||
// 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 (currentContext && _willDisplayNodeContentWithRenderingContext) { | ||
_willDisplayNodeContentWithRenderingContext(currentContext); | ||
} | ||
|
||
if (flags.implementsInstanceDrawRect) { | ||
[self drawRect:bounds withParameters:drawParameters isCancelled:isCancelledBlock isRasterizing:rasterizing]; | ||
} else { | ||
[[self class] drawRect:bounds withParameters:drawParameters isCancelled:isCancelledBlock isRasterizing:rasterizing]; | ||
// Decide if we use a class or instance method to draw or display. | ||
id object = usesInstanceMethodDisplay ? self : [self class]; | ||
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. This secretly makes me happy, which is probably bad. |
||
|
||
if (usesImageDisplay) { // If we are using a display method, we'll get an image back directly. | ||
image = [object 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]; | ||
} | ||
|
||
if (currentContext && _didDisplayNodeContentWithRenderingContext) { | ||
_didDisplayNodeContentWithRenderingContext(currentContext); | ||
} | ||
|
||
if (isCancelledBlock()) { | ||
if (!rasterizing) { | ||
UIGraphicsEndImageContext(); | ||
} | ||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
return nil; | ||
} | ||
|
||
UIImage *image = nil; | ||
if (!rasterizing) { | ||
|
||
if (shouldCreateGraphicsContext) { | ||
CHECK_CANCELLED_AND_RETURN_NIL_WITH_DECREMENT( UIGraphicsEndImageContext(); ); | ||
image = UIGraphicsGetImageFromCurrentImageContext(); | ||
UIGraphicsEndImageContext(); | ||
} | ||
|
||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing); | ||
|
||
ASDN_DELAY_FOR_DISPLAY(); | ||
DISPLAY_COUNT_DECREMENT(); | ||
return image; | ||
}; | ||
|
||
} | ||
|
||
return [displayBlock copy]; | ||
|
@@ -356,7 +351,7 @@ - (void)displayAsyncLayer:(_ASDisplayLayer *)asyncLayer asynchronously:(BOOL)asy | |
ASDisplayNodeCAssertMainThread(); | ||
if (!canceled && !isCancelledBlock()) { | ||
UIImage *image = (UIImage *)value; | ||
BOOL stretchable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero); | ||
BOOL stretchable = (NO == UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero)); | ||
if (stretchable) { | ||
ASDisplayNodeSetupLayerContentsWithResizableImage(_layer, image); | ||
} else { | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 was able to entirely eliminate this third condition, and thus use just one else {