[ASTextNode, ASImageNode, ASVideoNode] Use ASDisplayNode base class lock for subclass property synchronization (#1877)

* [ASTextNode, ASVideoNode] Use ASDisplayNode base class lock for subclass property synchronization

* fix headers to match master

* address @appleguy, @maicki comments

* import header

* Swap lock in ASNetworkImageNode as well

* remove invalid comment

* more cleanup of locks
This commit is contained in:
Hannah Troisi
2016-07-09 22:08:34 -07:00
committed by appleguy
parent 131dd25de3
commit f39c2ce7e3
4 changed files with 123 additions and 144 deletions

View File

@@ -44,7 +44,6 @@ struct ASImageNodeDrawParameters {
UIImage *_image;
void (^_displayCompletionBlock)(BOOL canceled);
ASDN::RecursiveMutex _imageLock;
// Drawing
ASImageNodeDrawParameters _drawParameter;
@@ -119,7 +118,7 @@ struct ASImageNodeDrawParameters {
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
// if a preferredFrameSize is set, call the superclass to return that instead of using the image size.
if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO)
return [super calculateSizeThatFits:constrainedSize];
@@ -133,11 +132,9 @@ struct ASImageNodeDrawParameters {
- (void)setImage:(UIImage *)image
{
_imageLock.lock();
ASDN::MutexLocker l(_propertyLock);
if (!ASObjectIsEqual(_image, image)) {
_image = image;
_imageLock.unlock();
[self invalidateCalculatedLayout];
if (image) {
@@ -153,14 +150,12 @@ struct ASImageNodeDrawParameters {
} else {
self.contents = nil;
}
} else {
_imageLock.unlock(); // We avoid using MutexUnlocker as it needlessly re-locks at the end of the scope.
}
}
- (UIImage *)image
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
return _image;
}
@@ -176,7 +171,7 @@ struct ASImageNodeDrawParameters {
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
_drawParameter = {
.bounds = self.bounds,
@@ -221,7 +216,7 @@ struct ASImageNodeDrawParameters {
asimagenode_modification_block_t imageModificationBlock;
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
ASImageNodeDrawParameters drawParameter = _drawParameter;
drawParameterBounds = drawParameter.bounds;
@@ -356,19 +351,19 @@ struct ASImageNodeDrawParameters {
{
[super displayDidFinish];
_imageLock.lock();
_propertyLock.lock();
void (^displayCompletionBlock)(BOOL canceled) = _displayCompletionBlock;
UIImage *image = _image;
_imageLock.unlock();
_propertyLock.unlock();
// If we've got a block to perform after displaying, do it.
if (image && displayCompletionBlock) {
displayCompletionBlock(NO);
_imageLock.lock();
_propertyLock.lock();
_displayCompletionBlock = nil;
_imageLock.unlock();
_propertyLock.unlock();
}
}
@@ -381,7 +376,7 @@ struct ASImageNodeDrawParameters {
}
// Stash the block and call-site queue. We'll invoke it in -displayDidFinish.
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
if (_displayCompletionBlock != displayCompletionBlock) {
_displayCompletionBlock = [displayCompletionBlock copy];
}
@@ -393,7 +388,7 @@ struct ASImageNodeDrawParameters {
- (BOOL)isCropEnabled
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
return _cropEnabled;
}
@@ -404,7 +399,7 @@ struct ASImageNodeDrawParameters {
- (void)setCropEnabled:(BOOL)cropEnabled recropImmediately:(BOOL)recropImmediately inBounds:(CGRect)cropBounds
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
if (_cropEnabled == cropEnabled)
return;
@@ -425,13 +420,13 @@ struct ASImageNodeDrawParameters {
- (CGRect)cropRect
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
return _cropRect;
}
- (void)setCropRect:(CGRect)cropRect
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
if (CGRectEqualToRect(_cropRect, cropRect))
return;
@@ -452,25 +447,25 @@ struct ASImageNodeDrawParameters {
- (BOOL)forceUpscaling
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
return _forceUpscaling;
}
- (void)setForceUpscaling:(BOOL)forceUpscaling
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
_forceUpscaling = forceUpscaling;
}
- (asimagenode_modification_block_t)imageModificationBlock
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
return _imageModificationBlock;
}
- (void)setImageModificationBlock:(asimagenode_modification_block_t)imageModificationBlock
{
ASDN::MutexLocker l(_imageLock);
ASDN::MutexLocker l(_propertyLock);
_imageModificationBlock = imageModificationBlock;
}

View File

@@ -11,6 +11,7 @@
#import "ASNetworkImageNode.h"
#import "ASBasicImageDownloader.h"
#import "ASDisplayNodeInternal.h"
#import "ASDisplayNode+Subclasses.h"
#import "ASDisplayNode+FrameworkPrivate.h"
#import "ASEqualityHelpers.h"
@@ -26,11 +27,10 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
@interface ASNetworkImageNode ()
{
ASDN::RecursiveMutex _lock;
__weak id<ASImageCacheProtocol, ASImageCacheProtocolDeprecated> _cache;
__weak id<ASImageDownloaderProtocol, ASImageDownloaderProtocolDeprecated> _downloader;
// Only access any of these with _lock.
// Only access any of these with _propertyLock.
__weak id<ASNetworkImageNodeDelegate> _delegate;
NSURL *_URL;
@@ -121,7 +121,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
- (void)setURL:(NSURL *)URL resetToDefault:(BOOL)reset
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
if (ASObjectIsEqual(URL, _URL)) {
return;
@@ -150,16 +150,15 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
- (NSURL *)URL
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
return _URL;
}
- (void)setDefaultImage:(UIImage *)defaultImage
{
_lock.lock();
ASDN::MutexLocker l(_propertyLock);
if (ASObjectIsEqual(defaultImage, _defaultImage)) {
_lock.unlock();
return;
}
_defaultImage = defaultImage;
@@ -172,49 +171,43 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
dispatch_async(dispatch_get_main_queue(), ^{
self.currentImageQuality = hasURL ? 0.0 : 1.0;
});
_lock.unlock();
// Locking: it is important to release _lock before entering setImage:, as it needs to release the lock before -invalidateCalculatedLayout.
// If we continue to hold the lock here, it will still be locked until the next unlock() call, causing a possible deadlock with
// -[ASNetworkImageNode displayWillStart] (which is called on a different thread / main, at an unpredictable time due to ASMainRunloopQueue).
self.image = defaultImage;
} else {
_lock.unlock();
}
}
- (UIImage *)defaultImage
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
return _defaultImage;
}
- (void)setCurrentImageQuality:(CGFloat)currentImageQuality
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
_currentImageQuality = currentImageQuality;
}
- (CGFloat)currentImageQuality
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
return _currentImageQuality;
}
- (void)setRenderedImageQuality:(CGFloat)renderedImageQuality
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
_renderedImageQuality = renderedImageQuality;
}
- (CGFloat)renderedImageQuality
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
return _renderedImageQuality;
}
- (void)setDelegate:(id<ASNetworkImageNodeDelegate>)delegate
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
_delegate = delegate;
_delegateFlags.delegateDidStartFetchingData = [delegate respondsToSelector:@selector(imageNodeDidStartFetchingData:)];
@@ -225,13 +218,13 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
- (id<ASNetworkImageNodeDelegate>)delegate
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
return _delegate;
}
- (void)setShouldRenderProgressImages:(BOOL)shouldRenderProgressImages
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
if (shouldRenderProgressImages == _shouldRenderProgressImages) {
return;
}
@@ -239,19 +232,19 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
_shouldRenderProgressImages = shouldRenderProgressImages;
ASDN::MutexUnlocker u(_lock);
ASDN::MutexUnlocker u(_propertyLock);
[self _updateProgressImageBlockOnDownloaderIfNeeded];
}
- (BOOL)shouldRenderProgressImages
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
return _shouldRenderProgressImages;
}
- (BOOL)placeholderShouldPersist
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
return (self.image == nil && _URL != nil);
}
@@ -262,7 +255,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
[super displayWillStart];
if (_cacheFlags.cacheSupportsSynchronousFetch) {
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
if (_imageLoaded == NO && _URL && _downloadIdentifier == nil) {
UIImage *result = [[_cache synchronouslyFetchedCachedImageWithURL:_URL] asdk_image];
if (result) {
@@ -279,7 +272,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
[self fetchData];
if (self.image == nil && _downloaderFlags.downloaderImplementsSetPriority) {
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
if (_downloadIdentifier != nil) {
[_downloader setPriority:ASImageDownloaderPriorityImminent withDownloadIdentifier:_downloadIdentifier];
}
@@ -293,7 +286,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
[super visibleStateDidChange:isVisible];
if (_downloaderFlags.downloaderImplementsSetPriority) {
_lock.lock();
ASDN::MutexLocker l(_propertyLock);
if (_downloadIdentifier != nil) {
if (isVisible) {
[_downloader setPriority:ASImageDownloaderPriorityVisible withDownloadIdentifier:_downloadIdentifier];
@@ -301,10 +294,8 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
[_downloader setPriority:ASImageDownloaderPriorityPreload withDownloadIdentifier:_downloadIdentifier];
}
}
_lock.unlock();
}
// This method has to be called without _lock held
[self _updateProgressImageBlockOnDownloaderIfNeeded];
}
@@ -313,7 +304,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
[super clearFetchedData];
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
[self _cancelImageDownload];
[self _clearImage];
@@ -328,24 +319,19 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
[super fetchData];
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
[self _lazilyLoadImageIfNecessary];
}
}
#pragma mark - Private methods -- only call with lock.
/**
@note: This should be called without _lock held. We will lock
super to read our interface state and it's best to avoid acquiring both locks.
*/
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
{
BOOL shouldRenderProgressImages = self.shouldRenderProgressImages;
ASDN::MutexLocker l(_propertyLock);
// Read our interface state before locking so that we don't lock super while holding our lock.
BOOL shouldRenderProgressImages = _shouldRenderProgressImages;
ASInterfaceState interfaceState = self.interfaceState;
ASDN::MutexLocker l(_lock);
if (!_downloaderFlags.downloaderImplementsSetProgress || _downloadIdentifier == nil) {
return;
@@ -360,14 +346,15 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
return;
}
ASDN::MutexLocker l(strongSelf->_lock);
ASDN::MutexLocker l(strongSelf->_propertyLock);
//Getting a result back for a different download identifier, download must not have been successfully canceled
if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
return;
}
strongSelf.image = progressImage;
dispatch_async(dispatch_get_main_queue(), ^{
strongSelf->_currentImageQuality = progress;
// See comment in -displayDidFinish for why this must be dispatched to main
strongSelf.currentImageQuality = progress;
});
};
}
@@ -391,6 +378,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
self.animatedImage = nil;
self.image = _defaultImage;
_imageLoaded = NO;
// See comment in -displayDidFinish for why this must be dispatched to main
dispatch_async(dispatch_get_main_queue(), ^{
self.currentImageQuality = 0.0;
});
@@ -413,7 +401,8 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
- (void)_downloadImageWithCompletion:(void (^)(id <ASImageContainerProtocol> imageContainer, NSError*, id downloadIdentifier))finished
{
ASPerformBlockOnBackgroundThread(^{
_lock.lock();
ASDN::MutexLocker l(_propertyLock);
if (_downloaderFlags.downloaderSupportsNewProtocol) {
_downloadIdentifier = [_downloader downloadImageWithURL:_URL
callbackQueue:dispatch_get_main_queue()
@@ -436,9 +425,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
}];
#pragma clang diagnostic pop
}
_lock.unlock();
// This method has to be called without _lock held
[self _updateProgressImageBlockOnDownloaderIfNeeded];
});
@@ -449,7 +436,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
// FIXME: We should revisit locking in this method (e.g. to access the instance variables at the top, and holding lock while calling delegate)
if (!_imageLoaded && _URL != nil && _downloadIdentifier == nil) {
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
if (_delegateFlags.delegateDidStartFetchingData) {
[_delegate imageNodeDidStartFetchingData:self];
}
@@ -457,7 +444,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
if (_URL.isFileURL) {
{
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
dispatch_async(dispatch_get_main_queue(), ^{
if (self.shouldCacheImage) {
@@ -515,7 +502,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
return;
}
ASDN::MutexLocker l(strongSelf->_lock);
ASDN::MutexLocker l(strongSelf->_propertyLock);
//Getting a result back for a different download identifier, download must not have been successfully canceled
if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
@@ -592,7 +579,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
{
[super displayDidFinish];
ASDN::MutexLocker l(_lock);
ASDN::MutexLocker l(_propertyLock);
if (_delegateFlags.delegateDidFinishDecoding && self.layer.contents != nil) {
/* We store the image quality in _currentImageQuality whenever _image is set. On the following displayDidFinish, we'll know that
_currentImageQuality is the quality of the image that has just finished rendering. In order for this to be accurate, we

View File

@@ -57,8 +57,6 @@ struct ASTextNodeDrawParameter {
NSRange _highlightRange;
ASHighlightOverlayLayer *_activeHighlightLayer;
std::recursive_mutex _textLock;
CGSize _constrainedSize;
ASTextKitRenderer *_renderer;
@@ -153,7 +151,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (NSString *)description
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
NSString *plainString = [[_attributedText string] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSString *truncationString = [_composedTruncationText string];
@@ -222,7 +220,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (ASTextKitRenderer *)_rendererWithBounds:(CGRect)bounds
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_renderer == nil) {
CGSize constrainedSize = _constrainedSize.width != -INFINITY ? _constrainedSize : bounds.size;
@@ -234,7 +232,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (ASTextKitAttributes)_rendererAttributes
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return {
.attributedString = _attributedText,
@@ -260,7 +258,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
// so our previous layout information is invalid, and TextKit may draw at the
// incorrect origin.
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
_constrainedSize = CGSizeMake(-INFINITY, -INFINITY);
}
[self _invalidateRenderer];
@@ -269,7 +267,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (void)_invalidateRenderer
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_renderer) {
// Destruction of the layout managers/containers/text storage is quite
@@ -288,7 +286,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (BOOL)_needInvalidateRendererForBoundsSize:(CGSize)boundsSize
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_renderer == nil) {
return YES;
@@ -327,7 +325,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
ASLayout *layout = self.calculatedLayout;
if (layout != nil) {
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
_constrainedSize = layout.size;
_renderer.constrainedSize = layout.size;
}
@@ -338,7 +336,7 @@ 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);
ASDN::MutexLocker l(_propertyLock);
_constrainedSize = constrainedSize;
@@ -373,7 +371,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
// Don't hold textLock for too long.
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (ASObjectIsEqual(attributedText, _attributedText)) {
return;
}
@@ -411,7 +409,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (void)setExclusionPaths:(NSArray *)exclusionPaths
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (ASObjectIsEqual(exclusionPaths, _exclusionPaths)) {
return;
@@ -425,7 +423,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (NSArray *)exclusionPaths
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return _exclusionPaths;
}
@@ -434,7 +432,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
_drawParameter = {
.backgroundColor = self.backgroundColor,
@@ -446,7 +444,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (void)drawRect:(CGRect)bounds withParameters:(id <NSObject>)p isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
ASTextNodeDrawParameter drawParameter = _drawParameter;
CGRect drawParameterBounds = drawParameter.bounds;
@@ -499,7 +497,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
{
ASDisplayNodeAssertMainThread();
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
ASTextKitRenderer *renderer = [self _renderer];
NSRange visibleRange = renderer.firstVisibleRange;
@@ -626,14 +624,14 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (ASTextNodeHighlightStyle)highlightStyle
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return _highlightStyle;
}
- (void)setHighlightStyle:(ASTextNodeHighlightStyle)highlightStyle
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
_highlightStyle = highlightStyle;
}
@@ -717,7 +715,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
}
if (highlightTargetLayer != nil) {
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
NSArray *highlightRects = [[self _renderer] rectsForTextRange:highlightRange measureOption:ASTextKitRendererMeasureOptionBlock];
NSMutableArray *converted = [NSMutableArray arrayWithCapacity:highlightRects.count];
@@ -797,7 +795,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (NSArray *)_rectsForTextRange:(NSRange)textRange measureOption:(ASTextKitRendererMeasureOption)measureOption
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
NSArray *rects = [[self _renderer] rectsForTextRange:textRange measureOption:measureOption];
NSMutableArray *adjustedRects = [NSMutableArray array];
@@ -815,7 +813,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (CGRect)trailingRect
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
CGRect rect = [[self _renderer] trailingRect];
return ASTextNodeAdjustRenderRectForShadowPadding(rect, self.shadowPadding);
@@ -823,7 +821,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (CGRect)frameForTextRange:(NSRange)textRange
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
CGRect frame = [[self _renderer] frameForTextRange:textRange];
return ASTextNodeAdjustRenderRectForShadowPadding(frame, self.shadowPadding);
@@ -833,7 +831,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
_placeholderColor = placeholderColor;
@@ -850,7 +848,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
return nil;
}
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
UIGraphicsBeginImageContext(size);
[self.placeholderColor setFill];
@@ -932,7 +930,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
if (inAdditionalTruncationMessage) {
NSRange visibleRange = NSMakeRange(0, 0);
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
visibleRange = [self _renderer].firstVisibleRange;
}
NSRange truncationMessageRange = [self _additionalTruncationMessageRangeWithVisibleRange:visibleRange];
@@ -1011,14 +1009,14 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (BOOL)_pendingLinkTap
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return (_highlightedLinkAttributeValue != nil && ![self _pendingTruncationTap]) && _delegate != nil;
}
- (BOOL)_pendingTruncationTap
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return [_highlightedLinkAttributeName isEqualToString:ASTextNodeTruncationTokenAttributeName];
}
@@ -1027,14 +1025,14 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (CGColorRef)shadowColor
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return _shadowColor;
}
- (void)setShadowColor:(CGColorRef)shadowColor
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_shadowColor != shadowColor) {
if (shadowColor != NULL) {
@@ -1048,14 +1046,14 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (CGSize)shadowOffset
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return _shadowOffset;
}
- (void)setShadowOffset:(CGSize)shadowOffset
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (!CGSizeEqualToSize(_shadowOffset, shadowOffset)) {
_shadowOffset = shadowOffset;
@@ -1066,14 +1064,14 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (CGFloat)shadowOpacity
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return _shadowOpacity;
}
- (void)setShadowOpacity:(CGFloat)shadowOpacity
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_shadowOpacity != shadowOpacity) {
_shadowOpacity = shadowOpacity;
@@ -1084,14 +1082,14 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (CGFloat)shadowRadius
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return _shadowRadius;
}
- (void)setShadowRadius:(CGFloat)shadowRadius
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_shadowRadius != shadowRadius) {
_shadowRadius = shadowRadius;
@@ -1107,7 +1105,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
- (UIEdgeInsets)shadowPaddingWithRenderer:(ASTextKitRenderer *)renderer
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return renderer.shadower.shadowPadding;
}
@@ -1126,7 +1124,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (void)setTruncationAttributedText:(NSAttributedString *)truncationAttributedText
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (ASObjectIsEqual(_truncationAttributedText, truncationAttributedText)) {
return;
@@ -1138,7 +1136,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (void)setAdditionalTruncationMessage:(NSAttributedString *)additionalTruncationMessage
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (ASObjectIsEqual(_additionalTruncationMessage, additionalTruncationMessage)) {
return;
@@ -1150,7 +1148,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (void)setTruncationMode:(NSLineBreakMode)truncationMode
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_truncationMode != truncationMode) {
_truncationMode = truncationMode;
@@ -1161,7 +1159,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (BOOL)isTruncated
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
ASTextKitRenderer *renderer = [self _renderer];
return renderer.firstVisibleRange.length < _attributedText.length;
@@ -1169,7 +1167,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (void)setPointSizeScaleFactors:(NSArray *)pointSizeScaleFactors
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if ([_pointSizeScaleFactors isEqualToArray:pointSizeScaleFactors] == NO) {
_pointSizeScaleFactors = pointSizeScaleFactors;
@@ -1179,7 +1177,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (void)setMaximumNumberOfLines:(NSUInteger)maximumNumberOfLines
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
if (_maximumNumberOfLines != maximumNumberOfLines) {
_maximumNumberOfLines = maximumNumberOfLines;
@@ -1190,7 +1188,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (NSUInteger)lineCount
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
return [[self _renderer] lineCount];
}
@@ -1199,7 +1197,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (void)_updateComposedTruncationText
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
_composedTruncationText = [self _prepareTruncationStringForDrawing:[self _composedTruncationText]];
}
@@ -1217,7 +1215,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
*/
- (NSRange)_additionalTruncationMessageRangeWithVisibleRange:(NSRange)visibleRange
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
// Check if we even have an additional truncation message.
if (!_additionalTruncationMessage) {
@@ -1240,7 +1238,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
*/
- (NSAttributedString *)_composedTruncationText
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
//If we have neither return the default
if (!_additionalTruncationMessage && !_truncationAttributedText) {
@@ -1270,7 +1268,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
*/
- (NSAttributedString *)_prepareTruncationStringForDrawing:(NSAttributedString *)truncationString
{
std::lock_guard<std::recursive_mutex> l(_textLock);
ASDN::MutexLocker l(_propertyLock);
truncationString = ASCleanseAttributedStringOfCoreTextAttributes(truncationString);
NSMutableAttributedString *truncationMutableString = [truncationString mutableCopy];

View File

@@ -9,6 +9,7 @@
//
#if TARGET_OS_IOS
#import <AVFoundation/AVFoundation.h>
#import "ASDisplayNodeInternal.h"
#import "ASDisplayNode+Subclasses.h"
#import "ASVideoNode.h"
#import "ASEqualityHelpers.h"
@@ -39,8 +40,6 @@ static NSString * const kStatus = @"status";
@interface ASVideoNode ()
{
ASDN::RecursiveMutex _videoLock;
__weak id<ASVideoNodeDelegate> _delegate;
struct {
unsigned int delegateVideNodeShouldChangePlayerStateTo:1;
@@ -122,7 +121,7 @@ static NSString * const kStatus = @"status";
- (AVPlayerItem *)constructPlayerItem
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (_asset != nil) {
return [[AVPlayerItem alloc] initWithAsset:_asset];
@@ -210,7 +209,7 @@ static NSString * const kStatus = @"status";
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
CGSize calculatedSize = constrainedSize;
// if a preferredFrameSize is set, call the superclass to return that instead of using the image size.
@@ -273,7 +272,7 @@ static NSString * const kStatus = @"status";
- (void)setVideoPlaceholderImage:(UIImage *)image
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (image != nil) {
self.contentMode = ASContentModeFromVideoGravity(_gravity);
}
@@ -282,7 +281,7 @@ static NSString * const kStatus = @"status";
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (object != _currentPlayerItem) {
return;
@@ -335,7 +334,7 @@ static NSString * const kStatus = @"status";
{
[super fetchData];
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
AVAsset *asset = self.asset;
// Return immediately if the asset is nil;
if (asset == nil || self.playerState == ASVideoNodePlayerStateInitialLoading) {
@@ -385,7 +384,7 @@ static NSString * const kStatus = @"status";
[super clearFetchedData];
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
self.player = nil;
self.currentItem = nil;
@@ -396,7 +395,7 @@ static NSString * const kStatus = @"status";
{
[super visibleStateDidChange:isVisible];
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (isVisible) {
if (_shouldBePlaying || _shouldAutoplay) {
@@ -413,7 +412,7 @@ static NSString * const kStatus = @"status";
- (void)setPlayerState:(ASVideoNodePlayerState)playerState
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
ASVideoNodePlayerState oldState = _playerState;
@@ -430,7 +429,7 @@ static NSString * const kStatus = @"status";
- (void)setAsset:(AVAsset *)asset
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (ASAssetIsEqual(asset, _asset)) {
return;
@@ -445,13 +444,13 @@ static NSString * const kStatus = @"status";
- (AVAsset *)asset
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return _asset;
}
- (AVPlayer *)player
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return _player;
}
@@ -489,7 +488,7 @@ static NSString * const kStatus = @"status";
- (void)setGravity:(NSString *)gravity
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (_playerNode.isNodeLoaded) {
((AVPlayerLayer *)_playerNode.layer).videoGravity = gravity;
}
@@ -499,19 +498,19 @@ static NSString * const kStatus = @"status";
- (NSString *)gravity
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return _gravity;
}
- (BOOL)muted
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return _muted;
}
- (void)setMuted:(BOOL)muted
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
_player.muted = muted;
_muted = muted;
@@ -521,7 +520,7 @@ static NSString * const kStatus = @"status";
- (void)play
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (![self isStateChangeValid:ASVideoNodePlayerStatePlaying]) {
return;
@@ -558,7 +557,7 @@ static NSString * const kStatus = @"status";
- (void)pause
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
if (![self isStateChangeValid:ASVideoNodePlayerStatePaused]) {
return;
}
@@ -569,7 +568,7 @@ static NSString * const kStatus = @"status";
- (BOOL)isPlaying
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return (_player.rate > 0 && !_player.error);
}
@@ -637,13 +636,13 @@ static NSString * const kStatus = @"status";
- (AVPlayerItem *)currentItem
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return _currentPlayerItem;
}
- (void)setCurrentItem:(AVPlayerItem *)currentItem
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
[self removePlayerItemObservers:_currentPlayerItem];
@@ -656,13 +655,13 @@ static NSString * const kStatus = @"status";
- (ASDisplayNode *)playerNode
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return _playerNode;
}
- (void)setPlayerNode:(ASDisplayNode *)playerNode
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
_playerNode = playerNode;
[self setNeedsLayout];
@@ -670,7 +669,7 @@ static NSString * const kStatus = @"status";
- (void)setPlayer:(AVPlayer *)player
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
_player = player;
player.muted = _muted;
((AVPlayerLayer *)_playerNode.layer).player = player;
@@ -678,13 +677,13 @@ static NSString * const kStatus = @"status";
- (BOOL)shouldBePlaying
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
return _shouldBePlaying;
}
- (void)setShouldBePlaying:(BOOL)shouldBePlaying
{
ASDN::MutexLocker l(_videoLock);
ASDN::MutexLocker l(_propertyLock);
_shouldBePlaying = shouldBePlaying;
}