Index: ios/chrome/browser/ui/util/text_frame.mm |
diff --git a/ios/chrome/browser/ui/util/text_frame.mm b/ios/chrome/browser/ui/util/text_frame.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..893a656c2350b4d0c8343471fd29f184a6b881bb |
--- /dev/null |
+++ b/ios/chrome/browser/ui/util/text_frame.mm |
@@ -0,0 +1,146 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/chrome/browser/ui/util/text_frame.h" |
+ |
+#include "base/logging.h" |
+#include "base/mac/foundation_util.h" |
+#import "base/mac/scoped_nsobject.h" |
+ |
+#pragma mark - FramedLine |
+ |
+@implementation FramedLine { |
+ // Backing object for property of the same name. |
+ base::scoped_nsprotocol<id> _line; |
+} |
+ |
+@synthesize stringRange = _stringRange; |
+@synthesize origin = _origin; |
+ |
+- (instancetype)initWithLine:(CTLineRef)line |
+ stringRange:(NSRange)stringRange |
+ origin:(CGPoint)origin { |
+ if ((self = [super init])) { |
+ DCHECK(line); |
+ // CTLines created by ManualTextFramers all have zero for their string range |
+ // locations, but its length should be equal to |stringRange|. |
+ NSRange lineRange; |
+ if (!base::mac::CFRangeToNSRange(CTLineGetStringRange(line), &lineRange)) { |
+ [self release]; |
+ return nil; |
+ } |
+ DCHECK_EQ(lineRange.length, stringRange.length); |
+ _line.reset([static_cast<id>(line) retain]); |
+ _stringRange = stringRange; |
+ _origin = origin; |
+ } |
+ return self; |
+} |
+ |
+- (NSString*)description { |
+ return [NSString stringWithFormat:@"%@ line:%@, stringRange:%@, origin:%@", |
+ [super description], _line.get(), |
+ NSStringFromRange(_stringRange), |
+ NSStringFromCGPoint(_origin)]; |
+} |
+ |
+- (CFIndex)lineOffsetForStringLocation:(NSUInteger)stringLocation { |
+ if (stringLocation < self.stringRange.location || |
+ stringLocation >= self.stringRange.location + self.stringRange.length) { |
+ return kCFNotFound; |
+ } |
+ NSRange lineRange; |
+ if (!base::mac::CFRangeToNSRange(CTLineGetStringRange(self.line), &lineRange)) |
+ return kCFNotFound; |
+ return lineRange.location + (stringLocation - self.stringRange.location); |
+} |
+ |
+#pragma mark Accessors |
+ |
+- (CTLineRef)line { |
+ return static_cast<CTLineRef>(_line.get()); |
+} |
+ |
+@end |
+ |
+#pragma mark - CoreTextTextFrame |
+ |
+@interface CoreTextTextFrame () { |
+ // Backing object for property of the same name. |
+ base::scoped_nsobject<NSAttributedString> _string; |
+ base::scoped_nsprotocol<id> _frame; |
+ base::scoped_nsobject<NSMutableArray> _lines; |
+} |
+ |
+// The CTFrameRef passed on initializaton. |
+@property(nonatomic, readonly) CTFrameRef frame; |
+ |
+// Populates |lines| using |frame|. |
+- (void)createFramedLines; |
+ |
+@end |
+ |
+@implementation CoreTextTextFrame |
+ |
+@synthesize bounds = _bounds; |
+ |
+- (instancetype)initWithString:(NSAttributedString*)string |
+ bounds:(CGRect)bounds |
+ frame:(CTFrameRef)frame { |
+ if ((self = [super self])) { |
+ DCHECK(string.string.length); |
+ _string.reset([string retain]); |
+ _bounds = bounds; |
+ DCHECK(frame); |
+ _frame.reset([static_cast<id>(frame) retain]); |
+ } |
+ return self; |
+} |
+ |
+#pragma mark Accessors |
+ |
+- (NSAttributedString*)string { |
+ return _string.get(); |
+} |
+ |
+- (NSRange)framedRange { |
+ NSRange range; |
+ CFRange cfRange = CTFrameGetVisibleStringRange(self.frame); |
+ if (base::mac::CFRangeToNSRange(cfRange, &range)) |
+ return range; |
+ return NSMakeRange(NSNotFound, 0); |
+} |
+ |
+- (NSArray*)lines { |
+ if (!_lines) |
+ [self createFramedLines]; |
+ return _lines.get(); |
+} |
+ |
+- (CTFrameRef)frame { |
+ return static_cast<CTFrameRef>(_frame.get()); |
+} |
+ |
+#pragma mark Private |
+ |
+- (void)createFramedLines { |
+ NSArray* lines = base::mac::CFToNSCast(CTFrameGetLines(self.frame)); |
+ CGPoint origins[lines.count]; |
+ CTFrameGetLineOrigins(self.frame, CFRangeMake(0, 0), origins); |
+ _lines.reset([[NSMutableArray alloc] initWithCapacity:lines.count]); |
+ for (NSUInteger line_idx = 0; line_idx < lines.count; ++line_idx) { |
+ CTLineRef line = static_cast<CTLineRef>(lines[line_idx]); |
+ NSRange stringRange; |
+ CFRange cfStringRange = CTLineGetStringRange(line); |
+ if (!base::mac::CFRangeToNSRange(cfStringRange, &stringRange)) |
+ break; |
+ base::scoped_nsobject<FramedLine> framedLine([[FramedLine alloc] |
+ initWithLine:line |
+ stringRange:stringRange |
+ origin:origins[line_idx]]); |
+ [_lines addObject:framedLine]; |
+ } |
+} |
+ |
+@end |