mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Fixed some text shrinking issues
Previously I was multiplying the calculated height of the text by the scale factor. This fails in the case where we have a long string that doesn't fit, but it is shrunk so much that it now has more than enough room in the renderer's constrained size. In this case we fail to update the calculated size's width. Also updated `lineCountForString` in `ASTextKitFontSizeAdjuster` to reuse a sizer layout manager and text container.
This commit is contained in:
@@ -22,6 +22,8 @@
|
|||||||
std::mutex _textKitMutex;
|
std::mutex _textKitMutex;
|
||||||
BOOL _measured;
|
BOOL _measured;
|
||||||
CGFloat _scaleFactor;
|
CGFloat _scaleFactor;
|
||||||
|
NSLayoutManager *_sizingLayoutManager;
|
||||||
|
NSTextContainer *_sizingTextContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithContext:(ASTextKitContext *)context
|
- (instancetype)initWithContext:(ASTextKitContext *)context
|
||||||
@@ -78,30 +80,38 @@
|
|||||||
|
|
||||||
- (NSUInteger)lineCountForString:(NSAttributedString *)attributedString
|
- (NSUInteger)lineCountForString:(NSAttributedString *)attributedString
|
||||||
{
|
{
|
||||||
NSUInteger lineCount = 0;
|
NSUInteger lineCount = 0;
|
||||||
|
|
||||||
static std::mutex __static_mutex;
|
static std::mutex __static_mutex;
|
||||||
std::lock_guard<std::mutex> l(__static_mutex);
|
std::lock_guard<std::mutex> l(__static_mutex);
|
||||||
|
|
||||||
NSTextStorage *textStorage = _attributes.textStorageCreationBlock ? _attributes.textStorageCreationBlock(attributedString) : [[NSTextStorage alloc] initWithAttributedString:attributedString];
|
NSTextStorage *textStorage = _attributes.textStorageCreationBlock ? _attributes.textStorageCreationBlock(attributedString) : [[NSTextStorage alloc] initWithAttributedString:attributedString];
|
||||||
NSLayoutManager *layoutManager = _attributes.layoutManagerCreationBlock ? _attributes.layoutManagerCreationBlock() : [[ASLayoutManager alloc] init];
|
if (_sizingLayoutManager == nil) {
|
||||||
layoutManager.usesFontLeading = NO;
|
_sizingLayoutManager = _attributes.layoutManagerCreationBlock ? _attributes.layoutManagerCreationBlock() : [[ASLayoutManager alloc] init];
|
||||||
[textStorage addLayoutManager:layoutManager];
|
_sizingLayoutManager.usesFontLeading = NO;
|
||||||
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(_constrainedSize.width, FLT_MAX)];
|
}
|
||||||
|
[textStorage addLayoutManager:_sizingLayoutManager];
|
||||||
textContainer.lineFragmentPadding = 0;
|
if (_sizingTextContainer == nil) {
|
||||||
textContainer.lineBreakMode = _attributes.lineBreakMode;
|
// 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.
|
||||||
// use 0 regardless of what is in the attributes so that we get an accurate line count
|
_sizingTextContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(_constrainedSize.width, FLT_MAX)];
|
||||||
textContainer.maximumNumberOfLines = 0;
|
_sizingTextContainer.lineFragmentPadding = 0;
|
||||||
textContainer.exclusionPaths = _attributes.exclusionPaths;
|
|
||||||
[layoutManager addTextContainer:textContainer];
|
// use 0 regardless of what is in the attributes so that we get an accurate line count
|
||||||
|
_sizingTextContainer.maximumNumberOfLines = 0;
|
||||||
for (NSRange lineRange = { 0, 0 }; NSMaxRange(lineRange) < [layoutManager numberOfGlyphs] && lineCount <= _attributes.maximumNumberOfLines; lineCount++) {
|
[_sizingLayoutManager addTextContainer:_sizingTextContainer];
|
||||||
[layoutManager lineFragmentRectForGlyphAtIndex:NSMaxRange(lineRange) effectiveRange:&lineRange];
|
}
|
||||||
}
|
|
||||||
|
_sizingTextContainer.lineBreakMode = _attributes.lineBreakMode;
|
||||||
return lineCount;
|
_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
|
- (CGFloat)scaleFactor
|
||||||
|
|||||||
@@ -142,28 +142,44 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
if (isinf(_constrainedSize.width) == NO && [_attributes.pointSizeScaleFactors count] > 0) {
|
if (isinf(_constrainedSize.width) == NO && [_attributes.pointSizeScaleFactors count] > 0) {
|
||||||
_currentScaleFactor = [[self fontSizeAdjuster] scaleFactor];
|
_currentScaleFactor = [[self fontSizeAdjuster] scaleFactor];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force glyph generation and layout, which may not have happened yet (and isn't triggered by
|
// Force glyph generation and layout, which may not have happened yet (and isn't triggered by
|
||||||
// -usedRectForTextContainer:).
|
// -usedRectForTextContainer:).
|
||||||
|
__block NSTextStorage *scaledTextStorage = nil;
|
||||||
|
BOOL isScaled = [self isScaled];
|
||||||
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
[[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];
|
[layoutManager ensureLayoutForTextContainer:textContainer];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
CGRect constrainedRect = {CGPointZero, _constrainedSize};
|
CGRect constrainedRect = {CGPointZero, _constrainedSize};
|
||||||
__block CGRect boundingRect;
|
__block CGRect boundingRect;
|
||||||
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
||||||
boundingRect = [layoutManager usedRectForTextContainer: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
|
// 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.
|
// to make sure our width calculations aren't being offset by glyphs going beyond the constrained rect.
|
||||||
boundingRect = CGRectIntersection(boundingRect, {.size = constrainedRect.size});
|
boundingRect = CGRectIntersection(boundingRect, {.size = constrainedRect.size});
|
||||||
CGSize boundingSize = [_shadower outsetSizeWithInsetSize:boundingRect.size];
|
CGSize boundingSize = [_shadower outsetSizeWithInsetSize:boundingRect.size];
|
||||||
_calculatedSize = CGSizeMake(boundingSize.width, boundingSize.height);
|
_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
|
#pragma mark - Drawing
|
||||||
@@ -189,7 +205,7 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
||||||
|
|
||||||
NSTextStorage *scaledTextStorage = nil;
|
NSTextStorage *scaledTextStorage = nil;
|
||||||
BOOL isScaled = (self.currentScaleFactor > 0 && self.currentScaleFactor < 1.0);
|
BOOL isScaled = [self isScaled];
|
||||||
|
|
||||||
if (isScaled) {
|
if (isScaled) {
|
||||||
// if we are going to scale the text, swap out the non-scaled text for the scaled version.
|
// if we are going to scale the text, swap out the non-scaled text for the scaled version.
|
||||||
|
|||||||
Reference in New Issue
Block a user