mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
165 lines
5.1 KiB
Plaintext
165 lines
5.1 KiB
Plaintext
//
|
|
// ASTextLine.mm
|
|
// Texture
|
|
//
|
|
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
|
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
|
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
|
|
#import "ASTextLine.h"
|
|
#import <AsyncDisplayKit/ASTextUtilities.h>
|
|
|
|
@implementation ASTextLine {
|
|
CGFloat _firstGlyphPos; // first glyph position for baseline, typically 0.
|
|
}
|
|
|
|
+ (instancetype)lineWithCTLine:(CTLineRef)CTLine position:(CGPoint)position vertical:(BOOL)isVertical NS_RETURNS_RETAINED {
|
|
if (!CTLine) return nil;
|
|
ASTextLine *line = [self new];
|
|
line->_position = position;
|
|
line->_vertical = isVertical;
|
|
[line setCTLine:CTLine];
|
|
return line;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
if (_CTLine) CFRelease(_CTLine);
|
|
}
|
|
|
|
- (void)setCTLine:(_Nonnull CTLineRef)CTLine {
|
|
if (_CTLine != CTLine) {
|
|
if (CTLine) CFRetain(CTLine);
|
|
if (_CTLine) CFRelease(_CTLine);
|
|
_CTLine = CTLine;
|
|
if (_CTLine) {
|
|
_lineWidth = CTLineGetTypographicBounds(_CTLine, &_ascent, &_descent, &_leading);
|
|
CFRange range = CTLineGetStringRange(_CTLine);
|
|
_range = NSMakeRange(range.location, range.length);
|
|
if (CTLineGetGlyphCount(_CTLine) > 0) {
|
|
CFArrayRef runs = CTLineGetGlyphRuns(_CTLine);
|
|
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, 0);
|
|
CGPoint pos;
|
|
CTRunGetPositions(run, CFRangeMake(0, 1), &pos);
|
|
_firstGlyphPos = pos.x;
|
|
} else {
|
|
_firstGlyphPos = 0;
|
|
}
|
|
_trailingWhitespaceWidth = CTLineGetTrailingWhitespaceWidth(_CTLine);
|
|
} else {
|
|
_lineWidth = _ascent = _descent = _leading = _firstGlyphPos = _trailingWhitespaceWidth = 0;
|
|
_range = NSMakeRange(0, 0);
|
|
}
|
|
[self reloadBounds];
|
|
}
|
|
}
|
|
|
|
- (void)setPosition:(CGPoint)position {
|
|
_position = position;
|
|
[self reloadBounds];
|
|
}
|
|
|
|
- (void)reloadBounds {
|
|
if (_vertical) {
|
|
_bounds = CGRectMake(_position.x - _descent, _position.y, _ascent + _descent, _lineWidth);
|
|
_bounds.origin.y += _firstGlyphPos;
|
|
} else {
|
|
_bounds = CGRectMake(_position.x, _position.y - _ascent, _lineWidth, _ascent + _descent);
|
|
_bounds.origin.x += _firstGlyphPos;
|
|
}
|
|
|
|
_attachments = nil;
|
|
_attachmentRanges = nil;
|
|
_attachmentRects = nil;
|
|
if (!_CTLine) return;
|
|
CFArrayRef runs = CTLineGetGlyphRuns(_CTLine);
|
|
NSUInteger runCount = CFArrayGetCount(runs);
|
|
if (runCount == 0) return;
|
|
|
|
NSMutableArray *attachments = [NSMutableArray new];
|
|
NSMutableArray *attachmentRanges = [NSMutableArray new];
|
|
NSMutableArray *attachmentRects = [NSMutableArray new];
|
|
for (NSUInteger r = 0; r < runCount; r++) {
|
|
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, r);
|
|
CFIndex glyphCount = CTRunGetGlyphCount(run);
|
|
if (glyphCount == 0) continue;
|
|
NSDictionary *attrs = (id)CTRunGetAttributes(run);
|
|
ASTextAttachment *attachment = attrs[ASTextAttachmentAttributeName];
|
|
if (attachment) {
|
|
CGPoint runPosition = CGPointZero;
|
|
CTRunGetPositions(run, CFRangeMake(0, 1), &runPosition);
|
|
|
|
CGFloat ascent, descent, leading, runWidth;
|
|
CGRect runTypoBounds;
|
|
runWidth = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, &leading);
|
|
|
|
if (_vertical) {
|
|
ASTEXT_SWAP(runPosition.x, runPosition.y);
|
|
runPosition.y = _position.y + runPosition.y;
|
|
runTypoBounds = CGRectMake(_position.x + runPosition.x - descent, runPosition.y , ascent + descent, runWidth);
|
|
} else {
|
|
runPosition.x += _position.x;
|
|
runPosition.y = _position.y - runPosition.y;
|
|
runTypoBounds = CGRectMake(runPosition.x, runPosition.y - ascent, runWidth, ascent + descent);
|
|
}
|
|
|
|
NSRange runRange = ASTextNSRangeFromCFRange(CTRunGetStringRange(run));
|
|
[attachments addObject:attachment];
|
|
[attachmentRanges addObject:[NSValue valueWithRange:runRange]];
|
|
[attachmentRects addObject:[NSValue valueWithCGRect:runTypoBounds]];
|
|
}
|
|
}
|
|
_attachments = attachments.count ? attachments : nil;
|
|
_attachmentRanges = attachmentRanges.count ? attachmentRanges : nil;
|
|
_attachmentRects = attachmentRects.count ? attachmentRects : nil;
|
|
}
|
|
|
|
- (CGSize)size {
|
|
return _bounds.size;
|
|
}
|
|
|
|
- (CGFloat)width {
|
|
return CGRectGetWidth(_bounds);
|
|
}
|
|
|
|
- (CGFloat)height {
|
|
return CGRectGetHeight(_bounds);
|
|
}
|
|
|
|
- (CGFloat)top {
|
|
return CGRectGetMinY(_bounds);
|
|
}
|
|
|
|
- (CGFloat)bottom {
|
|
return CGRectGetMaxY(_bounds);
|
|
}
|
|
|
|
- (CGFloat)left {
|
|
return CGRectGetMinX(_bounds);
|
|
}
|
|
|
|
- (CGFloat)right {
|
|
return CGRectGetMaxX(_bounds);
|
|
}
|
|
|
|
- (NSString *)description {
|
|
NSMutableString *desc = @"".mutableCopy;
|
|
NSRange range = self.range;
|
|
[desc appendFormat:@"<ASTextLine: %p> row:%ld range:%tu,%tu", self, (long)self.row, range.location, range.length];
|
|
[desc appendFormat:@" position:%@",NSStringFromCGPoint(self.position)];
|
|
[desc appendFormat:@" bounds:%@",NSStringFromCGRect(self.bounds)];
|
|
return desc;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation ASTextRunGlyphRange
|
|
+ (instancetype)rangeWithRange:(NSRange)range drawMode:(ASTextRunGlyphDrawMode)mode NS_RETURNS_RETAINED {
|
|
ASTextRunGlyphRange *one = [self new];
|
|
one.glyphRangeInRun = range;
|
|
one.drawMode = mode;
|
|
return one;
|
|
}
|
|
@end
|