OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/ui/util/text_region_mapper.h" |
| 6 |
| 7 #import <CoreText/CoreText.h> |
| 8 #import <QuartzCore/QuartzCore.h> |
| 9 |
| 10 #include "base/i18n/rtl.h" |
| 11 #include "base/ios/ios_util.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/mac/foundation_util.h" |
| 14 #include "base/mac/scoped_nsobject.h" |
| 15 #include "ios/chrome/browser/ui/ui_util.h" |
| 16 #import "ios/chrome/browser/ui/util/core_text_util.h" |
| 17 #import "ios/chrome/browser/ui/util/manual_text_framer.h" |
| 18 #import "ios/chrome/browser/ui/util/text_frame.h" |
| 19 |
| 20 @interface CoreTextRegionMapper () { |
| 21 // Backing object for property of the same name. |
| 22 base::scoped_nsprotocol<id<TextFrame>> _textFrame; |
| 23 } |
| 24 |
| 25 // The TextFrame used to calculate rects. |
| 26 @property(nonatomic, readonly) id<TextFrame> textFrame; |
| 27 |
| 28 @end |
| 29 |
| 30 @implementation CoreTextRegionMapper |
| 31 - (instancetype)initWithAttributedString:(NSAttributedString*)string |
| 32 bounds:(CGRect)bounds { |
| 33 if ((self = [super init])) { |
| 34 base::ScopedCFTypeRef<CTFrameRef> ctFrame = |
| 35 core_text_util::CreateTextFrameForStringInBounds(string, bounds); |
| 36 base::scoped_nsobject<ManualTextFramer> framer( |
| 37 [[ManualTextFramer alloc] initWithString:string inBounds:bounds]); |
| 38 [framer frameText]; |
| 39 if (core_text_util::IsTextFrameValid(ctFrame, framer, string)) { |
| 40 _textFrame.reset([[CoreTextTextFrame alloc] initWithString:string |
| 41 bounds:bounds |
| 42 frame:ctFrame]); |
| 43 } else { |
| 44 // Use ManualTextFramer if |ctFrame| is invalid. |
| 45 _textFrame.reset([[framer textFrame] retain]); |
| 46 } |
| 47 DCHECK(self.textFrame); |
| 48 } |
| 49 return self; |
| 50 } |
| 51 |
| 52 - (instancetype)init { |
| 53 NOTREACHED(); |
| 54 return nil; |
| 55 } |
| 56 |
| 57 - (id<TextFrame>)textFrame { |
| 58 return _textFrame.get(); |
| 59 } |
| 60 |
| 61 - (NSArray*)rectsForRange:(NSRange)range { |
| 62 NSRange framedRange = self.textFrame.framedRange; |
| 63 if (!range.length || range.location + range.length > framedRange.length) |
| 64 return @[]; |
| 65 |
| 66 NSMutableArray* rects = [NSMutableArray array]; |
| 67 // CoreText uses Quartz coordinates, so they will need to be flipped back to |
| 68 // UIKit-space. |
| 69 CGAffineTransform transformForCoreText = CGAffineTransformScale( |
| 70 CGAffineTransformMakeTranslation(0, self.textFrame.bounds.size.height), |
| 71 1.f, -1.f); |
| 72 |
| 73 CGFloat ascent = 0.0f; // height of text above the baseline. |
| 74 CGFloat descent = 0.0f; // height of text below the baseline. |
| 75 |
| 76 // Find any parts of the link on each line. |
| 77 for (FramedLine* line in self.textFrame.lines) { |
| 78 CGFloat lineWidth = static_cast<CGFloat>( |
| 79 CTLineGetTypographicBounds(line.line, &ascent, &descent, nullptr)); |
| 80 if (!lineWidth) |
| 81 break; |
| 82 |
| 83 NSRange overlap = NSIntersectionRange(range, line.stringRange); |
| 84 if (overlap.length > 0) { |
| 85 // Some of the range is on this line; find where it starts and ends. |
| 86 CFIndex stringOffset = |
| 87 [line lineOffsetForStringLocation:overlap.location]; |
| 88 DCHECK_NE(stringOffset, kCFNotFound); |
| 89 CGFloat start = |
| 90 CTLineGetOffsetForStringIndex(line.line, stringOffset, nullptr); |
| 91 CGFloat end = CTLineGetOffsetForStringIndex( |
| 92 line.line, stringOffset + overlap.length, nullptr); |
| 93 CGRect flippedRangeRect = |
| 94 CGRectMake(line.origin.x + start, |
| 95 line.origin.y - descent, // Lower extent of text. |
| 96 end - start, // Length of link text. |
| 97 ascent + descent); // Total height of text. |
| 98 // Flip to UIKit coordinates. |
| 99 CGRect rangeRect = |
| 100 CGRectApplyAffineTransform(flippedRangeRect, transformForCoreText); |
| 101 [rects addObject:[NSValue valueWithCGRect:rangeRect]]; |
| 102 } |
| 103 } |
| 104 return rects; |
| 105 } |
| 106 |
| 107 @end |
OLD | NEW |