Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1356 from rcancro/textShrinkningOptimizations
Browse files Browse the repository at this point in the history
[ASTextNode] More refinements to the new font size adjuster behavior.
  • Loading branch information
appleguy committed Mar 10, 2016
2 parents 0bc6060 + bcb1832 commit 5fde235
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 32 deletions.
58 changes: 34 additions & 24 deletions AsyncDisplayKit/TextKit/ASTextKitFontSizeAdjuster.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ @implementation ASTextKitFontSizeAdjuster
std::mutex _textKitMutex;
BOOL _measured;
CGFloat _scaleFactor;
NSLayoutManager *_sizingLayoutManager;
NSTextContainer *_sizingTextContainer;
}

- (instancetype)initWithContext:(ASTextKitContext *)context
Expand Down Expand Up @@ -78,30 +80,38 @@ + (void)adjustFontSizeForAttributeString:(NSMutableAttributedString *)attrString

- (NSUInteger)lineCountForString:(NSAttributedString *)attributedString
{
NSUInteger lineCount = 0;

static std::mutex __static_mutex;
std::lock_guard<std::mutex> l(__static_mutex);

NSTextStorage *textStorage = _attributes.textStorageCreationBlock ? _attributes.textStorageCreationBlock(attributedString) : [[NSTextStorage alloc] initWithAttributedString:attributedString];
NSLayoutManager *layoutManager = _attributes.layoutManagerCreationBlock ? _attributes.layoutManagerCreationBlock() : [[ASLayoutManager alloc] init];
layoutManager.usesFontLeading = NO;
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(_constrainedSize.width, FLT_MAX)];

textContainer.lineFragmentPadding = 0;
textContainer.lineBreakMode = _attributes.lineBreakMode;

// use 0 regardless of what is in the attributes so that we get an accurate line count
textContainer.maximumNumberOfLines = 0;
textContainer.exclusionPaths = _attributes.exclusionPaths;
[layoutManager addTextContainer:textContainer];

for (NSRange lineRange = { 0, 0 }; NSMaxRange(lineRange) < [layoutManager numberOfGlyphs] && lineCount <= _attributes.maximumNumberOfLines; lineCount++) {
[layoutManager lineFragmentRectForGlyphAtIndex:NSMaxRange(lineRange) effectiveRange:&lineRange];
}

return lineCount;
NSUInteger lineCount = 0;

static std::mutex __static_mutex;
std::lock_guard<std::mutex> l(__static_mutex);

NSTextStorage *textStorage = _attributes.textStorageCreationBlock ? _attributes.textStorageCreationBlock(attributedString) : [[NSTextStorage alloc] initWithAttributedString:attributedString];
if (_sizingLayoutManager == nil) {
_sizingLayoutManager = _attributes.layoutManagerCreationBlock ? _attributes.layoutManagerCreationBlock() : [[ASLayoutManager alloc] init];
_sizingLayoutManager.usesFontLeading = NO;
}
[textStorage addLayoutManager:_sizingLayoutManager];
if (_sizingTextContainer == nil) {
// make this text container unbounded in height so that the layout manager will compute the total
// number of lines and not stop counting when height runs out.
_sizingTextContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(_constrainedSize.width, FLT_MAX)];
_sizingTextContainer.lineFragmentPadding = 0;

// use 0 regardless of what is in the attributes so that we get an accurate line count
_sizingTextContainer.maximumNumberOfLines = 0;
[_sizingLayoutManager addTextContainer:_sizingTextContainer];
}

_sizingTextContainer.lineBreakMode = _attributes.lineBreakMode;
_sizingTextContainer.exclusionPaths = _attributes.exclusionPaths;


for (NSRange lineRange = { 0, 0 }; NSMaxRange(lineRange) < [_sizingLayoutManager numberOfGlyphs] && lineCount <= _attributes.maximumNumberOfLines; lineCount++) {
[_sizingLayoutManager lineFragmentRectForGlyphAtIndex:NSMaxRange(lineRange) effectiveRange:&lineRange];
}

[textStorage removeLayoutManager:_sizingLayoutManager];
return lineCount;
}

- (CGFloat)scaleFactor
Expand Down
32 changes: 24 additions & 8 deletions AsyncDisplayKit/TextKit/ASTextKitRenderer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -142,28 +142,44 @@ - (void)_calculateSize
if (isinf(_constrainedSize.width) == NO && [_attributes.pointSizeScaleFactors count] > 0) {
_currentScaleFactor = [[self fontSizeAdjuster] scaleFactor];
}

// Force glyph generation and layout, which may not have happened yet (and isn't triggered by
// -usedRectForTextContainer:).
__block NSTextStorage *scaledTextStorage = nil;
BOOL isScaled = [self isScaled];
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
if (isScaled) {
NSMutableAttributedString *scaledString = [[NSMutableAttributedString alloc] initWithAttributedString:textStorage];
[ASTextKitFontSizeAdjuster adjustFontSizeForAttributeString:scaledString withScaleFactor:_currentScaleFactor];
scaledTextStorage = [[NSTextStorage alloc] initWithAttributedString:scaledString];

[textStorage removeLayoutManager:layoutManager];
[scaledTextStorage addLayoutManager:layoutManager];
}
[layoutManager ensureLayoutForTextContainer:textContainer];
}];

CGRect constrainedRect = {CGPointZero, _constrainedSize};
__block CGRect boundingRect;
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
boundingRect = [layoutManager usedRectForTextContainer:textContainer];
if (isScaled) {
// put the non-scaled version back
[scaledTextStorage removeLayoutManager:layoutManager];
[textStorage addLayoutManager:layoutManager];
}
}];

// TextKit often returns incorrect glyph bounding rects in the horizontal direction, so we clip to our bounding rect
// to make sure our width calculations aren't being offset by glyphs going beyond the constrained rect.
boundingRect = CGRectIntersection(boundingRect, {.size = constrainedRect.size});
CGSize boundingSize = [_shadower outsetSizeWithInsetSize:boundingRect.size];
_calculatedSize = CGSizeMake(boundingSize.width, boundingSize.height);

if (_currentScaleFactor > 0.0 && _currentScaleFactor < 1.0) {
_calculatedSize.height = ceilf(_calculatedSize.height * _currentScaleFactor);
}
}

- (BOOL)isScaled
{
return (self.currentScaleFactor > 0 && self.currentScaleFactor < 1.0);
}

#pragma mark - Drawing
Expand All @@ -189,7 +205,7 @@ - (void)drawInContext:(CGContextRef)context bounds:(CGRect)bounds;
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {

NSTextStorage *scaledTextStorage = nil;
BOOL isScaled = (self.currentScaleFactor > 0 && self.currentScaleFactor < 1.0);
BOOL isScaled = [self isScaled];

if (isScaled) {
// if we are going to scale the text, swap out the non-scaled text for the scaled version.
Expand Down

0 comments on commit 5fde235

Please sign in to comment.