mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 11:50:56 +00:00
Adds support for using UIGraphicsImageRenderer in ASTextNode. (#1384)
* Adds support for using UIGraphicsImageRenderer in ASTextNode. In many cases this reduces the backing store of text nodes by 1/2. * Guard for UIGraphicsRenderer availability. * Comma
This commit is contained in:
parent
872e89b772
commit
9b80eabd8f
@ -26,7 +26,8 @@
|
|||||||
"exp_skip_a11y_wait",
|
"exp_skip_a11y_wait",
|
||||||
"exp_new_default_cell_layout_mode",
|
"exp_new_default_cell_layout_mode",
|
||||||
"exp_dispatch_apply",
|
"exp_dispatch_apply",
|
||||||
"exp_image_downloader_priority"
|
"exp_image_downloader_priority",
|
||||||
|
"exp_text_drawing"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) {
|
|||||||
ASExperimentalNewDefaultCellLayoutMode = 1 << 11, // exp_new_default_cell_layout_mode
|
ASExperimentalNewDefaultCellLayoutMode = 1 << 11, // exp_new_default_cell_layout_mode
|
||||||
ASExperimentalDispatchApply = 1 << 12, // exp_dispatch_apply
|
ASExperimentalDispatchApply = 1 << 12, // exp_dispatch_apply
|
||||||
ASExperimentalImageDownloaderPriority = 1 << 13, // exp_image_downloader_priority
|
ASExperimentalImageDownloaderPriority = 1 << 13, // exp_image_downloader_priority
|
||||||
|
ASExperimentalTextDrawing = 1 << 14, // exp_text_drawing
|
||||||
ASExperimentalFeatureAll = 0xFFFFFFFF
|
ASExperimentalFeatureAll = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,8 @@ NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags
|
|||||||
@"exp_skip_a11y_wait",
|
@"exp_skip_a11y_wait",
|
||||||
@"exp_new_default_cell_layout_mode",
|
@"exp_new_default_cell_layout_mode",
|
||||||
@"exp_dispatch_apply",
|
@"exp_dispatch_apply",
|
||||||
@"exp_image_downloader_priority"]));
|
@"exp_image_downloader_priority",
|
||||||
|
@"exp_text_drawing"]));
|
||||||
if (flags == ASExperimentalFeatureAll) {
|
if (flags == ASExperimentalFeatureAll) {
|
||||||
return allNames;
|
return allNames;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
#import <mutex>
|
#import <mutex>
|
||||||
#import <tgmath.h>
|
#import <tgmath.h>
|
||||||
|
|
||||||
|
#import <AsyncDisplayKit/ASAvailability.h>
|
||||||
#import <AsyncDisplayKit/_ASDisplayLayer.h>
|
#import <AsyncDisplayKit/_ASDisplayLayer.h>
|
||||||
#import <AsyncDisplayKit/ASDisplayNode+FrameworkPrivate.h>
|
#import <AsyncDisplayKit/ASDisplayNode+FrameworkPrivate.h>
|
||||||
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
||||||
@ -140,6 +141,9 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes,
|
|||||||
ASTextKitAttributes _rendererAttributes;
|
ASTextKitAttributes _rendererAttributes;
|
||||||
UIColor *_backgroundColor;
|
UIColor *_backgroundColor;
|
||||||
UIEdgeInsets _textContainerInsets;
|
UIEdgeInsets _textContainerInsets;
|
||||||
|
CGFloat _contentScale;
|
||||||
|
BOOL _opaque;
|
||||||
|
CGRect _bounds;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -148,12 +152,18 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes,
|
|||||||
- (instancetype)initWithRendererAttributes:(ASTextKitAttributes)rendererAttributes
|
- (instancetype)initWithRendererAttributes:(ASTextKitAttributes)rendererAttributes
|
||||||
backgroundColor:(/*nullable*/ UIColor *)backgroundColor
|
backgroundColor:(/*nullable*/ UIColor *)backgroundColor
|
||||||
textContainerInsets:(UIEdgeInsets)textContainerInsets
|
textContainerInsets:(UIEdgeInsets)textContainerInsets
|
||||||
|
contentScale:(CGFloat)contentScale
|
||||||
|
opaque:(BOOL)opaque
|
||||||
|
bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_rendererAttributes = rendererAttributes;
|
_rendererAttributes = rendererAttributes;
|
||||||
_backgroundColor = backgroundColor;
|
_backgroundColor = backgroundColor;
|
||||||
_textContainerInsets = textContainerInsets;
|
_textContainerInsets = textContainerInsets;
|
||||||
|
_contentScale = contentScale;
|
||||||
|
_opaque = opaque;
|
||||||
|
_bounds = bounds;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -526,15 +536,52 @@ static NSArray *DefaultLinkAttributeNames() {
|
|||||||
|
|
||||||
return [[ASTextNodeDrawParameter alloc] initWithRendererAttributes:[self _locked_rendererAttributes]
|
return [[ASTextNodeDrawParameter alloc] initWithRendererAttributes:[self _locked_rendererAttributes]
|
||||||
backgroundColor:self.backgroundColor
|
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;
|
ASTextNodeDrawParameter *drawParameter = (ASTextNodeDrawParameter *)parameters;
|
||||||
UIColor *backgroundColor = (isRasterizing || drawParameter == nil) ? nil : drawParameter->_backgroundColor;
|
|
||||||
|
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;
|
UIEdgeInsets textContainerInsets = drawParameter ? drawParameter->_textContainerInsets : UIEdgeInsetsZero;
|
||||||
ASTextKitRenderer *renderer = [drawParameter rendererForBounds:bounds];
|
ASTextKitRenderer *renderer = [drawParameter rendererForBounds:drawParameter->_bounds];
|
||||||
|
BOOL renderedWithGraphicsRenderer = NO;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!renderedWithGraphicsRenderer) {
|
||||||
|
UIGraphicsBeginImageContextWithOptions(CGSizeMake(drawParameter->_bounds.size.width, drawParameter->_bounds.size.height), drawParameter->_opaque, drawParameter->_contentScale);
|
||||||
|
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
ASDisplayNodeAssert(context, @"This is no good without a context.");
|
ASDisplayNodeAssert(context, @"This is no good without a context.");
|
||||||
@ -549,8 +596,14 @@ static NSArray *DefaultLinkAttributeNames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
[renderer drawInContext:context bounds:bounds];
|
[renderer drawInContext:context bounds:drawParameter->_bounds];
|
||||||
CGContextRestoreGState(context);
|
CGContextRestoreGState(context);
|
||||||
|
|
||||||
|
result = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
|
UIGraphicsEndImageContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Attributes
|
#pragma mark - Attributes
|
||||||
|
|||||||
@ -112,7 +112,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@summary Delegate override to provide new layer contents as a UIImage.
|
@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 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.
|
@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
|
+ (UIImage *)displayWithParameters:(nullable id<NSObject>)parameters
|
||||||
isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock;
|
isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock;
|
||||||
|
|||||||
@ -31,7 +31,8 @@ static ASExperimentalFeatures features[] = {
|
|||||||
ASExperimentalSkipAccessibilityWait,
|
ASExperimentalSkipAccessibilityWait,
|
||||||
ASExperimentalNewDefaultCellLayoutMode,
|
ASExperimentalNewDefaultCellLayoutMode,
|
||||||
ASExperimentalDispatchApply,
|
ASExperimentalDispatchApply,
|
||||||
ASExperimentalImageDownloaderPriority
|
ASExperimentalImageDownloaderPriority,
|
||||||
|
ASExperimentalTextDrawing
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface ASConfigurationTests : ASTestCase <ASConfigurationDelegate>
|
@interface ASConfigurationTests : ASTestCase <ASConfigurationDelegate>
|
||||||
@ -57,7 +58,8 @@ static ASExperimentalFeatures features[] = {
|
|||||||
@"exp_skip_a11y_wait",
|
@"exp_skip_a11y_wait",
|
||||||
@"exp_new_default_cell_layout_mode",
|
@"exp_new_default_cell_layout_mode",
|
||||||
@"exp_dispatch_apply",
|
@"exp_dispatch_apply",
|
||||||
@"exp_image_downloader_priority"
|
@"exp_image_downloader_priority",
|
||||||
|
@"exp_text_drawing"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user