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

Adds support for using UIGraphicsImageRenderer in ASTextNode. #1384

Merged
merged 4 commits into from
Mar 9, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion Schemas/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"exp_disable_a11y_cache",
"exp_skip_a11y_wait",
"exp_new_default_cell_layout_mode",
"exp_dispatch_apply"
"exp_dispatch_apply",
"exp_text_drawing"
]
}
}
Expand Down
1 change: 1 addition & 0 deletions Source/ASExperimentalFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) {
ASExperimentalSkipAccessibilityWait = 1 << 10, // exp_skip_a11y_wait
ASExperimentalNewDefaultCellLayoutMode = 1 << 11, // exp_new_default_cell_layout_mode
ASExperimentalDispatchApply = 1 << 12, // exp_dispatch_apply
ASExperimentalTextDrawing = 1 << 13, // exp_text_drawing
ASExperimentalFeatureAll = 0xFFFFFFFF
};

Expand Down
3 changes: 2 additions & 1 deletion Source/ASExperimentalFeatures.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
@"exp_disable_a11y_cache",
@"exp_skip_a11y_wait",
@"exp_new_default_cell_layout_mode",
@"exp_dispatch_apply"]));
@"exp_dispatch_apply",
@"exp_text_drawing"]));

if (flags == ASExperimentalFeatureAll) {
return allNames;
Expand Down
87 changes: 70 additions & 17 deletions Source/ASTextNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#import <mutex>
#import <tgmath.h>

#import <AsyncDisplayKit/ASAvailability.h>
#import <AsyncDisplayKit/_ASDisplayLayer.h>
#import <AsyncDisplayKit/ASDisplayNode+FrameworkPrivate.h>
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
Expand Down Expand Up @@ -140,6 +141,9 @@ @interface ASTextNodeDrawParameter : NSObject {
ASTextKitAttributes _rendererAttributes;
UIColor *_backgroundColor;
UIEdgeInsets _textContainerInsets;
CGFloat _contentScale;
BOOL _opaque;
CGRect _bounds;
}
@end

Expand All @@ -148,12 +152,18 @@ @implementation ASTextNodeDrawParameter
- (instancetype)initWithRendererAttributes:(ASTextKitAttributes)rendererAttributes
backgroundColor:(/*nullable*/ UIColor *)backgroundColor
textContainerInsets:(UIEdgeInsets)textContainerInsets
contentScale:(CGFloat)contentScale
opaque:(BOOL)opaque
bounds:(CGRect)bounds
{
self = [super init];
if (self != nil) {
_rendererAttributes = rendererAttributes;
_backgroundColor = backgroundColor;
_textContainerInsets = textContainerInsets;
_contentScale = contentScale;
_opaque = opaque;
_bounds = bounds;
}
return self;
}
Expand Down Expand Up @@ -526,31 +536,74 @@ - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer

return [[ASTextNodeDrawParameter alloc] initWithRendererAttributes:[self _locked_rendererAttributes]
backgroundColor:self.backgroundColor
textContainerInsets:_textContainerInset];
textContainerInsets:_textContainerInset
contentScale:_contentsScaleForDisplay
opaque:self.isOpaque
bounds:[self threadSafeBounds]];
}

+ (void)drawRect:(CGRect)bounds withParameters:(id)parameters isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing
+ (UIImage *)displayWithParameters:(id<NSObject>)parameters isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelled
{
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, textContainerInsets.left, textContainerInsets.top);
if (drawParameter->_bounds.size.width <= 0 || drawParameter->_bounds.size.height <= 0) {
return nil;
}

UIImage *result = nil;
UIColor *backgroundColor = drawParameter->_backgroundColor;
UIEdgeInsets textContainerInsets = drawParameter ? drawParameter->_textContainerInsets : UIEdgeInsetsZero;
ASTextKitRenderer *renderer = [drawParameter rendererForBounds:drawParameter->_bounds];
BOOL renderedWithGraphicsRenderer = NO;

// Fill background
if (backgroundColor != nil) {
[backgroundColor setFill];
UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy);
if (AS_AVAILABLE_IOS_TVOS(10, 10)) {
if (ASActivateExperimentalFeature(ASExperimentalTextDrawing)) {
renderedWithGraphicsRenderer = YES;
UIGraphicsImageRenderer *graphicsRenderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(drawParameter->_bounds.size.width, drawParameter->_bounds.size.height)];
result = [graphicsRenderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
CGContextRef context = rendererContext.CGContext;
ASDisplayNodeAssert(context, @"This is no good without a context.");

CGContextSaveGState(context);
CGContextTranslateCTM(context, textContainerInsets.left, textContainerInsets.top);

// Fill background
if (backgroundColor != nil) {
[backgroundColor setFill];
UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy);
}

// Draw text
[renderer drawInContext:context bounds:drawParameter->_bounds];
CGContextRestoreGState(context);
}];
}
}

// Draw text
[renderer drawInContext:context bounds:bounds];
CGContextRestoreGState(context);
if (!renderedWithGraphicsRenderer) {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(drawParameter->_bounds.size.width, drawParameter->_bounds.size.height), drawParameter->_opaque, drawParameter->_contentScale);

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

CGContextSaveGState(context);
CGContextTranslateCTM(context, textContainerInsets.left, textContainerInsets.top);

// Fill background
if (backgroundColor != nil) {
[backgroundColor setFill];
UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy);
}

// Draw text
[renderer drawInContext:context bounds:drawParameter->_bounds];
CGContextRestoreGState(context);

result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

return result;
}

#pragma mark - Attributes
Expand Down
2 changes: 1 addition & 1 deletion Source/Details/_ASDisplayLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ NS_ASSUME_NONNULL_BEGIN
@summary Delegate override to provide new layer contents as a UIImage.
@param parameters An object describing all of the properties you need to draw. Return this from -drawParametersForAsyncLayer:
@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.
@return A UIImage with contents that are ready to display on the main thread. Make sure that the image is already decoded before returning it here.
@return A UIImage (backed by a CGImage) with contents that are ready to display on the main thread. Make sure that the image is already decoded before returning it here.
*/
+ (UIImage *)displayWithParameters:(nullable id<NSObject>)parameters
isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock;
Expand Down
6 changes: 4 additions & 2 deletions Tests/ASConfigurationTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
ASExperimentalDisableAccessibilityCache,
ASExperimentalSkipAccessibilityWait,
ASExperimentalNewDefaultCellLayoutMode,
ASExperimentalDispatchApply
ASExperimentalDispatchApply,
ASExperimentalTextDrawing
};

@interface ASConfigurationTests : ASTestCase <ASConfigurationDelegate>
Expand All @@ -55,7 +56,8 @@ + (NSArray *)names {
@"exp_disable_a11y_cache",
@"exp_skip_a11y_wait",
@"exp_new_default_cell_layout_mode",
@"exp_dispatch_apply"
@"exp_dispatch_apply",
@"exp_text_drawing"
];
}

Expand Down