Reduce copying in ASTextNode2 stack (#1065)

* Remove copying in text stack, make text container have an optional immutable mode

* Changelog

* Comment

* Update CHANGELOG.md

* Use new name

* Import header
This commit is contained in:
Adlai Holler 2018-08-07 08:32:43 -07:00 committed by GitHub
parent 2bb216b02e
commit 03e6ce0916
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 19 deletions

View File

@ -31,6 +31,7 @@
- Optimize display node accessibility by not creating attributed & non-attributed copies of hint, label, and value. [Adlai Holler](https://github.com/Adlai-Holler)
- Add an experimental feature that reuses CTFramesetter objects in ASTextNode2 to improve performance. [Adlai Holler](https://github.com/Adlai-Holler)
- Add NS_DESIGNATED_INITIALIZER to ASViewController initWithNode: [Michael Schneider](https://github.com/maicki) [#1054](https://github.com/TextureGroup/Texture/pull/1054)
- Optimize text stack by removing unneeded copying. [Adlai Holler](https://github.com/Adlai-Holler)
## 2.7
- Fix pager node for interface coalescing. [Max Wang](https://github.com/wsdwsd0829) [#877](https://github.com/TextureGroup/Texture/pull/877)

View File

@ -236,12 +236,17 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
ASLockScopeSelf();
ASTextContainer *container = [_textContainer copy];
NSAttributedString *attributedText = self.attributedText;
container.size = constrainedSize;
ASTextContainer *container;
if (!CGSizeEqualToSize(container.size, constrainedSize)) {
container = [_textContainer copy];
container.size = constrainedSize;
[container makeImmutable];
} else {
container = _textContainer;
}
[self _ensureTruncationText];
NSMutableAttributedString *mutableText = [attributedText mutableCopy];
NSMutableAttributedString *mutableText = [_attributedText mutableCopy];
[self prepareAttributedString:mutableText];
ASTextLayout *layout = [ASTextNode2 compatibleLayoutWithContainer:container text:mutableText];
@ -365,9 +370,12 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
{
ASLockScopeSelf();
[self _ensureTruncationText];
// Unlike layout, here we must copy the container since drawing is asynchronous.
ASTextContainer *copiedContainer = [_textContainer copy];
copiedContainer.size = self.bounds.size;
NSMutableAttributedString *mutableText = [self.attributedText mutableCopy] ?: [[NSMutableAttributedString alloc] init];
[copiedContainer makeImmutable];
NSMutableAttributedString *mutableText = [_attributedText mutableCopy] ?: [[NSMutableAttributedString alloc] init];
[self prepareAttributedString:mutableText];

View File

@ -67,6 +67,9 @@ AS_EXTERN const CGSize ASTextContainerMaxSize;
/// Creates a container with the specified path. @param path The path.
+ (instancetype)containerWithPath:(nullable UIBezierPath *)path NS_RETURNS_RETAINED;
/// Mark this immutable, so you get free copies going forward.
- (void)makeImmutable;
/// The constrained size. (if the size is larger than ASTextContainerMaxSize, it will be clipped)
@property CGSize size;

View File

@ -17,6 +17,7 @@
#import <AsyncDisplayKit/ASTextLayout.h>
#import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASConfigurationInternal.h>
#import <AsyncDisplayKit/ASTextUtilities.h>
#import <AsyncDisplayKit/ASTextAttribute.h>
@ -134,26 +135,36 @@ static CGColorRef ASTextGetCGColor(CGColorRef color) {
return self;
}
- (id)copyWithZone:(NSZone *)zone {
ASTextContainer *one = [self.class new];
- (id)copyForced:(BOOL)forceCopy
{
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
if (_readonly && !forceCopy) {
dispatch_semaphore_signal(_lock);
return self;
}
ASTextContainer *one = [self.class new];
one->_size = _size;
one->_insets = _insets;
one->_path = _path;
one->_exclusionPaths = _exclusionPaths.copy;
one->_exclusionPaths = [_exclusionPaths copy];
one->_pathFillEvenOdd = _pathFillEvenOdd;
one->_pathLineWidth = _pathLineWidth;
one->_verticalForm = _verticalForm;
one->_maximumNumberOfRows = _maximumNumberOfRows;
one->_truncationType = _truncationType;
one->_truncationToken = _truncationToken.copy;
one->_truncationToken = [_truncationToken copy];
one->_linePositionModifier = [(NSObject *)_linePositionModifier copy];
dispatch_semaphore_signal(_lock);
return one;
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
return [self copyWithZone:zone];
- (id)copyWithZone:(NSZone *)zone {
return [self copyForced:NO];
}
- (id)mutableCopyWithZone:(NSZone *)zone {
return [self copyForced:YES];
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
@ -189,18 +200,25 @@ static CGColorRef ASTextGetCGColor(CGColorRef color) {
return self;
}
- (void)makeImmutable
{
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
_readonly = YES;
dispatch_semaphore_signal(_lock);
}
#define Getter(...) \
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
__VA_ARGS__; \
dispatch_semaphore_signal(_lock);
#define Setter(...) \
if (_readonly) { \
@throw [NSException exceptionWithName:NSInternalInconsistencyException \
reason:@"Cannot change the property of the 'container' in 'ASTextLayout'." userInfo:nil]; \
return; \
} \
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
if (__builtin_expect(_readonly, NO)) { \
ASDisplayNodeFailAssert(@"Attempt to modify immutable text container."); \
dispatch_semaphore_signal(_lock); \
return; \
} \
__VA_ARGS__; \
dispatch_semaphore_signal(_lock);
@ -407,11 +425,10 @@ dispatch_semaphore_signal(_lock);
if (lineRowsIndex) free(lineRowsIndex); \
return nil; }
text = text.mutableCopy;
container = container.copy;
container = [container copy];
if (!text || !container) return nil;
if (range.location + range.length > text.length) return nil;
container->_readonly = YES;
[container makeImmutable];
maximumNumberOfRows = container.maximumNumberOfRows;
// It may use larger constraint size when create CTFrame with