123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- //
- // YYYTextLine.m
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 15/3/3.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import "YYTextLine.h"
- #import "YYTextUtilities.h"
- #import "YYKitMacro.h"
- @implementation YYTextLine {
- CGFloat _firstGlyphPos; // first glyph position for baseline, typically 0.
- }
- + (instancetype)lineWithCTLine:(CTLineRef)CTLine position:(CGPoint)position vertical:(BOOL)isVertical {
- if (!CTLine) return nil;
- YYTextLine *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 = 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 = CFArrayGetValueAtIndex(runs, r);
- CFIndex glyphCount = CTRunGetGlyphCount(run);
- if (glyphCount == 0) continue;
- NSDictionary *attrs = (id)CTRunGetAttributes(run);
- YYTextAttachment *attachment = attrs[YYTextAttachmentAttributeName];
- 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) {
- YY_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 = YYNSRangeFromCFRange(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:@"<YYTextLine: %p> row:%zd range:%tu,%tu",self, self.row, range.location, range.length];
- [desc appendFormat:@" position:%@",NSStringFromCGPoint(self.position)];
- [desc appendFormat:@" bounds:%@",NSStringFromCGRect(self.bounds)];
- return desc;
- }
- @end
- @implementation YYTextRunGlyphRange
- + (instancetype)rangeWithRange:(NSRange)range drawMode:(YYTextRunGlyphDrawMode)mode {
- YYTextRunGlyphRange *one = [self new];
- one.glyphRangeInRun = range;
- one.drawMode = mode;
- return one;
- }
- @end
|