Share a singleton shadower for all cases when shadow isn't drawn, fix issues (#2511)

This commit is contained in:
Adlai Holler
2016-10-30 15:34:29 -07:00
committed by appleguy
parent 611894329a
commit 3eb7a307fa
8 changed files with 54 additions and 35 deletions

View File

@@ -102,10 +102,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
if (self = [super init]) { if (self = [super init]) {
// Load default values from superclass. // Load default values from superclass.
_shadowOffset = [super shadowOffset]; _shadowOffset = [super shadowOffset];
CGColorRef superColor = [super shadowColor]; _shadowColor = CGColorRetain([super shadowColor]);
if (superColor != NULL) {
_shadowColor = CGColorRetain(superColor);
}
_shadowOpacity = [super shadowOpacity]; _shadowOpacity = [super shadowOpacity];
_shadowRadius = [super shadowRadius]; _shadowRadius = [super shadowRadius];
@@ -140,10 +137,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (void)dealloc - (void)dealloc
{ {
if (_shadowColor != NULL) { CGColorRelease(_shadowColor);
CGColorRelease(_shadowColor);
}
[self _invalidateRenderer]; [self _invalidateRenderer];
if (_longPressGestureRecognizer) { if (_longPressGestureRecognizer) {
@@ -548,9 +543,6 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
CGContextTranslateCTM(context, _textContainerInset.left, _textContainerInset.top); CGContextTranslateCTM(context, _textContainerInset.left, _textContainerInset.top);
ASTextKitRenderer *renderer = [self _rendererWithBounds:drawParameterBounds]; ASTextKitRenderer *renderer = [self _rendererWithBounds:drawParameterBounds];
UIEdgeInsets shadowPadding = [self shadowPaddingWithRenderer:renderer];
CGPoint boundsOrigin = drawParameterBounds.origin;
CGPoint textOrigin = CGPointMake(boundsOrigin.x - shadowPadding.left, boundsOrigin.y - shadowPadding.top);
// Fill background // Fill background
if (backgroundColor != nil) { if (backgroundColor != nil) {
@@ -558,12 +550,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy); UIRectFillUsingBlendMode(CGContextGetClipBoundingBox(context), kCGBlendModeCopy);
} }
// Draw shadow
[renderer.shadower setShadowInContext:context];
// Draw text // Draw text
bounds.origin = textOrigin; [renderer drawInContext:context bounds:drawParameterBounds];
[renderer drawInContext:context bounds:bounds];
CGContextRestoreGState(context); CGContextRestoreGState(context);
} }
@@ -1133,14 +1121,9 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
{ {
ASDN::MutexLocker l(__instanceLock__); ASDN::MutexLocker l(__instanceLock__);
if (_shadowColor != shadowColor) { if (_shadowColor != shadowColor && CGColorEqualToColor(shadowColor, _shadowColor) == NO) {
if (shadowColor != NULL) { CGColorRelease(_shadowColor);
CGColorRetain(shadowColor); _shadowColor = CGColorRetain(shadowColor);
}
if (_shadowColor != NULL) {
CGColorRelease(_shadowColor);
}
_shadowColor = shadowColor;
_cachedShadowUIColor = [UIColor colorWithCGColor:shadowColor]; _cachedShadowUIColor = [UIColor colorWithCGColor:shadowColor];
[self _invalidateRenderer]; [self _invalidateRenderer];
[self setNeedsDisplay]; [self setNeedsDisplay];

View File

@@ -59,7 +59,7 @@ struct ASTextKitAttributes {
/** /**
An array of UIBezierPath objects representing the exclusion paths inside the receiver's bounding rectangle. Default value: nil. An array of UIBezierPath objects representing the exclusion paths inside the receiver's bounding rectangle. Default value: nil.
*/ */
NSArray *exclusionPaths; NSArray<UIBezierPath *> *exclusionPaths;
/** /**
The shadow offset for any shadows applied to the text. The coordinate space for this is the same as UIKit, so a The shadow offset for any shadows applied to the text. The coordinate space for this is the same as UIKit, so a
positive width means towards the right, and a positive height means towards the bottom. positive width means towards the right, and a positive height means towards the bottom.

View File

@@ -68,10 +68,10 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
{ {
if (!_shadower) { if (!_shadower) {
ASTextKitAttributes attributes = _attributes; ASTextKitAttributes attributes = _attributes;
_shadower = [[ASTextKitShadower alloc] initWithShadowOffset:attributes.shadowOffset _shadower = [ASTextKitShadower shadowerWithShadowOffset:attributes.shadowOffset
shadowColor:attributes.shadowColor shadowColor:attributes.shadowColor
shadowOpacity:attributes.shadowOpacity shadowOpacity:attributes.shadowOpacity
shadowRadius:attributes.shadowRadius]; shadowRadius:attributes.shadowRadius];
} }
return _shadower; return _shadower;
} }

View File

@@ -15,10 +15,10 @@
*/ */
@interface ASTextKitShadower : NSObject @interface ASTextKitShadower : NSObject
- (instancetype)initWithShadowOffset:(CGSize)shadowOffset + (ASTextKitShadower *)shadowerWithShadowOffset:(CGSize)shadowOffset
shadowColor:(UIColor *)shadowColor shadowColor:(UIColor *)shadowColor
shadowOpacity:(CGFloat)shadowOpacity shadowOpacity:(CGFloat)shadowOpacity
shadowRadius:(CGFloat)shadowRadius; shadowRadius:(CGFloat)shadowRadius;
/** /**
* @abstract The offset from the top-left corner at which the shadow starts. * @abstract The offset from the top-left corner at which the shadow starts.

View File

@@ -14,7 +14,9 @@
static inline CGSize _insetSize(CGSize size, UIEdgeInsets insets) static inline CGSize _insetSize(CGSize size, UIEdgeInsets insets)
{ {
return UIEdgeInsetsInsetRect({.size = size}, insets).size; size.width -= (insets.left + insets.right);
size.height -= (insets.top + insets.bottom);
return size;
} }
static inline UIEdgeInsets _invertInsets(UIEdgeInsets insets) static inline UIEdgeInsets _invertInsets(UIEdgeInsets insets)
@@ -31,6 +33,28 @@ static inline UIEdgeInsets _invertInsets(UIEdgeInsets insets)
UIEdgeInsets _calculatedShadowPadding; UIEdgeInsets _calculatedShadowPadding;
} }
+ (ASTextKitShadower *)shadowerWithShadowOffset:(CGSize)shadowOffset
shadowColor:(UIColor *)shadowColor
shadowOpacity:(CGFloat)shadowOpacity
shadowRadius:(CGFloat)shadowRadius
{
/**
* For all cases where no shadow is drawn, we share this singleton shadower to save resources.
*/
static dispatch_once_t onceToken;
static ASTextKitShadower *sharedNonShadower;
dispatch_once(&onceToken, ^{
sharedNonShadower = [[ASTextKitShadower alloc] initWithShadowOffset:CGSizeZero shadowColor:nil shadowOpacity:0 shadowRadius:0];
});
BOOL hasShadow = shadowOpacity > 0 && (shadowRadius > 0 || CGSizeEqualToSize(shadowOffset, CGSizeZero) == NO) && CGColorGetAlpha(shadowColor.CGColor) > 0;
if (hasShadow == NO) {
return sharedNonShadower;
} else {
return [[ASTextKitShadower alloc] initWithShadowOffset:shadowOffset shadowColor:shadowColor shadowOpacity:shadowOpacity shadowRadius:shadowRadius];
}
}
- (instancetype)initWithShadowOffset:(CGSize)shadowOffset - (instancetype)initWithShadowOffset:(CGSize)shadowOffset
shadowColor:(UIColor *)shadowColor shadowColor:(UIColor *)shadowColor
shadowOpacity:(CGFloat)shadowOpacity shadowOpacity:(CGFloat)shadowOpacity
@@ -52,7 +76,7 @@ static inline UIEdgeInsets _invertInsets(UIEdgeInsets insets)
*/ */
- (BOOL)_shouldDrawShadow - (BOOL)_shouldDrawShadow
{ {
return _shadowOpacity != 0.0 && _shadowColor != nil && (_shadowRadius != 0 || !CGSizeEqualToSize(_shadowOffset, CGSizeZero)); return _shadowOpacity != 0.0 && (_shadowRadius != 0 || !CGSizeEqualToSize(_shadowOffset, CGSizeZero)) && CGColorGetAlpha(_shadowColor.CGColor) > 0;
} }
- (void)setShadowInContext:(CGContextRef)context - (void)setShadowInContext:(CGContextRef)context

View File

@@ -92,4 +92,16 @@
ASSnapshotVerifyNode(textNode, nil); ASSnapshotVerifyNode(textNode, nil);
} }
- (void)testShadowing
{
ASTextNode *textNode = [[ASTextNode alloc] init];
textNode.attributedText = [[NSAttributedString alloc] initWithString:@"Quality is Important"];
textNode.shadowColor = [UIColor blackColor].CGColor;
textNode.shadowOpacity = 0.3;
textNode.shadowRadius = 3;
textNode.shadowOffset = CGSizeMake(0, 1);
[textNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))];
ASSnapshotVerifyNode(textNode, nil);
}
@end @end

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB