| Index: ios/chrome/browser/ui/util/text_region_mapper.mm
|
| diff --git a/ios/chrome/browser/ui/util/text_region_mapper.mm b/ios/chrome/browser/ui/util/text_region_mapper.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f9c25f08b1e3cc47de6469f89c05f8ca1bbcd45f
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/util/text_region_mapper.mm
|
| @@ -0,0 +1,107 @@
|
| +// 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_region_mapper.h"
|
| +
|
| +#import <CoreText/CoreText.h>
|
| +#import <QuartzCore/QuartzCore.h>
|
| +
|
| +#include "base/i18n/rtl.h"
|
| +#include "base/ios/ios_util.h"
|
| +#include "base/logging.h"
|
| +#include "base/mac/foundation_util.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +#include "ios/chrome/browser/ui/ui_util.h"
|
| +#import "ios/chrome/browser/ui/util/core_text_util.h"
|
| +#import "ios/chrome/browser/ui/util/manual_text_framer.h"
|
| +#import "ios/chrome/browser/ui/util/text_frame.h"
|
| +
|
| +@interface CoreTextRegionMapper () {
|
| + // Backing object for property of the same name.
|
| + base::scoped_nsprotocol<id<TextFrame>> _textFrame;
|
| +}
|
| +
|
| +// The TextFrame used to calculate rects.
|
| +@property(nonatomic, readonly) id<TextFrame> textFrame;
|
| +
|
| +@end
|
| +
|
| +@implementation CoreTextRegionMapper
|
| +- (instancetype)initWithAttributedString:(NSAttributedString*)string
|
| + bounds:(CGRect)bounds {
|
| + if ((self = [super init])) {
|
| + base::ScopedCFTypeRef<CTFrameRef> ctFrame =
|
| + core_text_util::CreateTextFrameForStringInBounds(string, bounds);
|
| + base::scoped_nsobject<ManualTextFramer> framer(
|
| + [[ManualTextFramer alloc] initWithString:string inBounds:bounds]);
|
| + [framer frameText];
|
| + if (core_text_util::IsTextFrameValid(ctFrame, framer, string)) {
|
| + _textFrame.reset([[CoreTextTextFrame alloc] initWithString:string
|
| + bounds:bounds
|
| + frame:ctFrame]);
|
| + } else {
|
| + // Use ManualTextFramer if |ctFrame| is invalid.
|
| + _textFrame.reset([[framer textFrame] retain]);
|
| + }
|
| + DCHECK(self.textFrame);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (instancetype)init {
|
| + NOTREACHED();
|
| + return nil;
|
| +}
|
| +
|
| +- (id<TextFrame>)textFrame {
|
| + return _textFrame.get();
|
| +}
|
| +
|
| +- (NSArray*)rectsForRange:(NSRange)range {
|
| + NSRange framedRange = self.textFrame.framedRange;
|
| + if (!range.length || range.location + range.length > framedRange.length)
|
| + return @[];
|
| +
|
| + NSMutableArray* rects = [NSMutableArray array];
|
| + // CoreText uses Quartz coordinates, so they will need to be flipped back to
|
| + // UIKit-space.
|
| + CGAffineTransform transformForCoreText = CGAffineTransformScale(
|
| + CGAffineTransformMakeTranslation(0, self.textFrame.bounds.size.height),
|
| + 1.f, -1.f);
|
| +
|
| + CGFloat ascent = 0.0f; // height of text above the baseline.
|
| + CGFloat descent = 0.0f; // height of text below the baseline.
|
| +
|
| + // Find any parts of the link on each line.
|
| + for (FramedLine* line in self.textFrame.lines) {
|
| + CGFloat lineWidth = static_cast<CGFloat>(
|
| + CTLineGetTypographicBounds(line.line, &ascent, &descent, nullptr));
|
| + if (!lineWidth)
|
| + break;
|
| +
|
| + NSRange overlap = NSIntersectionRange(range, line.stringRange);
|
| + if (overlap.length > 0) {
|
| + // Some of the range is on this line; find where it starts and ends.
|
| + CFIndex stringOffset =
|
| + [line lineOffsetForStringLocation:overlap.location];
|
| + DCHECK_NE(stringOffset, kCFNotFound);
|
| + CGFloat start =
|
| + CTLineGetOffsetForStringIndex(line.line, stringOffset, nullptr);
|
| + CGFloat end = CTLineGetOffsetForStringIndex(
|
| + line.line, stringOffset + overlap.length, nullptr);
|
| + CGRect flippedRangeRect =
|
| + CGRectMake(line.origin.x + start,
|
| + line.origin.y - descent, // Lower extent of text.
|
| + end - start, // Length of link text.
|
| + ascent + descent); // Total height of text.
|
| + // Flip to UIKit coordinates.
|
| + CGRect rangeRect =
|
| + CGRectApplyAffineTransform(flippedRangeRect, transformForCoreText);
|
| + [rects addObject:[NSValue valueWithCGRect:rangeRect]];
|
| + }
|
| + }
|
| + return rects;
|
| +}
|
| +
|
| +@end
|
|
|