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

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

Issue 2580333003: Upstream Chrome on iOS source code [10/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 #include "ios/chrome/browser/ui/util/manual_text_framer.h"
6
7 #include "base/mac/foundation_util.h"
8 #import "base/mac/scoped_nsobject.h"
9 #include "base/time/time.h"
10 #import "ios/chrome/browser/ui/util/core_text_util.h"
11 #import "ios/chrome/browser/ui/util/text_frame.h"
12 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoF ontLoader.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/gtest_mac.h"
15 #include "testing/platform_test.h"
16 #include "url/gurl.h"
17
18 namespace {
19 // Copy of ManualTextFramer's alignment function.
20 enum class AlignmentFunction : short { CEIL = 0, FLOOR };
21 CGFloat AlignValueToPixel(CGFloat value, AlignmentFunction function) {
22 static CGFloat scale = [[UIScreen mainScreen] scale];
23 return function == AlignmentFunction::CEIL ? ceil(value * scale) / scale
24 : floor(value * scale) / scale;
25 }
26
27 class ManualTextFramerTest : public PlatformTest {
28 protected:
29 void SetUp() override {
30 attributes_.reset([[NSMutableDictionary alloc] init]);
31 string_.reset([[NSMutableAttributedString alloc] init]);
32 }
33
34 NSString* text() { return [string_ string]; }
35 NSRange text_range() { return NSMakeRange(0, [string_ length]); }
36 id<TextFrame> text_frame() {
37 return static_cast<id<TextFrame>>(text_frame_.get());
38 }
39
40 void SetText(NSString* text) {
41 DCHECK(text.length);
42 [[string_ mutableString] setString:text];
43 }
44
45 void FrameTextInBounds(CGRect bounds) {
46 base::scoped_nsobject<ManualTextFramer> manual_framer(
47 [[ManualTextFramer alloc] initWithString:string_ inBounds:bounds]);
48 [manual_framer frameText];
49 id frame = [manual_framer textFrame];
50 text_frame_.reset([frame retain]);
51 }
52
53 UIFont* RobotoFontWithSize(CGFloat size) {
54 return [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:size];
55 }
56
57 NSParagraphStyle* CreateParagraphStyle(CGFloat line_height,
58 NSTextAlignment alignment,
59 NSLineBreakMode line_break_mode) {
60 NSMutableParagraphStyle* style =
61 [[[NSMutableParagraphStyle alloc] init] autorelease];
62 style.alignment = alignment;
63 style.lineBreakMode = line_break_mode;
64 style.minimumLineHeight = line_height;
65 style.maximumLineHeight = line_height;
66 return style;
67 }
68
69 NSMutableDictionary* attributes() { return attributes_; }
70
71 void ApplyAttributesForRange(NSRange range) {
72 [string_ setAttributes:attributes_ range:range];
73 }
74
75 void CheckForLineCountAndFramedRange(NSUInteger line_count,
76 NSRange framed_range) {
77 EXPECT_EQ(line_count, text_frame().lines.count);
78 EXPECT_EQ(framed_range.location, text_frame().framedRange.location);
79 EXPECT_EQ(framed_range.length, text_frame().framedRange.length);
80 }
81
82 base::scoped_nsobject<NSMutableDictionary> attributes_;
83 base::scoped_nsobject<NSMutableAttributedString> string_;
84 base::scoped_nsprotocol<id<TextFrame>> text_frame_;
85 };
86
87 // Tests that newline characters cause an attributed string to be laid out on
88 // multiple lines.
89 TEST_F(ManualTextFramerTest, NewlineTest) {
90 SetText(@"line one\nline two\nline three");
91 attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
92 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
93 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
94 ApplyAttributesForRange(text_range());
95 CGRect bounds = CGRectMake(0, 0, 500, 500);
96 FrameTextInBounds(bounds);
97 CheckForLineCountAndFramedRange(3, text_range());
98 }
99
100 // Tests that strings with no spaces fail correctly.
101 TEST_F(ManualTextFramerTest, NoSpacesText) {
102 // "St. Mary's church in the hollow of the white hazel near the the rapid
103 // whirlpool of Llantysilio of the red cave."
104 SetText(
105 @"Llanfair­pwllgwyngyll­gogery­chwyrn­drobwll­llan­tysilio­gogo­goch");
106 attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
107 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
108 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
109 ApplyAttributesForRange(text_range());
110 CGRect bounds = CGRectMake(0, 0, 200, 60);
111 FrameTextInBounds(bounds);
112 CheckForLineCountAndFramedRange(0, NSMakeRange(0, 0));
113 }
114
115 // Tests that multiple newlines are accounted for. Only the first three
116 // newlines should be added to |lines_|.
117 TEST_F(ManualTextFramerTest, MultipleNewlineTest) {
118 SetText(@"\n\n\ntext");
119 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
120 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
121 ApplyAttributesForRange(text_range());
122 CGRect bounds = CGRectMake(0, 0, 500, 60);
123 FrameTextInBounds(bounds);
124 CheckForLineCountAndFramedRange(3, NSMakeRange(0, 3));
125 }
126
127 // Tests that the framed range for text that will be rendered with ligatures is
128 // corresponds with the actual range of the text.
129 TEST_F(ManualTextFramerTest, LigatureTest) {
130 SetText(@"fffi");
131 attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
132 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
133 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
134 ApplyAttributesForRange(text_range());
135 CGRect bounds = CGRectMake(0, 0, 500, 20);
136 FrameTextInBounds(bounds);
137 CheckForLineCountAndFramedRange(1, text_range());
138 }
139
140 // Tests that ManualTextFramer correctly frames Å
141 TEST_F(ManualTextFramerTest, DiacriticTest) {
142 SetText(@"A\u030A");
143 attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
144 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
145 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
146 ApplyAttributesForRange(text_range());
147 CGRect bounds = CGRectMake(0, 0, 500, 20);
148 FrameTextInBounds(bounds);
149 CheckForLineCountAndFramedRange(1, text_range());
150 }
151
152 // String text, attributes, and bounds are chosen to match the "Terms of
153 // Service" text in WelcomeToChromeView, as the text is not properly framed by
154 // CTFrameSetter. http://crbug.com/537212
155 TEST_F(ManualTextFramerTest, TOSTextTest) {
156 CGRect bounds = CGRectMake(0, 0, 300.0, 40.0);
157 NSString* const kTOSLinkText = @"Terms of Service";
158 NSString* const kTOSText =
159 @"By using this application, you agree to Chrome’s Terms of Service.";
160 SetText(kTOSText);
161 attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
162 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
163 20.0, NSTextAlignmentCenter, NSLineBreakByTruncatingTail);
164 attributes()[NSForegroundColorAttributeName] = [UIColor blackColor];
165 ApplyAttributesForRange(text_range());
166 attributes()[NSForegroundColorAttributeName] = [UIColor blueColor];
167 ApplyAttributesForRange([kTOSText rangeOfString:kTOSLinkText]);
168 FrameTextInBounds(bounds);
169 CheckForLineCountAndFramedRange(2, text_range());
170 }
171
172 // Tests that the origin of a left-aligned single line is correct.
173 TEST_F(ManualTextFramerTest, SimpleOriginTest) {
174 SetText(@"test");
175 UIFont* font = RobotoFontWithSize(14.0);
176 attributes()[NSFontAttributeName] = font;
177 CGFloat line_height = 20.0;
178 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
179 line_height, NSTextAlignmentLeft, NSLineBreakByWordWrapping);
180 ApplyAttributesForRange(text_range());
181 CGRect bounds = CGRectMake(0, 0, 500, 21);
182 FrameTextInBounds(bounds);
183 CheckForLineCountAndFramedRange(1, text_range());
184 FramedLine* line = [text_frame().lines firstObject];
185 EXPECT_EQ(0, line.origin.x);
186 EXPECT_EQ(
187 AlignValueToPixel(CGRectGetHeight(bounds) - line_height - font.descender,
188 AlignmentFunction::FLOOR),
189 line.origin.y);
190 }
191
192 // Tests that lines that are laid out in RTL are right aligned.
193 TEST_F(ManualTextFramerTest, OriginRTLTest) {
194 SetText(@"\u0641\u064e\u0628\u064e\u0642\u064e\u064a\u0652\u062a\u064f\u0020"
195 @"\u0645\u064f\u062a\u064e\u0627\u0628\u0650\u0639\u064e\u0627\u064b"
196 @"\u0020\u0028\u0634\u064f\u063a\u0652\u0644\u0650\u064a\u0029\u0020"
197 @"\u0644\u064e\u0639\u064e\u0644\u064e\u0643\u0650\u0020\u062a\u064e"
198 @"\u062a\u064e\u0639\u064e\u0644\u0651\u064e\u0645\u064e\u0020\u0627"
199 @"\u0644\u062d\u0650\u0631\u0652\u0635\u064e\u0020\u0639\u064e\u0644"
200 @"\u064e\u0649\u0020\u0627\u0644\u0648\u064e\u0642\u0652\u062a\u0650"
201 @"\u0020\u002e\u0020\u0641\u064e\u0627\u0644\u062d\u064e\u064a\u064e"
202 @"\u0627\u0629\u064f");
203 attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
204 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
205 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
206 ApplyAttributesForRange(text_range());
207 CGRect bounds = CGRectMake(0, 0, 100.0, 60.0);
208 FrameTextInBounds(bounds);
209 CheckForLineCountAndFramedRange(3, text_range());
210 for (FramedLine* line in text_frame().lines) {
211 CGFloat line_width =
212 AlignValueToPixel(core_text_util::GetTrimmedLineWidth(line.line),
213 AlignmentFunction::CEIL);
214 EXPECT_EQ(CGRectGetMaxX(bounds), line.origin.x + line_width);
215 }
216 }
217
218 TEST_F(ManualTextFramerTest, CJKLineBreakTest) {
219 // Example from our strings. Framer will put “触摸搜索” on one line, and then
220 // fail to frame the second.
221 // clang-format off
222 SetText(@"“触摸搜索”会将所选字词和当前页面(作为上下文)一起发送给 Google 搜索。"
223 @"您可以在设置中停用此功能。");
224 // clang-format on
225 attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
226 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
227 16 * 1.15, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
228 ApplyAttributesForRange(text_range());
229 CGRect bounds = CGRectMake(0, 0, 300.0, 65.0);
230 FrameTextInBounds(bounds);
231 CheckForLineCountAndFramedRange(3, NSMakeRange(0, 53));
232
233 // Example without any space-ish characters:
234 // clang-format off
235 SetText(@"会将所选字词和当前页面(作为上下文)一起发送给Google搜索。"
236 @"您可以在设置中停用此功能。");
237 // clang-format on
238 attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
239 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
240 16 * 1.15, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
241 ApplyAttributesForRange(text_range());
242 FrameTextInBounds(bounds);
243 CheckForLineCountAndFramedRange(2, NSMakeRange(0, 45));
244 }
245
246 // Tests that paragraphs with NSTextAlignmentCenter are actually centered.
247 TEST_F(ManualTextFramerTest, CenterAlignedTest) {
248 SetText(@"xxxx\nyyy\nwww");
249 attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
250 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
251 20.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
252 ApplyAttributesForRange(text_range());
253 CGRect bounds = CGRectMake(0, 0, 200.0, 60.0);
254 FrameTextInBounds(bounds);
255 CheckForLineCountAndFramedRange(3, text_range());
256 for (FramedLine* line in text_frame().lines) {
257 CGFloat line_width =
258 AlignValueToPixel(core_text_util::GetTrimmedLineWidth(line.line),
259 AlignmentFunction::CEIL);
260 EXPECT_EQ(AlignValueToPixel(CGRectGetMidX(bounds) - 0.5 * line_width,
261 AlignmentFunction::FLOOR),
262 line.origin.x);
263 }
264 }
265
266 // Tests that words with a large line height will not be framed if they don't
267 // fit in the bounding height.
268 TEST_F(ManualTextFramerTest, LargeLineHeightTest) {
269 SetText(@"the last word is very LARGE");
270 attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
271 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
272 20.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
273 ApplyAttributesForRange(text_range());
274 attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
275 500.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
276 ApplyAttributesForRange(NSMakeRange(22, 5)); // "LARGE"
277 CGRect bounds = CGRectMake(0, 0, 500, 20.0);
278 FrameTextInBounds(bounds);
279 CheckForLineCountAndFramedRange(1, NSMakeRange(0, 22));
280 }
281
282 // Tests a preexisting error condition in which a BiDi string containing Arabic
283 // is correctly laid out (crbug.com/584549).
284 TEST_F(ManualTextFramerTest, RTLTest) {
285 SetText(@"\u0642\u062F\u0020\u064A\u0633\u062A\u062E\u062F\u0645\u0020\u0047"
286 "\u006F\u006F\u0067\u006C\u0065\u0020\u0043\u0068\u0072\u006F\u006D"
287 "\u0065\u0020\u062E\u062F\u0645\u0627\u062A\u0020\u0627\u0644\u0648"
288 "\u064A\u0628\u0020\u0644\u062A\u062D\u0633\u064A\u0646\u0020\u062A"
289 "\u062C\u0631\u0628\u0629\u0020\u0627\u0644\u062A\u0635\u0641\u062D"
290 "\u002E\u0020\u0648\u064A\u0645\u0643\u0646\u0643\u0020\u0628\u0634"
291 "\u0643\u0644\u0020\u0627\u062E\u062A\u064A\u0627\u0631\u064A\u0020"
292 "\u062A\u0639\u0637\u064A\u0644\u0020\u0647\u0630\u0647\u0020\u0627"
293 "\u0644\u062E\u062F\u0645\u0627\u062A\u002E");
294 attributes()[NSFontAttributeName] = [UIFont systemFontOfSize:20.0];
295 ApplyAttributesForRange(text_range());
296 CGRect bounds = CGRectMake(0, 0, 500, 100);
297 FrameTextInBounds(bounds);
298 CheckForLineCountAndFramedRange(2, text_range());
299 }
300
301 } // namespace
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/util/manual_text_framer.mm ('k') | ios/chrome/browser/ui/util/relaxed_bounds_constraints_hittest.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698