mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-20 21:29:00 +00:00
Cleanup ASTextNode and add locking
For now we use a big recursive lock. This needs to be revisited as we revisit the whole ASDK locking strategy.
This commit is contained in:
parent
22fa715682
commit
3d72a6b7e5
@ -11,22 +11,19 @@
|
||||
#import "ASTextNode.h"
|
||||
#import "ASTextNode+Beta.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#import <AsyncDisplayKit/_ASDisplayLayer.h>
|
||||
#import <AsyncDisplayKit/ASAssert.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeInternal.h>
|
||||
#import <AsyncDisplayKit/ASHighlightOverlayLayer.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||
|
||||
#import "ASTextKitCoreTextAdditions.h"
|
||||
#import "ASTextKitComponents.h"
|
||||
#import "ASTextKitFontSizeAdjuster.h"
|
||||
#import "ASTextKitRenderer.h"
|
||||
#import "ASTextKitRenderer+Positioning.h"
|
||||
#import "ASTextKitShadower.h"
|
||||
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASEqualityHelpers.h"
|
||||
#import "ASLayout.h"
|
||||
|
||||
static const NSTimeInterval ASTextNodeHighlightFadeOutDuration = 0.15;
|
||||
@ -38,15 +35,13 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
||||
@interface ASTextNodeDrawParameters : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) CGRect bounds;
|
||||
|
||||
@property (nonatomic, strong, readonly) UIColor *backgroundColor;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASTextNodeDrawParameters
|
||||
|
||||
- (instancetype)initWithBounds:(CGRect)bounds
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
- (instancetype)initWithBounds:(CGRect)bounds backgroundColor:(UIColor *)backgroundColor
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_bounds = bounds;
|
||||
@ -76,7 +71,7 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
||||
NSRange _highlightRange;
|
||||
ASHighlightOverlayLayer *_activeHighlightLayer;
|
||||
|
||||
ASDN::Mutex _rendererLock;
|
||||
std::recursive_mutex _textLock;
|
||||
|
||||
CGSize _constrainedSize;
|
||||
|
||||
@ -160,6 +155,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
NSString *plainString = [[_attributedText string] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
||||
NSString *truncationString = [_composedTruncationText string];
|
||||
if (plainString.length > 50)
|
||||
@ -227,7 +224,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (ASTextKitRenderer *)_rendererWithBounds:(CGRect)bounds
|
||||
{
|
||||
ASDN::MutexLocker l(_rendererLock);
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_renderer == nil) {
|
||||
CGSize constrainedSize = _constrainedSize.width != -INFINITY ? _constrainedSize : bounds.size;
|
||||
_renderer = [[ASTextKitRenderer alloc] initWithTextKitAttributes:[self _rendererAttributes]
|
||||
@ -250,9 +248,28 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
};
|
||||
}
|
||||
|
||||
- (void)_invalidateRendererIfNeeded
|
||||
{
|
||||
[self _invalidateRendererIfNeededForBoundsSize:self.threadSafeBounds.size];
|
||||
}
|
||||
|
||||
- (void)_invalidateRendererIfNeededForBoundsSize:(CGSize)boundsSize
|
||||
{
|
||||
if ([self _needInvalidateRendererForBoundsSize:boundsSize]) {
|
||||
// Our bounds of frame have changed to a size that is not identical to our constraining size,
|
||||
// so our previous layout information is invalid, and TextKit may draw at the
|
||||
// incorrect origin.
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
_constrainedSize = CGSizeMake(-INFINITY, -INFINITY);
|
||||
}
|
||||
[self _invalidateRenderer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_invalidateRenderer
|
||||
{
|
||||
ASDN::MutexLocker l(_rendererLock);
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_renderer) {
|
||||
// Destruction of the layout managers/containers/text storage is quite
|
||||
@ -267,27 +284,13 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_invalidateRendererIfNeeded
|
||||
{
|
||||
[self _invalidateRendererIfNeededForBoundsSize:self.threadSafeBounds.size];
|
||||
}
|
||||
|
||||
- (void)_invalidateRendererIfNeededForBoundsSize:(CGSize)boundsSize
|
||||
{
|
||||
if ([self _needInvalidateRendererForBoundsSize:boundsSize]) {
|
||||
// Our bounds of frame have changed to a size that is not identical to our constraining size,
|
||||
// so our previous layout information is invalid, and TextKit may draw at the
|
||||
// incorrect origin.
|
||||
_constrainedSize = CGSizeMake(-INFINITY, -INFINITY);
|
||||
[self _invalidateRenderer];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Layout and Sizing
|
||||
|
||||
- (BOOL)_needInvalidateRendererForBoundsSize:(CGSize)boundsSize
|
||||
{
|
||||
if (!_renderer) {
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_renderer == nil) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -322,6 +325,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
[super calculatedLayoutDidChange];
|
||||
|
||||
ASLayout *layout = self.calculatedLayout;
|
||||
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
if (layout != nil) {
|
||||
_constrainedSize = layout.size;
|
||||
_renderer.constrainedSize = layout.size;
|
||||
@ -333,6 +338,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
ASDisplayNodeAssert(constrainedSize.width >= 0, @"Constrained width for text (%f) is too narrow", constrainedSize.width);
|
||||
ASDisplayNodeAssert(constrainedSize.height >= 0, @"Constrained height for text (%f) is too short", constrainedSize.height);
|
||||
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
_constrainedSize = constrainedSize;
|
||||
|
||||
// Instead of invalidating the renderer, in case this is a new call with a different constrained size,
|
||||
@ -341,7 +348,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
[self setNeedsDisplay];
|
||||
|
||||
CGSize size = [[self _renderer] size];
|
||||
CGSize size = [self _renderer].size;
|
||||
if (_attributedText.length > 0) {
|
||||
CGFloat screenScale = ASScreenScale();
|
||||
self.ascender = round([[_attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
|
||||
@ -359,6 +366,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)setAttributedText:(NSAttributedString *)attributedText
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (attributedText == nil) {
|
||||
attributedText = [[NSAttributedString alloc] initWithString:@"" attributes:nil];
|
||||
}
|
||||
@ -388,16 +397,18 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
[self setNeedsDisplay];
|
||||
|
||||
self.accessibilityLabel = _attributedText.string;
|
||||
|
||||
// We're an accessibility element by default if there is a string.
|
||||
self.isAccessibilityElement = _attributedText.length != 0;
|
||||
// Accessiblity
|
||||
self.accessibilityLabel = _attributedText.string;
|
||||
self.isAccessibilityElement = (_attributedText.length != 0); // We're an accessibility element by default if there is a string.
|
||||
}
|
||||
|
||||
#pragma mark - Text Layout
|
||||
|
||||
- (void)setExclusionPaths:(NSArray *)exclusionPaths
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (ASObjectIsEqual(exclusionPaths, _exclusionPaths)) {
|
||||
return;
|
||||
}
|
||||
@ -410,6 +421,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (NSArray *)exclusionPaths
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return _exclusionPaths;
|
||||
}
|
||||
|
||||
@ -417,6 +430,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)drawRect:(CGRect)bounds withParameters:(ASTextNodeDrawParameters *)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
ASDisplayNodeAssert(context, @"This is no good without a context.");
|
||||
|
||||
@ -437,7 +452,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
}
|
||||
|
||||
// Draw shadow
|
||||
[[renderer shadower] setShadowInContext:context];
|
||||
[renderer.shadower setShadowInContext:context];
|
||||
|
||||
// Draw text
|
||||
bounds.origin = textOrigin;
|
||||
@ -470,6 +485,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
inAdditionalTruncationMessage:(out BOOL *)inAdditionalTruncationMessageOut
|
||||
forHighlighting:(BOOL)highlighting
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
ASTextKitRenderer *renderer = [self _renderer];
|
||||
NSRange visibleRange = renderer.firstVisibleRange;
|
||||
NSAttributedString *attributedString = _attributedText;
|
||||
@ -562,6 +579,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
if (gestureRecognizer == _longPressGestureRecognizer) {
|
||||
// Don't allow long press on truncation message
|
||||
if ([self _pendingTruncationTap]) {
|
||||
@ -593,6 +612,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (NSRange)highlightRange
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
return _highlightRange;
|
||||
}
|
||||
|
||||
@ -603,6 +624,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)setHighlightRange:(NSRange)highlightRange animated:(BOOL)animated
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
[self _setHighlightRange:highlightRange forAttributeName:nil value:nil animated:animated];
|
||||
}
|
||||
|
||||
@ -672,7 +695,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
NSMutableArray *converted = [NSMutableArray arrayWithCapacity:highlightRects.count];
|
||||
for (NSValue *rectValue in highlightRects) {
|
||||
UIEdgeInsets shadowPadding = _renderer.shadower.shadowPadding;
|
||||
CGRect rendererRect = [[self class] _adjustRendererRect:rectValue.CGRectValue forShadowPadding:shadowPadding];
|
||||
CGRect rendererRect = ASTextNodeAdjustRenderRectForShadowPadding(rectValue.CGRectValue, shadowPadding);
|
||||
CGRect highlightedRect = [self.layer convertRect:rendererRect toLayer:highlightTargetLayer];
|
||||
|
||||
// We set our overlay layer's frame to the bounds of the highlight target layer.
|
||||
@ -709,6 +732,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)_clearHighlightIfNecessary
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
if ([self _pendingLinkTap] || [self _pendingTruncationTap]) {
|
||||
[self setHighlightRange:NSMakeRange(0, 0) animated:YES];
|
||||
}
|
||||
@ -726,29 +751,12 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
#pragma mark - Text rects
|
||||
|
||||
+ (CGRect)_adjustRendererRect:(CGRect)rendererRect forShadowPadding:(UIEdgeInsets)shadowPadding
|
||||
{
|
||||
static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UIEdgeInsets shadowPadding) {
|
||||
rendererRect.origin.x -= shadowPadding.left;
|
||||
rendererRect.origin.y -= shadowPadding.top;
|
||||
return rendererRect;
|
||||
}
|
||||
|
||||
- (NSArray *)_rectsForTextRange:(NSRange)textRange measureOption:(ASTextKitRendererMeasureOption)measureOption
|
||||
{
|
||||
NSArray *rects = [[self _renderer] rectsForTextRange:textRange measureOption:measureOption];
|
||||
NSMutableArray *adjustedRects = [NSMutableArray array];
|
||||
|
||||
for (NSValue *rectValue in rects) {
|
||||
CGRect rect = [rectValue CGRectValue];
|
||||
rect = [self.class _adjustRendererRect:rect forShadowPadding:self.shadowPadding];
|
||||
|
||||
NSValue *adjustedRectValue = [NSValue valueWithCGRect:rect];
|
||||
[adjustedRects addObject:adjustedRectValue];
|
||||
}
|
||||
|
||||
return adjustedRects;
|
||||
}
|
||||
|
||||
- (NSArray *)rectsForTextRange:(NSRange)textRange
|
||||
{
|
||||
return [self _rectsForTextRange:textRange measureOption:ASTextKitRendererMeasureOptionCapHeight];
|
||||
@ -759,22 +767,46 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
return [self _rectsForTextRange:textRange measureOption:ASTextKitRendererMeasureOptionBlock];
|
||||
}
|
||||
|
||||
- (NSArray *)_rectsForTextRange:(NSRange)textRange measureOption:(ASTextKitRendererMeasureOption)measureOption
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
NSArray *rects = [[self _renderer] rectsForTextRange:textRange measureOption:measureOption];
|
||||
NSMutableArray *adjustedRects = [NSMutableArray array];
|
||||
|
||||
for (NSValue *rectValue in rects) {
|
||||
CGRect rect = [rectValue CGRectValue];
|
||||
rect = ASTextNodeAdjustRenderRectForShadowPadding(rect, self.shadowPadding);
|
||||
|
||||
NSValue *adjustedRectValue = [NSValue valueWithCGRect:rect];
|
||||
[adjustedRects addObject:adjustedRectValue];
|
||||
}
|
||||
|
||||
return adjustedRects;
|
||||
}
|
||||
|
||||
- (CGRect)trailingRect
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
CGRect rect = [[self _renderer] trailingRect];
|
||||
return [self.class _adjustRendererRect:rect forShadowPadding:self.shadowPadding];
|
||||
return ASTextNodeAdjustRenderRectForShadowPadding(rect, self.shadowPadding);
|
||||
}
|
||||
|
||||
- (CGRect)frameForTextRange:(NSRange)textRange
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
CGRect frame = [[self _renderer] frameForTextRange:textRange];
|
||||
return [self.class _adjustRendererRect:frame forShadowPadding:self.shadowPadding];
|
||||
return ASTextNodeAdjustRenderRectForShadowPadding(frame, self.shadowPadding);
|
||||
}
|
||||
|
||||
#pragma mark - Placeholders
|
||||
|
||||
- (void)setPlaceholderColor:(UIColor *)placeholderColor
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
_placeholderColor = placeholderColor;
|
||||
|
||||
// prevent placeholders if we don't have a color
|
||||
@ -790,6 +822,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
return nil;
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
UIGraphicsBeginImageContext(size);
|
||||
[self.placeholderColor setFill];
|
||||
|
||||
@ -816,8 +850,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
#pragma mark - Touch Handling
|
||||
|
||||
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
|
||||
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
if (!_passthroughNonlinkTouches) {
|
||||
return [super pointInside:point withEvent:event];
|
||||
}
|
||||
@ -846,9 +882,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
|
||||
CGPoint point = [[touches anyObject] locationInView:self.view];
|
||||
|
||||
@ -878,6 +913,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[super touchesCancelled:touches withEvent:event];
|
||||
|
||||
[self _clearHighlightIfNecessary];
|
||||
@ -885,6 +921,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[super touchesEnded:touches withEvent:event];
|
||||
|
||||
if ([self _pendingLinkTap] && [_delegate respondsToSelector:@selector(textNode:tappedLinkAttribute:value:atPoint:textRange:)]) {
|
||||
@ -903,6 +940,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
[super touchesMoved:touches withEvent:event];
|
||||
|
||||
UITouch *touch = [touches anyObject];
|
||||
@ -928,6 +966,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (void)_handleLongPress:(UILongPressGestureRecognizer *)longPressRecognizer
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
// Respond to long-press when it begins, not when it ends.
|
||||
if (longPressRecognizer.state == UIGestureRecognizerStateBegan) {
|
||||
if ([self.delegate respondsToSelector:@selector(textNode:longPressedLinkAttribute:value:atPoint:textRange:)]) {
|
||||
@ -939,11 +979,15 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (BOOL)_pendingLinkTap
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return (_highlightedLinkAttributeValue != nil && ![self _pendingTruncationTap]) && _delegate != nil;
|
||||
}
|
||||
|
||||
- (BOOL)_pendingTruncationTap
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return [_highlightedLinkAttributeName isEqualToString:ASTextNodeTruncationTokenAttributeName];
|
||||
}
|
||||
|
||||
@ -951,11 +995,15 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (CGColorRef)shadowColor
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return _shadowColor;
|
||||
}
|
||||
|
||||
- (void)setShadowColor:(CGColorRef)shadowColor
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_shadowColor != shadowColor) {
|
||||
if (shadowColor != NULL) {
|
||||
CGColorRetain(shadowColor);
|
||||
@ -968,11 +1016,15 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (CGSize)shadowOffset
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return _shadowOffset;
|
||||
}
|
||||
|
||||
- (void)setShadowOffset:(CGSize)shadowOffset
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (!CGSizeEqualToSize(_shadowOffset, shadowOffset)) {
|
||||
_shadowOffset = shadowOffset;
|
||||
[self _invalidateRenderer];
|
||||
@ -982,11 +1034,15 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (CGFloat)shadowOpacity
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return _shadowOpacity;
|
||||
}
|
||||
|
||||
- (void)setShadowOpacity:(CGFloat)shadowOpacity
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_shadowOpacity != shadowOpacity) {
|
||||
_shadowOpacity = shadowOpacity;
|
||||
[self _invalidateRenderer];
|
||||
@ -996,11 +1052,15 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (CGFloat)shadowRadius
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return _shadowRadius;
|
||||
}
|
||||
|
||||
- (void)setShadowRadius:(CGFloat)shadowRadius
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_shadowRadius != shadowRadius) {
|
||||
_shadowRadius = shadowRadius;
|
||||
[self _invalidateRenderer];
|
||||
@ -1015,6 +1075,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
|
||||
- (UIEdgeInsets)shadowPaddingWithRenderer:(ASTextKitRenderer *)renderer
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return renderer.shadower.shadowPadding;
|
||||
}
|
||||
|
||||
@ -1032,6 +1094,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
|
||||
- (void)setTruncationAttributedText:(NSAttributedString *)truncationAttributedText
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (ASObjectIsEqual(_truncationAttributedText, truncationAttributedText)) {
|
||||
return;
|
||||
}
|
||||
@ -1042,6 +1106,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
|
||||
- (void)setAdditionalTruncationMessage:(NSAttributedString *)additionalTruncationMessage
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (ASObjectIsEqual(_additionalTruncationMessage, additionalTruncationMessage)) {
|
||||
return;
|
||||
}
|
||||
@ -1052,6 +1118,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
|
||||
- (void)setTruncationMode:(NSLineBreakMode)truncationMode
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_truncationMode != truncationMode) {
|
||||
_truncationMode = truncationMode;
|
||||
[self _invalidateRenderer];
|
||||
@ -1061,12 +1129,16 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
|
||||
- (BOOL)isTruncated
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
ASTextKitRenderer *renderer = [self _renderer];
|
||||
return renderer.firstVisibleRange.length < _attributedText.length;
|
||||
}
|
||||
|
||||
- (void)setPointSizeScaleFactors:(NSArray *)pointSizeScaleFactors
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if ([_pointSizeScaleFactors isEqualToArray:pointSizeScaleFactors] == NO) {
|
||||
_pointSizeScaleFactors = pointSizeScaleFactors;
|
||||
[self _invalidateRenderer];
|
||||
@ -1075,6 +1147,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
|
||||
- (void)setMaximumNumberOfLines:(NSUInteger)maximumNumberOfLines
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
if (_maximumNumberOfLines != maximumNumberOfLines) {
|
||||
_maximumNumberOfLines = maximumNumberOfLines;
|
||||
[self _invalidateRenderer];
|
||||
@ -1084,6 +1158,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
|
||||
- (NSUInteger)lineCount
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
return [[self _renderer] lineCount];
|
||||
}
|
||||
|
||||
@ -1091,6 +1167,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
|
||||
- (void)_updateComposedTruncationText
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
_composedTruncationText = [self _prepareTruncationStringForDrawing:[self _composedTruncationText]];
|
||||
}
|
||||
|
||||
@ -1107,6 +1185,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
*/
|
||||
- (NSRange)_additionalTruncationMessageRangeWithVisibleRange:(NSRange)visibleRange
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
// Check if we even have an additional truncation message.
|
||||
if (!_additionalTruncationMessage) {
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
@ -1118,8 +1198,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
NSUInteger additionalTruncationMessageLength = _additionalTruncationMessage.length;
|
||||
// We get the location of the truncation token, then add the length of the
|
||||
// truncation attributed string +1 for the space between.
|
||||
NSRange range = NSMakeRange(truncationTokenIndex + _truncationAttributedText.length + 1, additionalTruncationMessageLength);
|
||||
return range;
|
||||
return NSMakeRange(truncationTokenIndex + _truncationAttributedText.length + 1, additionalTruncationMessageLength);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1129,6 +1208,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
*/
|
||||
- (NSAttributedString *)_composedTruncationText
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
//If we have neither return the default
|
||||
if (!_additionalTruncationMessage && !_truncationAttributedText) {
|
||||
return _composedTruncationText;
|
||||
@ -1157,6 +1238,8 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
*/
|
||||
- (NSAttributedString *)_prepareTruncationStringForDrawing:(NSAttributedString *)truncationString
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> l(_textLock);
|
||||
|
||||
truncationString = ASCleanseAttributedStringOfCoreTextAttributes(truncationString);
|
||||
NSMutableAttributedString *truncationMutableString = [truncationString mutableCopy];
|
||||
// Grab the attributes from the full string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user