Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: ios/chrome/browser/ui/util/core_text_util.mm

Issue 2588733002: Upstream Chrome on iOS source code [9/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/core_text_util.h"
6
7 #import <UIKit/UIKit.h>
8
9 #include "base/i18n/rtl.h"
10 #include "base/mac/foundation_util.h"
11 #include "base/mac/scoped_nsobject.h"
12 #import "ios/chrome/browser/ui/util/manual_text_framer.h"
13 #import "ios/chrome/browser/ui/util/text_frame.h"
14 #import "ios/chrome/browser/ui/util/unicode_util.h"
15
16 namespace core_text_util {
17
18 namespace {
19 // Returns the range within |string| for which |text_frame|'s glyph information
20 // is non-repeating.
21 CFRange GetValidRangeForTextFrame(CTFrameRef text_frame,
22 NSAttributedString* string) {
23 DCHECK(text_frame);
24 DCHECK(string.length);
25 CFRange range = CFRangeMake(0, 0);
26 bool is_rtl =
27 GetEffectiveWritingDirection(string) == NSWritingDirectionRightToLeft;
28 for (id line_id in base::mac::CFToNSCast(CTFrameGetLines(text_frame))) {
29 CTLineRef line = static_cast<CTLineRef>(line_id);
30 NSArray* runs = base::mac::CFToNSCast(CTLineGetGlyphRuns(line));
31 NSInteger run_idx = is_rtl ? runs.count - 1 : 0;
32 while (run_idx >= 0 && run_idx < static_cast<NSInteger>(runs.count)) {
33 CTRunRef run = static_cast<CTRunRef>(runs[run_idx]);
34 CFRange run_range = CTRunGetStringRange(run);
35 if (run_range.location == range.location + range.length)
36 range.length += run_range.length;
37 else
38 break;
39 run_idx += is_rtl ? -1 : 1;
40 }
41 }
42 return range;
43 }
44 } // namespace
45
46 base::ScopedCFTypeRef<CTFrameRef> CreateTextFrameForStringInBounds(
47 NSAttributedString* string,
48 CGRect bounds) {
49 base::ScopedCFTypeRef<CTFramesetterRef> frame_setter(
50 CTFramesetterCreateWithAttributedString(base::mac::NSToCFCast(string)));
51 DCHECK(frame_setter);
52 base::ScopedCFTypeRef<CGPathRef> path(CGPathCreateWithRect(bounds, nullptr));
53 DCHECK(path);
54 base::ScopedCFTypeRef<CTFrameRef> text_frame(
55 CTFramesetterCreateFrame(frame_setter, CFRangeMake(0, 0), path, nullptr));
56 DCHECK(text_frame);
57 return text_frame;
58 }
59
60 bool IsTextFrameValid(CTFrameRef text_frame,
61 ManualTextFramer* manual_framer,
62 NSAttributedString* string) {
63 DCHECK(text_frame);
64 DCHECK(manual_framer);
65 CFRange visible_range = CTFrameGetVisibleStringRange(text_frame);
66 CFRange valid_range = GetValidRangeForTextFrame(text_frame, string);
67 NSRange unsigned_visible_range;
68 // If |visible_range| has invalid values, return early.
69 if (!base::mac::CFRangeToNSRange(visible_range, &unsigned_visible_range))
70 return false;
71 NSRange manual_range = manual_framer.textFrame.framedRange;
72 return visible_range.location == valid_range.location &&
73 visible_range.length == valid_range.length &&
74 manual_range.length == unsigned_visible_range.length;
75 }
76
77 CGFloat GetTrimmedLineWidth(CTLineRef line) {
78 DCHECK(line);
79 return CTLineGetTypographicBounds(line, nullptr, nullptr, nullptr) -
80 CTLineGetTrailingWhitespaceWidth(line);
81 }
82
83 CGFloat GetRunWidthWithRange(CTRunRef run, CFRange range) {
84 DCHECK(run);
85 CFIndex glyph_count = CTRunGetGlyphCount(run);
86 if (range.location < 0 || range.location >= glyph_count ||
87 range.location + range.length > glyph_count || !range.length) {
88 return 0;
89 }
90 return CTRunGetTypographicBounds(run, range, nullptr, nullptr, nullptr);
91 }
92
93 CGFloat GetGlyphWidth(CTRunRef run, CFIndex glyph_idx) {
94 return GetRunWidthWithRange(run, CFRangeMake(glyph_idx, 1));
95 }
96
97 CFIndex GetGlyphIdxForCharInSet(CTRunRef run,
98 CFRange range,
99 NSAttributedString* string,
100 NSCharacterSet* set) {
101 DCHECK(run);
102 CFIndex glyph_count = CTRunGetGlyphCount(run);
103 DCHECK_LT(range.location, glyph_count);
104 DCHECK_LE(range.location + range.length, glyph_count);
105 DCHECK(string.length);
106 DCHECK(set);
107 BOOL isRTL =
108 GetEffectiveWritingDirection(string) == NSWritingDirectionRightToLeft;
109 CFIndex glyph_idx =
110 isRTL ? range.location + range.length - 1 : range.location;
111 CFIndex string_idx = GetStringIdxForGlyphIdx(run, glyph_idx);
112 while (![set characterIsMember:[string.string characterAtIndex:string_idx]]) {
113 glyph_idx += isRTL ? -1 : 1;
114 string_idx = GetStringIdxForGlyphIdx(run, glyph_idx);
115 if (string_idx == NSNotFound)
116 return kCFNotFound;
117 }
118 return glyph_idx;
119 }
120
121 NSUInteger GetStringIdxForGlyphIdx(CTRunRef run, CFIndex glyph_idx) {
122 DCHECK(run);
123 if (glyph_idx < 0 || glyph_idx >= CTRunGetGlyphCount(run))
124 return NSNotFound;
125 CFIndex string_idx;
126 CTRunGetStringIndices(run, CFRangeMake(glyph_idx, 1), &string_idx);
127 return static_cast<NSUInteger>(string_idx);
128 }
129
130 NSRange GetStringRangeForRun(CTRunRef run) {
131 DCHECK(run);
132 NSRange stringRange;
133 if (base::mac::CFRangeToNSRange(CTRunGetStringRange(run), &stringRange))
134 return stringRange;
135 return NSMakeRange(NSNotFound, 0);
136 }
137
138 void EnumerateAttributesInString(NSAttributedString* string,
139 NSRange range,
140 AttributesBlock block) {
141 DCHECK(string.length);
142 DCHECK_LT(range.location, string.length);
143 DCHECK_LE(range.location + range.length, string.length);
144 DCHECK(block);
145 NSUInteger char_idx = range.location;
146 NSRange effectiveRange = NSMakeRange(0, 0);
147 while (char_idx < range.location + range.length) {
148 NSDictionary* attributes =
149 [string attributesAtIndex:char_idx effectiveRange:&effectiveRange];
150 block(attributes);
151 char_idx += range.length;
152 }
153 }
154
155 CGFloat GetLineHeight(NSAttributedString* string, NSRange range) {
156 __block CGFloat line_height = 0;
157 AttributesBlock block = ^(NSDictionary* attributes) {
158 NSParagraphStyle* style = attributes[NSParagraphStyleAttributeName];
159 CGFloat run_line_height = 0;
160 UIFont* font = attributes[NSFontAttributeName];
161 if (!font)
162 font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
163 DCHECK(font);
164 run_line_height = font.ascender - font.descender;
165 if (style.lineHeightMultiple > 0)
166 run_line_height *= style.lineHeightMultiple;
167 if (style.minimumLineHeight > 0)
168 run_line_height = std::max(run_line_height, style.minimumLineHeight);
169 if (style.maximumLineHeight > 0)
170 run_line_height = std::min(run_line_height, style.maximumLineHeight);
171 line_height = std::max(line_height, run_line_height);
172 };
173 EnumerateAttributesInString(string, range, block);
174 return line_height;
175 }
176
177 CGFloat GetLineSpacing(NSAttributedString* string, NSRange range) {
178 __block CGFloat line_spacing = 0;
179 AttributesBlock block = ^(NSDictionary* attributes) {
180 NSParagraphStyle* style = attributes[NSParagraphStyleAttributeName];
181 line_spacing = std::max(line_spacing, style.lineSpacing);
182 };
183 EnumerateAttributesInString(string, range, block);
184 return line_spacing;
185 }
186
187 NSTextAlignment GetEffectiveTextAlignment(NSAttributedString* string) {
188 DCHECK(string.length);
189 NSTextAlignment alignment = NSTextAlignmentLeft;
190 NSParagraphStyle* style = [string attribute:NSParagraphStyleAttributeName
191 atIndex:0
192 effectiveRange:nullptr];
193 if (style) {
194 alignment = style.alignment;
195 if (alignment == NSTextAlignmentNatural ||
196 alignment == NSTextAlignmentJustified) {
197 NSWritingDirection direction = GetEffectiveWritingDirection(string);
198 alignment = direction == NSWritingDirectionRightToLeft
199 ? NSTextAlignmentRight
200 : NSTextAlignmentLeft;
201 }
202 }
203 return alignment;
204 }
205
206 NSWritingDirection GetEffectiveWritingDirection(NSAttributedString* string) {
207 DCHECK(string.length);
208 // Search for unicode bidirectionality characters within |string|.
209 NSWritingDirection direction =
210 unicode_util::UnicodeWritingDirectionForString(string.string);
211 if (direction == NSWritingDirectionNatural) {
212 // If there are no characters with bidirectionality information, default to
213 // NSWritingDirectionLeftToRight.
214 direction = NSWritingDirectionLeftToRight;
215 }
216 NSParagraphStyle* style = [string attribute:NSParagraphStyleAttributeName
217 atIndex:0
218 effectiveRange:nullptr];
219 if (style && style.baseWritingDirection != NSWritingDirectionNatural) {
220 // Use the NSParagraphStyle's writing direction if specified.
221 direction = style.baseWritingDirection;
222 }
223 return direction;
224 }
225
226 } // namespace core_text_util
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/util/core_text_util.h ('k') | ios/chrome/browser/ui/util/core_text_util_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698