• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <iostream>
18 
19 #include "flutter/fml/logging.h"
20 #include "render_test.h"
21 #include "third_party/icu/source/common/unicode/unistr.h"
22 #include "third_party/skia/include/core/SkColor.h"
23 #include "third_party/skia/include/core/SkPath.h"
24 #include "txt/font_style.h"
25 #include "txt/font_weight.h"
26 #include "txt/paragraph_builder_txt.h"
27 #include "txt/paragraph_txt.h"
28 #include "txt/placeholder_run.h"
29 #include "txt_test_utils.h"
30 
31 #define DISABLE_ON_WINDOWS(TEST) DISABLE_TEST_WINDOWS(TEST)
32 
33 namespace txt {
34 
35 using ParagraphTest = RenderTest;
36 
TEST_F(ParagraphTest,SimpleParagraph)37 TEST_F(ParagraphTest, SimpleParagraph) {
38   const char* text = "Hello World Text Dialog";
39   auto icu_text = icu::UnicodeString::fromUTF8(text);
40   std::u16string u16_text(icu_text.getBuffer(),
41                           icu_text.getBuffer() + icu_text.length());
42 
43   txt::ParagraphStyle paragraph_style;
44   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
45 
46   txt::TextStyle text_style;
47   // We must supply a font here, as the default is Arial, and we do not
48   // include Arial in our test fonts as it is proprietary. We want it to
49   // be Arial default though as it is one of the most common fonts on host
50   // platforms. On real devices/apps, Arial should be able to be resolved.
51   text_style.font_families = std::vector<std::string>(1, "Roboto");
52   text_style.color = SK_ColorBLACK;
53   builder.PushStyle(text_style);
54   builder.AddText(u16_text);
55 
56   builder.Pop();
57 
58   auto paragraph = BuildParagraph(builder);
59   paragraph->Layout(GetTestCanvasWidth());
60 
61   paragraph->Paint(GetCanvas(), 10.0, 15.0);
62 
63   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
64   for (size_t i = 0; i < u16_text.length(); i++) {
65     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
66   }
67   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
68   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
69   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
70   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
71   ASSERT_TRUE(Snapshot());
72 }
73 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderParagraph))74 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderParagraph)) {
75   const char* text = "012 34";
76   auto icu_text = icu::UnicodeString::fromUTF8(text);
77   std::u16string u16_text(icu_text.getBuffer(),
78                           icu_text.getBuffer() + icu_text.length());
79 
80   txt::ParagraphStyle paragraph_style;
81   paragraph_style.max_lines = 14;
82   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
83 
84   txt::TextStyle text_style;
85   text_style.font_families = std::vector<std::string>(1, "Roboto");
86   text_style.font_size = 26;
87   text_style.letter_spacing = 1;
88   text_style.word_spacing = 5;
89   text_style.color = SK_ColorBLACK;
90   text_style.height = 1;
91   text_style.decoration = TextDecoration::kUnderline;
92   text_style.decoration_color = SK_ColorBLACK;
93   builder.PushStyle(text_style);
94 
95   builder.AddText(u16_text);
96 
97   txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
98                                       TextBaseline::kAlphabetic, 0);
99   builder.AddPlaceholder(placeholder_run);
100 
101   builder.AddText(u16_text);
102 
103   builder.AddPlaceholder(placeholder_run);
104   txt::PlaceholderRun placeholder_run2(5, 50, PlaceholderAlignment::kBaseline,
105                                        TextBaseline::kAlphabetic, 50);
106   builder.AddPlaceholder(placeholder_run2);
107   builder.AddPlaceholder(placeholder_run);
108   builder.AddPlaceholder(placeholder_run2);
109   builder.AddText(u16_text);
110   builder.AddPlaceholder(placeholder_run2);
111 
112   builder.AddText(u16_text);
113   builder.AddText(u16_text);
114   builder.AddPlaceholder(placeholder_run2);
115   builder.AddPlaceholder(placeholder_run2);
116   builder.AddPlaceholder(placeholder_run2);
117   builder.AddPlaceholder(placeholder_run2);
118   builder.AddPlaceholder(placeholder_run2);
119   builder.AddPlaceholder(placeholder_run);
120   builder.AddText(u16_text);
121   builder.AddText(u16_text);
122   builder.AddText(u16_text);
123   builder.AddText(u16_text);
124   builder.AddText(u16_text);
125   builder.AddPlaceholder(placeholder_run2);
126   builder.AddPlaceholder(placeholder_run);
127   builder.AddText(u16_text);
128   builder.AddText(u16_text);
129 
130   builder.Pop();
131 
132   auto paragraph = BuildParagraph(builder);
133   paragraph->Layout(GetTestCanvasWidth());
134 
135   paragraph->Paint(GetCanvas(), 0, 0);
136 
137   SkPaint paint;
138   paint.setStyle(SkPaint::kStroke_Style);
139   paint.setAntiAlias(true);
140   paint.setStrokeWidth(1);
141 
142   Paragraph::RectHeightStyle rect_height_style =
143       Paragraph::RectHeightStyle::kTight;
144   Paragraph::RectWidthStyle rect_width_style =
145       Paragraph::RectWidthStyle::kTight;
146   paint.setColor(SK_ColorRED);
147   std::vector<txt::Paragraph::TextBox> boxes =
148       paragraph->GetRectsForRange(0, 3, rect_height_style, rect_width_style);
149   for (size_t i = 0; i < boxes.size(); ++i) {
150     GetCanvas()->drawRect(boxes[i].rect, paint);
151   }
152   // ASSERT_TRUE(Snapshot());
153   EXPECT_EQ(boxes.size(), 1ull);
154 
155   paint.setColor(SK_ColorGREEN);
156   boxes =
157       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
158   for (size_t i = 0; i < boxes.size(); ++i) {
159     GetCanvas()->drawRect(boxes[i].rect, paint);
160   }
161   EXPECT_EQ(boxes.size(), 1ull);
162 
163   paint.setColor(SK_ColorRED);
164   boxes = paragraph->GetRectsForPlaceholders();
165   for (size_t i = 0; i < boxes.size(); ++i) {
166     GetCanvas()->drawRect(boxes[i].rect, paint);
167   }
168 
169   paint.setColor(SK_ColorBLUE);
170   boxes =
171       paragraph->GetRectsForRange(4, 17, rect_height_style, rect_width_style);
172   for (size_t i = 0; i < boxes.size(); ++i) {
173     GetCanvas()->drawRect(boxes[i].rect, paint);
174   }
175   EXPECT_EQ(boxes.size(), 7ull);
176   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 90.921875);
177   EXPECT_FLOAT_EQ(boxes[1].rect.top(), 50);
178   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 140.92188);
179   EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 100);
180 
181   EXPECT_FLOAT_EQ(boxes[3].rect.left(), 231.34375);
182   EXPECT_FLOAT_EQ(boxes[3].rect.top(), 50);
183   EXPECT_FLOAT_EQ(boxes[3].rect.right(), 231.34375 + 50);
184   EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 100);
185 
186   EXPECT_FLOAT_EQ(boxes[4].rect.left(), 281.34375);
187   EXPECT_FLOAT_EQ(boxes[4].rect.top(), 0);
188   EXPECT_FLOAT_EQ(boxes[4].rect.right(), 281.34375 + 5);
189   EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 50);
190 
191   EXPECT_FLOAT_EQ(boxes[6].rect.left(), 336.34375);
192   EXPECT_FLOAT_EQ(boxes[6].rect.top(), 0);
193   EXPECT_FLOAT_EQ(boxes[6].rect.right(), 336.34375 + 5);
194   EXPECT_FLOAT_EQ(boxes[6].rect.bottom(), 50);
195 
196   ASSERT_TRUE(Snapshot());
197 }
198 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderBaselineParagraph))199 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBaselineParagraph)) {
200   const char* text = "012 34";
201   auto icu_text = icu::UnicodeString::fromUTF8(text);
202   std::u16string u16_text(icu_text.getBuffer(),
203                           icu_text.getBuffer() + icu_text.length());
204 
205   txt::ParagraphStyle paragraph_style;
206   paragraph_style.max_lines = 14;
207   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
208 
209   txt::TextStyle text_style;
210   text_style.font_families = std::vector<std::string>(1, "Roboto");
211   text_style.font_size = 26;
212   text_style.letter_spacing = 1;
213   text_style.word_spacing = 5;
214   text_style.color = SK_ColorBLACK;
215   text_style.height = 1;
216   text_style.decoration = TextDecoration::kUnderline;
217   text_style.decoration_color = SK_ColorBLACK;
218   builder.PushStyle(text_style);
219 
220   builder.AddText(u16_text);
221 
222   txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBaseline,
223                                       TextBaseline::kAlphabetic, 38.34734);
224   builder.AddPlaceholder(placeholder_run);
225 
226   builder.AddText(u16_text);
227 
228   builder.Pop();
229 
230   auto paragraph = BuildParagraph(builder);
231   paragraph->Layout(GetTestCanvasWidth());
232 
233   paragraph->Paint(GetCanvas(), 0, 0);
234 
235   SkPaint paint;
236   paint.setStyle(SkPaint::kStroke_Style);
237   paint.setAntiAlias(true);
238   paint.setStrokeWidth(1);
239 
240   Paragraph::RectHeightStyle rect_height_style =
241       Paragraph::RectHeightStyle::kTight;
242   Paragraph::RectWidthStyle rect_width_style =
243       Paragraph::RectWidthStyle::kTight;
244   paint.setColor(SK_ColorRED);
245   std::vector<txt::Paragraph::TextBox> boxes =
246       paragraph->GetRectsForPlaceholders();
247   for (size_t i = 0; i < boxes.size(); ++i) {
248     GetCanvas()->drawRect(boxes[i].rect, paint);
249   }
250   EXPECT_EQ(boxes.size(), 1ull);
251   // Verify the box is in the right place
252   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875);
253   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
254   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188);
255   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
256 
257   paint.setColor(SK_ColorBLUE);
258   boxes =
259       paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
260   for (size_t i = 0; i < boxes.size(); ++i) {
261     GetCanvas()->drawRect(boxes[i].rect, paint);
262   }
263   EXPECT_EQ(boxes.size(), 1ull);
264   // Verify the other text didn't just shift to accomodate it.
265   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219);
266   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 14.226246);
267   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875);
268   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44.694996);
269 
270   ASSERT_TRUE(Snapshot());
271 }
272 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderAboveBaselineParagraph))273 TEST_F(ParagraphTest,
274        DISABLE_ON_WINDOWS(InlinePlaceholderAboveBaselineParagraph)) {
275   const char* text = "012 34";
276   auto icu_text = icu::UnicodeString::fromUTF8(text);
277   std::u16string u16_text(icu_text.getBuffer(),
278                           icu_text.getBuffer() + icu_text.length());
279 
280   txt::ParagraphStyle paragraph_style;
281   paragraph_style.max_lines = 14;
282   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
283 
284   txt::TextStyle text_style;
285   text_style.font_families = std::vector<std::string>(1, "Roboto");
286   text_style.font_size = 26;
287   text_style.letter_spacing = 1;
288   text_style.word_spacing = 5;
289   text_style.color = SK_ColorBLACK;
290   text_style.height = 1;
291   text_style.decoration = TextDecoration::kUnderline;
292   text_style.decoration_color = SK_ColorBLACK;
293   builder.PushStyle(text_style);
294 
295   builder.AddText(u16_text);
296 
297   txt::PlaceholderRun placeholder_run(55, 50,
298                                       PlaceholderAlignment::kAboveBaseline,
299                                       TextBaseline::kAlphabetic, 903129.129308);
300   builder.AddPlaceholder(placeholder_run);
301 
302   builder.AddText(u16_text);
303 
304   builder.Pop();
305 
306   auto paragraph = BuildParagraph(builder);
307   paragraph->Layout(GetTestCanvasWidth());
308 
309   paragraph->Paint(GetCanvas(), 0, 0);
310 
311   SkPaint paint;
312   paint.setStyle(SkPaint::kStroke_Style);
313   paint.setAntiAlias(true);
314   paint.setStrokeWidth(1);
315 
316   Paragraph::RectHeightStyle rect_height_style =
317       Paragraph::RectHeightStyle::kTight;
318   Paragraph::RectWidthStyle rect_width_style =
319       Paragraph::RectWidthStyle::kTight;
320   paint.setColor(SK_ColorRED);
321   std::vector<txt::Paragraph::TextBox> boxes =
322       paragraph->GetRectsForPlaceholders();
323   for (size_t i = 0; i < boxes.size(); ++i) {
324     GetCanvas()->drawRect(boxes[i].rect, paint);
325   }
326   EXPECT_EQ(boxes.size(), 1ull);
327   // Verify the box is in the right place
328   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875);
329   EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.34765625);
330   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188);
331   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 49.652344);
332 
333   paint.setColor(SK_ColorBLUE);
334   boxes =
335       paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
336   for (size_t i = 0; i < boxes.size(); ++i) {
337     GetCanvas()->drawRect(boxes[i].rect, paint);
338   }
339   EXPECT_EQ(boxes.size(), 1ull);
340   // Verify the other text didn't just shift to accomodate it.
341   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219);
342   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 25.53125);
343   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875);
344   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 56);
345 
346   ASSERT_TRUE(Snapshot());
347 }
348 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderBelowBaselineParagraph))349 TEST_F(ParagraphTest,
350        DISABLE_ON_WINDOWS(InlinePlaceholderBelowBaselineParagraph)) {
351   const char* text = "012 34";
352   auto icu_text = icu::UnicodeString::fromUTF8(text);
353   std::u16string u16_text(icu_text.getBuffer(),
354                           icu_text.getBuffer() + icu_text.length());
355 
356   txt::ParagraphStyle paragraph_style;
357   paragraph_style.max_lines = 14;
358   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
359 
360   txt::TextStyle text_style;
361   text_style.font_families = std::vector<std::string>(1, "Roboto");
362   text_style.font_size = 26;
363   text_style.letter_spacing = 1;
364   text_style.word_spacing = 5;
365   text_style.color = SK_ColorBLACK;
366   text_style.height = 1;
367   text_style.decoration = TextDecoration::kUnderline;
368   text_style.decoration_color = SK_ColorBLACK;
369   builder.PushStyle(text_style);
370 
371   builder.AddText(u16_text);
372 
373   txt::PlaceholderRun placeholder_run(55, 50,
374                                       PlaceholderAlignment::kBelowBaseline,
375                                       TextBaseline::kAlphabetic, 903129.129308);
376   builder.AddPlaceholder(placeholder_run);
377 
378   builder.AddText(u16_text);
379 
380   builder.Pop();
381 
382   auto paragraph = BuildParagraph(builder);
383   paragraph->Layout(GetTestCanvasWidth());
384 
385   paragraph->Paint(GetCanvas(), 0, 0);
386 
387   SkPaint paint;
388   paint.setStyle(SkPaint::kStroke_Style);
389   paint.setAntiAlias(true);
390   paint.setStrokeWidth(1);
391 
392   Paragraph::RectHeightStyle rect_height_style =
393       Paragraph::RectHeightStyle::kTight;
394   Paragraph::RectWidthStyle rect_width_style =
395       Paragraph::RectWidthStyle::kTight;
396   paint.setColor(SK_ColorRED);
397   std::vector<txt::Paragraph::TextBox> boxes =
398       paragraph->GetRectsForPlaceholders();
399   for (size_t i = 0; i < boxes.size(); ++i) {
400     GetCanvas()->drawRect(boxes[i].rect, paint);
401   }
402   EXPECT_EQ(boxes.size(), 1ull);
403   // Verify the box is in the right place
404   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875);
405   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 24);
406   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188);
407   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
408 
409   paint.setColor(SK_ColorBLUE);
410   boxes =
411       paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
412   for (size_t i = 0; i < boxes.size(); ++i) {
413     GetCanvas()->drawRect(boxes[i].rect, paint);
414   }
415   EXPECT_EQ(boxes.size(), 1ull);
416   // Verify the other text didn't just shift to accomodate it.
417   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219);
418   EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.12109375);
419   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875);
420   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 30.347656);
421 
422   ASSERT_TRUE(Snapshot());
423 }
424 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderBottomParagraph))425 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBottomParagraph)) {
426   const char* text = "012 34";
427   auto icu_text = icu::UnicodeString::fromUTF8(text);
428   std::u16string u16_text(icu_text.getBuffer(),
429                           icu_text.getBuffer() + icu_text.length());
430 
431   txt::ParagraphStyle paragraph_style;
432   paragraph_style.max_lines = 14;
433   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
434 
435   txt::TextStyle text_style;
436   text_style.font_families = std::vector<std::string>(1, "Roboto");
437   text_style.font_size = 26;
438   text_style.letter_spacing = 1;
439   text_style.word_spacing = 5;
440   text_style.color = SK_ColorBLACK;
441   text_style.height = 1;
442   text_style.decoration = TextDecoration::kUnderline;
443   text_style.decoration_color = SK_ColorBLACK;
444   builder.PushStyle(text_style);
445 
446   builder.AddText(u16_text);
447 
448   txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBottom,
449                                       TextBaseline::kAlphabetic, 0);
450   builder.AddPlaceholder(placeholder_run);
451 
452   builder.AddText(u16_text);
453 
454   builder.Pop();
455 
456   auto paragraph = BuildParagraph(builder);
457   paragraph->Layout(GetTestCanvasWidth());
458 
459   paragraph->Paint(GetCanvas(), 0, 0);
460 
461   SkPaint paint;
462   paint.setStyle(SkPaint::kStroke_Style);
463   paint.setAntiAlias(true);
464   paint.setStrokeWidth(1);
465 
466   Paragraph::RectHeightStyle rect_height_style =
467       Paragraph::RectHeightStyle::kTight;
468   Paragraph::RectWidthStyle rect_width_style =
469       Paragraph::RectWidthStyle::kTight;
470   paint.setColor(SK_ColorRED);
471   std::vector<txt::Paragraph::TextBox> boxes =
472       paragraph->GetRectsForPlaceholders();
473   for (size_t i = 0; i < boxes.size(); ++i) {
474     GetCanvas()->drawRect(boxes[i].rect, paint);
475   }
476   EXPECT_EQ(boxes.size(), 1ull);
477   // Verify the box is in the right place
478   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875);
479   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
480   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188);
481   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
482 
483   paint.setColor(SK_ColorBLUE);
484   boxes =
485       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
486   for (size_t i = 0; i < boxes.size(); ++i) {
487     GetCanvas()->drawRect(boxes[i].rect, paint);
488   }
489   EXPECT_EQ(boxes.size(), 1ull);
490   // Verify the other text didn't just shift to accomodate it.
491   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0.5);
492   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 19.53125);
493   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.097656);
494   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
495 
496   ASSERT_TRUE(Snapshot());
497 }
498 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderTopParagraph))499 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderTopParagraph)) {
500   const char* text = "012 34";
501   auto icu_text = icu::UnicodeString::fromUTF8(text);
502   std::u16string u16_text(icu_text.getBuffer(),
503                           icu_text.getBuffer() + icu_text.length());
504 
505   txt::ParagraphStyle paragraph_style;
506   paragraph_style.max_lines = 14;
507   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
508 
509   txt::TextStyle text_style;
510   text_style.font_families = std::vector<std::string>(1, "Roboto");
511   text_style.font_size = 26;
512   text_style.letter_spacing = 1;
513   text_style.word_spacing = 5;
514   text_style.color = SK_ColorBLACK;
515   text_style.height = 1;
516   text_style.decoration = TextDecoration::kUnderline;
517   text_style.decoration_color = SK_ColorBLACK;
518   builder.PushStyle(text_style);
519 
520   builder.AddText(u16_text);
521 
522   txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kTop,
523                                       TextBaseline::kAlphabetic, 0);
524   builder.AddPlaceholder(placeholder_run);
525 
526   builder.AddText(u16_text);
527 
528   builder.Pop();
529 
530   auto paragraph = BuildParagraph(builder);
531   paragraph->Layout(GetTestCanvasWidth());
532 
533   paragraph->Paint(GetCanvas(), 0, 0);
534 
535   SkPaint paint;
536   paint.setStyle(SkPaint::kStroke_Style);
537   paint.setAntiAlias(true);
538   paint.setStrokeWidth(1);
539 
540   Paragraph::RectHeightStyle rect_height_style =
541       Paragraph::RectHeightStyle::kTight;
542   Paragraph::RectWidthStyle rect_width_style =
543       Paragraph::RectWidthStyle::kTight;
544   paint.setColor(SK_ColorRED);
545   std::vector<txt::Paragraph::TextBox> boxes =
546       paragraph->GetRectsForPlaceholders();
547   for (size_t i = 0; i < boxes.size(); ++i) {
548     GetCanvas()->drawRect(boxes[i].rect, paint);
549   }
550   EXPECT_EQ(boxes.size(), 1ull);
551   // Verify the box is in the right place
552   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875);
553   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
554   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188);
555   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
556 
557   paint.setColor(SK_ColorBLUE);
558   boxes =
559       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
560   for (size_t i = 0; i < boxes.size(); ++i) {
561     GetCanvas()->drawRect(boxes[i].rect, paint);
562   }
563   EXPECT_EQ(boxes.size(), 1ull);
564   // Verify the other text didn't just shift to accomodate it.
565   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0.5);
566   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
567   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.097656);
568   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 30.46875);
569 
570   ASSERT_TRUE(Snapshot());
571 }
572 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderMiddleParagraph))573 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderMiddleParagraph)) {
574   const char* text = "012 34";
575   auto icu_text = icu::UnicodeString::fromUTF8(text);
576   std::u16string u16_text(icu_text.getBuffer(),
577                           icu_text.getBuffer() + icu_text.length());
578 
579   txt::ParagraphStyle paragraph_style;
580   paragraph_style.max_lines = 14;
581   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
582 
583   txt::TextStyle text_style;
584   text_style.font_families = std::vector<std::string>(1, "Roboto");
585   text_style.font_size = 26;
586   text_style.letter_spacing = 1;
587   text_style.word_spacing = 5;
588   text_style.color = SK_ColorBLACK;
589   text_style.height = 1;
590   text_style.decoration = TextDecoration::kUnderline;
591   text_style.decoration_color = SK_ColorBLACK;
592   builder.PushStyle(text_style);
593 
594   builder.AddText(u16_text);
595 
596   txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kMiddle,
597                                       TextBaseline::kAlphabetic, 0);
598   builder.AddPlaceholder(placeholder_run);
599 
600   builder.AddText(u16_text);
601 
602   builder.Pop();
603 
604   auto paragraph = BuildParagraph(builder);
605   paragraph->Layout(GetTestCanvasWidth());
606 
607   paragraph->Paint(GetCanvas(), 0, 0);
608 
609   SkPaint paint;
610   paint.setStyle(SkPaint::kStroke_Style);
611   paint.setAntiAlias(true);
612   paint.setStrokeWidth(1);
613 
614   Paragraph::RectHeightStyle rect_height_style =
615       Paragraph::RectHeightStyle::kTight;
616   Paragraph::RectWidthStyle rect_width_style =
617       Paragraph::RectWidthStyle::kTight;
618   paint.setColor(SK_ColorRED);
619   std::vector<txt::Paragraph::TextBox> boxes =
620       paragraph->GetRectsForPlaceholders();
621   for (size_t i = 0; i < boxes.size(); ++i) {
622     GetCanvas()->drawRect(boxes[i].rect, paint);
623   }
624   EXPECT_EQ(boxes.size(), 1ull);
625   // Verify the box is in the right place
626   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875);
627   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
628   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188);
629   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
630 
631   paint.setColor(SK_ColorBLUE);
632   boxes =
633       paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
634   for (size_t i = 0; i < boxes.size(); ++i) {
635     GetCanvas()->drawRect(boxes[i].rect, paint);
636   }
637   EXPECT_EQ(boxes.size(), 1ull);
638   // Verify the other text didn't just shift to accomodate it.
639   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219);
640   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 9.765625);
641   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875);
642   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 40.234375);
643 
644   ASSERT_TRUE(Snapshot());
645 }
646 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderIdeographicBaselineParagraph))647 TEST_F(ParagraphTest,
648        DISABLE_ON_WINDOWS(InlinePlaceholderIdeographicBaselineParagraph)) {
649   const char* text = "給能上目秘使";
650   auto icu_text = icu::UnicodeString::fromUTF8(text);
651   std::u16string u16_text(icu_text.getBuffer(),
652                           icu_text.getBuffer() + icu_text.length());
653 
654   txt::ParagraphStyle paragraph_style;
655   paragraph_style.max_lines = 14;
656   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
657 
658   txt::TextStyle text_style;
659   text_style.font_families = std::vector<std::string>(1, "Source Han Serif CN");
660   text_style.font_size = 26;
661   text_style.letter_spacing = 1;
662   text_style.word_spacing = 5;
663   text_style.color = SK_ColorBLACK;
664   text_style.height = 1;
665   text_style.decoration = TextDecoration::kUnderline;
666   text_style.decoration_color = SK_ColorBLACK;
667   builder.PushStyle(text_style);
668 
669   builder.AddText(u16_text);
670 
671   txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBaseline,
672                                       TextBaseline::kIdeographic, 38.34734);
673   builder.AddPlaceholder(placeholder_run);
674 
675   builder.AddText(u16_text);
676 
677   builder.Pop();
678 
679   auto paragraph = BuildParagraph(builder);
680   paragraph->Layout(GetTestCanvasWidth());
681 
682   paragraph->Paint(GetCanvas(), 0, 0);
683 
684   SkPaint paint;
685   paint.setStyle(SkPaint::kStroke_Style);
686   paint.setAntiAlias(true);
687   paint.setStrokeWidth(1);
688 
689   Paragraph::RectHeightStyle rect_height_style =
690       Paragraph::RectHeightStyle::kTight;
691   Paragraph::RectWidthStyle rect_width_style =
692       Paragraph::RectWidthStyle::kTight;
693   paint.setColor(SK_ColorRED);
694   std::vector<txt::Paragraph::TextBox> boxes =
695       paragraph->GetRectsForPlaceholders();
696   for (size_t i = 0; i < boxes.size(); ++i) {
697     GetCanvas()->drawRect(boxes[i].rect, paint);
698   }
699   EXPECT_EQ(boxes.size(), 1ull);
700   // Verify the box is in the right place
701   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 162.5);
702   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
703   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 217.5);
704   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
705 
706   paint.setColor(SK_ColorBLUE);
707   boxes =
708       paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
709   for (size_t i = 0; i < boxes.size(); ++i) {
710     GetCanvas()->drawRect(boxes[i].rect, paint);
711   }
712   EXPECT_EQ(boxes.size(), 1ull);
713   // Verify the other text didn't just shift to accomodate it.
714   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 135.5);
715   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 4.7033391);
716   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 162.5);
717   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 42.065342);
718 
719   ASSERT_TRUE(Snapshot());
720 }
721 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderBreakParagraph))722 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBreakParagraph)) {
723   const char* text = "012 34";
724   auto icu_text = icu::UnicodeString::fromUTF8(text);
725   std::u16string u16_text(icu_text.getBuffer(),
726                           icu_text.getBuffer() + icu_text.length());
727 
728   txt::ParagraphStyle paragraph_style;
729   paragraph_style.max_lines = 14;
730   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
731 
732   txt::TextStyle text_style;
733   text_style.font_families = std::vector<std::string>(1, "Roboto");
734   text_style.font_size = 26;
735   text_style.letter_spacing = 1;
736   text_style.word_spacing = 5;
737   text_style.color = SK_ColorBLACK;
738   text_style.height = 1;
739   text_style.decoration = TextDecoration::kUnderline;
740   text_style.decoration_color = SK_ColorBLACK;
741   builder.PushStyle(text_style);
742 
743   builder.AddText(u16_text);
744 
745   txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
746                                       TextBaseline::kAlphabetic, 50);
747   txt::PlaceholderRun placeholder_run2(25, 25, PlaceholderAlignment::kBaseline,
748                                        TextBaseline::kAlphabetic, 12.5);
749   builder.AddPlaceholder(placeholder_run);
750   builder.AddPlaceholder(placeholder_run);
751   builder.AddPlaceholder(placeholder_run);
752   builder.AddPlaceholder(placeholder_run2);
753   builder.AddPlaceholder(placeholder_run);
754   builder.AddText(u16_text);
755   builder.AddPlaceholder(placeholder_run);
756   builder.AddPlaceholder(placeholder_run);
757   builder.AddPlaceholder(placeholder_run);
758   builder.AddPlaceholder(placeholder_run);
759   builder.AddPlaceholder(placeholder_run2);
760   builder.AddPlaceholder(placeholder_run);
761   builder.AddPlaceholder(placeholder_run);
762   builder.AddPlaceholder(placeholder_run);
763   builder.AddPlaceholder(placeholder_run);
764   builder.AddPlaceholder(placeholder_run);
765   builder.AddPlaceholder(placeholder_run);
766   builder.AddPlaceholder(placeholder_run2);
767   builder.AddPlaceholder(placeholder_run);
768   builder.AddPlaceholder(placeholder_run);
769   builder.AddPlaceholder(placeholder_run);
770   builder.AddPlaceholder(placeholder_run);
771   builder.AddPlaceholder(placeholder_run);
772   builder.AddPlaceholder(placeholder_run);
773   builder.AddPlaceholder(placeholder_run);
774   builder.AddPlaceholder(placeholder_run2);
775   builder.AddPlaceholder(placeholder_run);
776 
777   builder.AddText(u16_text);
778 
779   builder.AddPlaceholder(placeholder_run);
780   builder.AddPlaceholder(placeholder_run2);
781 
782   builder.AddText(u16_text);
783   builder.AddText(u16_text);
784   builder.AddText(u16_text);
785   builder.AddText(u16_text);
786   builder.AddPlaceholder(placeholder_run2);
787   builder.AddPlaceholder(placeholder_run);
788   builder.AddText(u16_text);
789   builder.AddPlaceholder(placeholder_run2);
790   builder.AddText(u16_text);
791   builder.AddText(u16_text);
792   builder.AddText(u16_text);
793   builder.AddText(u16_text);
794   builder.AddText(u16_text);
795   builder.AddText(u16_text);
796   builder.AddText(u16_text);
797   builder.AddText(u16_text);
798   builder.AddText(u16_text);
799   builder.AddText(u16_text);
800   builder.AddText(u16_text);
801   builder.AddText(u16_text);
802   builder.AddText(u16_text);
803   builder.AddText(u16_text);
804   builder.AddText(u16_text);
805   builder.AddText(u16_text);
806   builder.AddText(u16_text);
807   builder.AddText(u16_text);
808   builder.AddText(u16_text);
809 
810   builder.Pop();
811 
812   auto paragraph = BuildParagraph(builder);
813   paragraph->Layout(GetTestCanvasWidth() - 100);
814 
815   paragraph->Paint(GetCanvas(), 0, 0);
816 
817   SkPaint paint;
818   paint.setStyle(SkPaint::kStroke_Style);
819   paint.setAntiAlias(true);
820   paint.setStrokeWidth(1);
821 
822   Paragraph::RectHeightStyle rect_height_style =
823       Paragraph::RectHeightStyle::kTight;
824   Paragraph::RectWidthStyle rect_width_style =
825       Paragraph::RectWidthStyle::kTight;
826   paint.setColor(SK_ColorRED);
827   std::vector<txt::Paragraph::TextBox> boxes =
828       paragraph->GetRectsForRange(0, 3, rect_height_style, rect_width_style);
829   for (size_t i = 0; i < boxes.size(); ++i) {
830     GetCanvas()->drawRect(boxes[i].rect, paint);
831   }
832   EXPECT_EQ(boxes.size(), 1ull);
833 
834   paint.setColor(SK_ColorGREEN);
835   boxes = paragraph->GetRectsForRange(175, 176, rect_height_style,
836                                       rect_width_style);
837   for (size_t i = 0; i < boxes.size(); ++i) {
838     GetCanvas()->drawRect(boxes[i].rect, paint);
839   }
840   EXPECT_EQ(boxes.size(), 1ull);
841   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 31.695312);
842   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 218.53125);
843   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 47.292969);
844   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 249);
845 
846   paint.setColor(SK_ColorRED);
847   boxes = paragraph->GetRectsForPlaceholders();
848   for (size_t i = 0; i < boxes.size(); ++i) {
849     GetCanvas()->drawRect(boxes[i].rect, paint);
850   }
851 
852   paint.setColor(SK_ColorBLUE);
853   boxes =
854       paragraph->GetRectsForRange(4, 45, rect_height_style, rect_width_style);
855   for (size_t i = 0; i < boxes.size(); ++i) {
856     GetCanvas()->drawRect(boxes[i].rect, paint);
857   }
858   EXPECT_EQ(boxes.size(), 30ull);
859   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 59.726562);
860   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 26.378906);
861   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875);
862   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 56.847656);
863 
864   EXPECT_FLOAT_EQ(boxes[11].rect.left(), 606.34375);
865   EXPECT_FLOAT_EQ(boxes[11].rect.top(), 38);
866   EXPECT_FLOAT_EQ(boxes[11].rect.right(), 631.34375);
867   EXPECT_FLOAT_EQ(boxes[11].rect.bottom(), 63);
868 
869   EXPECT_FLOAT_EQ(boxes[17].rect.left(), 0.5);
870   EXPECT_FLOAT_EQ(boxes[17].rect.top(), 63.5);
871   EXPECT_FLOAT_EQ(boxes[17].rect.right(), 50.5);
872   EXPECT_FLOAT_EQ(boxes[17].rect.bottom(), 113.5);
873 
874   ASSERT_TRUE(Snapshot());
875 }
876 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholderGetRectsParagraph))877 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderGetRectsParagraph)) {
878   const char* text = "012 34";
879   auto icu_text = icu::UnicodeString::fromUTF8(text);
880   std::u16string u16_text(icu_text.getBuffer(),
881                           icu_text.getBuffer() + icu_text.length());
882 
883   txt::ParagraphStyle paragraph_style;
884   paragraph_style.max_lines = 14;
885   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
886 
887   txt::TextStyle text_style;
888   text_style.font_families = std::vector<std::string>(1, "Roboto");
889   text_style.font_size = 26;
890   text_style.letter_spacing = 1;
891   text_style.word_spacing = 5;
892   text_style.color = SK_ColorBLACK;
893   text_style.height = 1;
894   text_style.decoration = TextDecoration::kUnderline;
895   text_style.decoration_color = SK_ColorBLACK;
896   builder.PushStyle(text_style);
897 
898   builder.AddText(u16_text);
899 
900   txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
901                                       TextBaseline::kAlphabetic, 50);
902   txt::PlaceholderRun placeholder_run2(5, 20, PlaceholderAlignment::kBaseline,
903                                        TextBaseline::kAlphabetic, 10);
904   builder.AddPlaceholder(placeholder_run);
905   builder.AddPlaceholder(placeholder_run);
906   builder.AddPlaceholder(placeholder_run);
907   builder.AddPlaceholder(placeholder_run);
908   builder.AddPlaceholder(placeholder_run);
909   builder.AddPlaceholder(placeholder_run);
910   builder.AddPlaceholder(placeholder_run);
911   builder.AddPlaceholder(placeholder_run);
912   builder.AddPlaceholder(placeholder_run2);
913   builder.AddPlaceholder(placeholder_run);
914   builder.AddPlaceholder(placeholder_run);
915   builder.AddPlaceholder(placeholder_run);
916   builder.AddPlaceholder(placeholder_run);
917   builder.AddPlaceholder(placeholder_run);
918   builder.AddPlaceholder(placeholder_run2);
919   builder.AddPlaceholder(placeholder_run);
920   builder.AddPlaceholder(placeholder_run);
921   builder.AddPlaceholder(placeholder_run);
922   builder.AddPlaceholder(placeholder_run);
923   builder.AddPlaceholder(placeholder_run);
924   builder.AddPlaceholder(placeholder_run);
925   builder.AddPlaceholder(placeholder_run);
926   builder.AddPlaceholder(placeholder_run);
927 
928   builder.AddText(u16_text);
929 
930   builder.AddPlaceholder(placeholder_run);
931   builder.AddPlaceholder(placeholder_run2);
932   builder.AddPlaceholder(placeholder_run2);
933   builder.AddPlaceholder(placeholder_run);
934   builder.AddPlaceholder(placeholder_run2);
935   builder.AddPlaceholder(placeholder_run2);
936 
937   builder.AddText(u16_text);
938   builder.AddText(u16_text);
939   builder.AddText(u16_text);
940   builder.AddText(u16_text);
941   builder.AddText(u16_text);
942   builder.AddText(u16_text);
943   builder.AddText(u16_text);
944   builder.AddText(u16_text);
945   builder.AddText(u16_text);
946   builder.AddText(u16_text);
947   builder.AddText(u16_text);
948   builder.AddPlaceholder(placeholder_run2);
949   builder.AddPlaceholder(placeholder_run);
950   builder.AddPlaceholder(placeholder_run2);
951   builder.AddPlaceholder(placeholder_run);
952   builder.AddPlaceholder(placeholder_run2);
953   builder.AddText(u16_text);
954 
955   builder.Pop();
956 
957   auto paragraph = BuildParagraph(builder);
958   paragraph->Layout(GetTestCanvasWidth());
959 
960   paragraph->Paint(GetCanvas(), 0, 0);
961 
962   SkPaint paint;
963   paint.setStyle(SkPaint::kStroke_Style);
964   paint.setAntiAlias(true);
965   paint.setStrokeWidth(1);
966   paint.setColor(SK_ColorRED);
967   std::vector<txt::Paragraph::TextBox> boxes =
968       paragraph->GetRectsForPlaceholders();
969   for (size_t i = 0; i < boxes.size(); ++i) {
970     GetCanvas()->drawRect(boxes[i].rect, paint);
971   }
972   EXPECT_EQ(boxes.size(), 34ull);
973   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875);
974   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
975   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 140.92188);
976   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
977 
978   EXPECT_FLOAT_EQ(boxes[16].rect.left(), 800.92188);
979   EXPECT_FLOAT_EQ(boxes[16].rect.top(), 0);
980   EXPECT_FLOAT_EQ(boxes[16].rect.right(), 850.92188);
981   EXPECT_FLOAT_EQ(boxes[16].rect.bottom(), 50);
982 
983   EXPECT_FLOAT_EQ(boxes[33].rect.left(), 503.38281);
984   EXPECT_FLOAT_EQ(boxes[33].rect.top(), 160);
985   EXPECT_FLOAT_EQ(boxes[33].rect.right(), 508.38281);
986   EXPECT_FLOAT_EQ(boxes[33].rect.bottom(), 180);
987 
988   Paragraph::RectHeightStyle rect_height_style =
989       Paragraph::RectHeightStyle::kMax;
990   Paragraph::RectWidthStyle rect_width_style =
991       Paragraph::RectWidthStyle::kTight;
992   paint.setColor(SK_ColorBLUE);
993   boxes =
994       paragraph->GetRectsForRange(30, 50, rect_height_style, rect_width_style);
995   for (size_t i = 0; i < boxes.size(); ++i) {
996     GetCanvas()->drawRect(boxes[i].rect, paint);
997   }
998   EXPECT_EQ(boxes.size(), 8ull);
999   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 216.09766);
1000   // Top should be taller than "tight"
1001   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 60);
1002   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 290.92188);
1003   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 120);
1004 
1005   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 290.92188);
1006   EXPECT_FLOAT_EQ(boxes[1].rect.top(), 60);
1007   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 340.92188);
1008   EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 120);
1009 
1010   EXPECT_FLOAT_EQ(boxes[2].rect.left(), 340.92188);
1011   EXPECT_FLOAT_EQ(boxes[2].rect.top(), 60);
1012   EXPECT_FLOAT_EQ(boxes[2].rect.right(), 345.92188);
1013   EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 120);
1014 
1015   ASSERT_TRUE(Snapshot());
1016 }
1017 
1018 #if OS_LINUX
1019 // Tests if manually inserted 0xFFFC characters are replaced to 0xFFFD in order
1020 // to not interfere with the placeholder box layout.
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (InlinePlaceholder0xFFFCParagraph))1021 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholder0xFFFCParagraph)) {
1022   const char* text = "ab\uFFFCcd";
1023   auto icu_text = icu::UnicodeString::fromUTF8(text);
1024   std::u16string u16_text(icu_text.getBuffer(),
1025                           icu_text.getBuffer() + icu_text.length());
1026 
1027   // Used to generate the replaced version.
1028   const char* text2 = "ab\uFFFDcd";
1029   auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
1030   std::u16string u16_text2(icu_text2.getBuffer(),
1031                            icu_text2.getBuffer() + icu_text2.length());
1032 
1033   txt::ParagraphStyle paragraph_style;
1034   paragraph_style.max_lines = 14;
1035   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1036 
1037   txt::TextStyle text_style;
1038   text_style.font_families = std::vector<std::string>(1, "Roboto");
1039   text_style.font_size = 26;
1040   text_style.letter_spacing = 1;
1041   text_style.word_spacing = 5;
1042   text_style.color = SK_ColorBLACK;
1043   text_style.height = 1;
1044   text_style.decoration = TextDecoration::kUnderline;
1045   text_style.decoration_color = SK_ColorBLACK;
1046   builder.PushStyle(text_style);
1047 
1048   std::vector<uint16_t> truth_text;
1049 
1050   builder.AddText(u16_text);
1051   truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1052   builder.AddText(u16_text);
1053   truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1054 
1055   txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
1056                                       TextBaseline::kAlphabetic, 25);
1057   builder.AddPlaceholder(placeholder_run);
1058   truth_text.push_back(0xFFFC);
1059 
1060   builder.AddText(u16_text);
1061   truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1062   builder.AddText(u16_text);
1063   truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1064 
1065   builder.AddPlaceholder(placeholder_run);
1066   truth_text.push_back(0xFFFC);
1067   builder.AddPlaceholder(placeholder_run);
1068   truth_text.push_back(0xFFFC);
1069   builder.AddText(u16_text);
1070   truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1071   builder.AddText(u16_text);
1072   truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1073   builder.AddPlaceholder(placeholder_run);
1074   truth_text.push_back(0xFFFC);
1075 
1076   builder.Pop();
1077 
1078   auto paragraph = BuildParagraph(builder);
1079   paragraph->Layout(GetTestCanvasWidth());
1080 
1081   paragraph->Paint(GetCanvas(), 0, 0);
1082 
1083   for (size_t i = 0; i < truth_text.size(); ++i) {
1084     EXPECT_EQ(paragraph->text_[i], truth_text[i]);
1085   }
1086 
1087   SkPaint paint;
1088   paint.setStyle(SkPaint::kStroke_Style);
1089   paint.setAntiAlias(true);
1090   paint.setStrokeWidth(1);
1091 
1092   paint.setColor(SK_ColorRED);
1093 
1094   paint.setColor(SK_ColorRED);
1095   std::vector<txt::Paragraph::TextBox> boxes =
1096       paragraph->GetRectsForPlaceholders();
1097   for (size_t i = 0; i < boxes.size(); ++i) {
1098     GetCanvas()->drawRect(boxes[i].rect, paint);
1099   }
1100   EXPECT_EQ(boxes.size(), 4ull);
1101 
1102   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177.83594);
1103   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
1104   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 227.83594);
1105   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
1106 
1107   EXPECT_FLOAT_EQ(boxes[3].rect.left(), 682.50781);
1108   EXPECT_FLOAT_EQ(boxes[3].rect.top(), 0);
1109   EXPECT_FLOAT_EQ(boxes[3].rect.right(), 732.50781);
1110   EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 50);
1111 
1112   ASSERT_TRUE(Snapshot());
1113 }
1114 #endif
1115 
TEST_F(ParagraphTest,SimpleRedParagraph)1116 TEST_F(ParagraphTest, SimpleRedParagraph) {
1117   const char* text = "I am RED";
1118   auto icu_text = icu::UnicodeString::fromUTF8(text);
1119   std::u16string u16_text(icu_text.getBuffer(),
1120                           icu_text.getBuffer() + icu_text.length());
1121 
1122   txt::ParagraphStyle paragraph_style;
1123   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1124 
1125   txt::TextStyle text_style;
1126   text_style.font_families = std::vector<std::string>(1, "Roboto");
1127   text_style.color = SK_ColorRED;
1128   builder.PushStyle(text_style);
1129 
1130   builder.AddText(u16_text);
1131 
1132   builder.Pop();
1133 
1134   auto paragraph = BuildParagraph(builder);
1135   paragraph->Layout(GetTestCanvasWidth());
1136 
1137   paragraph->Paint(GetCanvas(), 10.0, 15.0);
1138 
1139   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1140   for (size_t i = 0; i < u16_text.length(); i++) {
1141     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1142   }
1143   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1144   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1145   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1146   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
1147   ASSERT_TRUE(Snapshot());
1148 }
1149 
TEST_F(ParagraphTest,RainbowParagraph)1150 TEST_F(ParagraphTest, RainbowParagraph) {
1151   const char* text1 = "Red Roboto";
1152   auto icu_text1 = icu::UnicodeString::fromUTF8(text1);
1153   std::u16string u16_text1(icu_text1.getBuffer(),
1154                            icu_text1.getBuffer() + icu_text1.length());
1155   const char* text2 = "big Greeen Default";
1156   auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
1157   std::u16string u16_text2(icu_text2.getBuffer(),
1158                            icu_text2.getBuffer() + icu_text2.length());
1159   const char* text3 = "Defcolor Homemade Apple";
1160   auto icu_text3 = icu::UnicodeString::fromUTF8(text3);
1161   std::u16string u16_text3(icu_text3.getBuffer(),
1162                            icu_text3.getBuffer() + icu_text3.length());
1163   const char* text4 = "Small Blue Roboto";
1164   auto icu_text4 = icu::UnicodeString::fromUTF8(text4);
1165   std::u16string u16_text4(icu_text4.getBuffer(),
1166                            icu_text4.getBuffer() + icu_text4.length());
1167   const char* text5 =
1168       "Continue Last Style With lots of words to check if it overlaps "
1169       "properly or not";
1170   auto icu_text5 = icu::UnicodeString::fromUTF8(text5);
1171   std::u16string u16_text5(icu_text5.getBuffer(),
1172                            icu_text5.getBuffer() + icu_text5.length());
1173 
1174   txt::ParagraphStyle paragraph_style;
1175   paragraph_style.max_lines = 2;
1176   paragraph_style.text_align = TextAlign::left;
1177   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1178 
1179   txt::TextStyle text_style1;
1180   text_style1.font_families = std::vector<std::string>(1, "Roboto");
1181   text_style1.color = SK_ColorRED;
1182 
1183   builder.PushStyle(text_style1);
1184 
1185   builder.AddText(u16_text1);
1186 
1187   txt::TextStyle text_style2;
1188   text_style2.font_size = 50;
1189   text_style2.letter_spacing = 10;
1190   text_style2.word_spacing = 30;
1191   text_style2.font_weight = txt::FontWeight::w600;
1192   text_style2.color = SK_ColorGREEN;
1193   text_style2.font_families = std::vector<std::string>(1, "Roboto");
1194   text_style2.decoration = TextDecoration::kUnderline |
1195                            TextDecoration::kOverline |
1196                            TextDecoration::kLineThrough;
1197   text_style2.decoration_color = SK_ColorBLACK;
1198   builder.PushStyle(text_style2);
1199 
1200   builder.AddText(u16_text2);
1201 
1202   txt::TextStyle text_style3;
1203   text_style3.font_families = std::vector<std::string>(1, "Homemade Apple");
1204   builder.PushStyle(text_style3);
1205 
1206   builder.AddText(u16_text3);
1207 
1208   txt::TextStyle text_style4;
1209   text_style4.font_size = 14;
1210   text_style4.color = SK_ColorBLUE;
1211   text_style4.font_families = std::vector<std::string>(1, "Roboto");
1212   text_style4.decoration = TextDecoration::kUnderline |
1213                            TextDecoration::kOverline |
1214                            TextDecoration::kLineThrough;
1215   text_style4.decoration_color = SK_ColorBLACK;
1216   builder.PushStyle(text_style4);
1217 
1218   builder.AddText(u16_text4);
1219 
1220   // Extra text to see if it goes to default when there is more text chunks than
1221   // styles.
1222   builder.AddText(u16_text5);
1223 
1224   builder.Pop();
1225 
1226   auto paragraph = BuildParagraph(builder);
1227   paragraph->Layout(GetTestCanvasWidth());
1228   paragraph->Paint(GetCanvas(), 0, 0);
1229 
1230   u16_text1 += u16_text2 + u16_text3 + u16_text4;
1231   for (size_t i = 0; i < u16_text1.length(); i++) {
1232     ASSERT_EQ(paragraph->text_[i], u16_text1[i]);
1233   }
1234   ASSERT_TRUE(Snapshot());
1235   ASSERT_EQ(paragraph->runs_.runs_.size(), 4ull);
1236   ASSERT_EQ(paragraph->runs_.styles_.size(), 5ull);
1237   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style1));
1238   ASSERT_TRUE(paragraph->runs_.styles_[2].equals(text_style2));
1239   ASSERT_TRUE(paragraph->runs_.styles_[3].equals(text_style3));
1240   ASSERT_TRUE(paragraph->runs_.styles_[4].equals(text_style4));
1241   ASSERT_EQ(paragraph->records_[0].style().color, text_style1.color);
1242   ASSERT_EQ(paragraph->records_[1].style().color, text_style2.color);
1243   ASSERT_EQ(paragraph->records_[2].style().color, text_style3.color);
1244   ASSERT_EQ(paragraph->records_[3].style().color, text_style4.color);
1245 }
1246 
1247 // Currently, this should render nothing without a supplied TextStyle.
TEST_F(ParagraphTest,DefaultStyleParagraph)1248 TEST_F(ParagraphTest, DefaultStyleParagraph) {
1249   const char* text = "No TextStyle! Uh Oh!";
1250   auto icu_text = icu::UnicodeString::fromUTF8(text);
1251   std::u16string u16_text(icu_text.getBuffer(),
1252                           icu_text.getBuffer() + icu_text.length());
1253 
1254   txt::ParagraphStyle paragraph_style;
1255   paragraph_style.font_family = "Roboto";
1256   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1257 
1258   builder.AddText(u16_text);
1259 
1260   builder.Pop();
1261 
1262   auto paragraph = BuildParagraph(builder);
1263   paragraph->Layout(GetTestCanvasWidth());
1264 
1265   paragraph->Paint(GetCanvas(), 10.0, 15.0);
1266 
1267   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1268   for (size_t i = 0; i < u16_text.length(); i++) {
1269     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1270   }
1271   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1272   ASSERT_EQ(paragraph->runs_.styles_.size(), 1ull);
1273   ASSERT_TRUE(Snapshot());
1274 }
1275 
TEST_F(ParagraphTest,BoldParagraph)1276 TEST_F(ParagraphTest, BoldParagraph) {
1277   const char* text = "This is Red max bold text!";
1278   auto icu_text = icu::UnicodeString::fromUTF8(text);
1279   std::u16string u16_text(icu_text.getBuffer(),
1280                           icu_text.getBuffer() + icu_text.length());
1281 
1282   txt::ParagraphStyle paragraph_style;
1283   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1284 
1285   txt::TextStyle text_style;
1286   text_style.font_families = std::vector<std::string>(1, "Roboto");
1287   text_style.font_size = 60;
1288   text_style.letter_spacing = 0;
1289   text_style.font_weight = txt::FontWeight::w900;
1290   text_style.color = SK_ColorRED;
1291   builder.PushStyle(text_style);
1292 
1293   builder.AddText(u16_text);
1294 
1295   builder.Pop();
1296 
1297   auto paragraph = BuildParagraph(builder);
1298   paragraph->Layout(GetTestCanvasWidth());
1299 
1300   paragraph->Paint(GetCanvas(), 10.0, 60.0);
1301 
1302   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1303   for (size_t i = 0; i < u16_text.length(); i++) {
1304     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1305   }
1306   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1307   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1308   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1309   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
1310   ASSERT_TRUE(Snapshot());
1311 
1312   // width_ takes the full available space, but longest_line_ is only the width
1313   // of the text, which is less than one line.
1314   ASSERT_DOUBLE_EQ(paragraph->width_, GetTestCanvasWidth());
1315   ASSERT_TRUE(paragraph->longest_line_ < paragraph->width_);
1316   Paragraph::RectHeightStyle rect_height_style =
1317       Paragraph::RectHeightStyle::kMax;
1318   Paragraph::RectWidthStyle rect_width_style =
1319       Paragraph::RectWidthStyle::kTight;
1320   std::vector<txt::Paragraph::TextBox> boxes = paragraph->GetRectsForRange(
1321       0, strlen(text), rect_height_style, rect_width_style);
1322   ASSERT_DOUBLE_EQ(paragraph->longest_line_,
1323                    boxes[boxes.size() - 1].rect.right() - boxes[0].rect.left());
1324 }
1325 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (HeightOverrideParagraph))1326 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(HeightOverrideParagraph)) {
1327   const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
1328   auto icu_text = icu::UnicodeString::fromUTF8(text);
1329   std::u16string u16_text(icu_text.getBuffer(),
1330                           icu_text.getBuffer() + icu_text.length());
1331 
1332   txt::ParagraphStyle paragraph_style;
1333   paragraph_style.max_lines = 10;
1334   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1335 
1336   txt::TextStyle text_style;
1337   text_style.font_families = std::vector<std::string>(1, "Roboto");
1338   text_style.font_size = 20;
1339   text_style.letter_spacing = 0;
1340   text_style.word_spacing = 0;
1341   text_style.color = SK_ColorBLACK;
1342   text_style.height = 3.6345;
1343   text_style.has_height_override = true;
1344   builder.PushStyle(text_style);
1345 
1346   builder.AddText(u16_text);
1347 
1348   builder.Pop();
1349 
1350   auto paragraph = BuildParagraph(builder);
1351   paragraph->Layout(550);
1352 
1353   paragraph->Paint(GetCanvas(), 0, 0);
1354 
1355   SkPaint paint;
1356   paint.setStyle(SkPaint::kStroke_Style);
1357   paint.setAntiAlias(true);
1358   paint.setStrokeWidth(1);
1359 
1360   // Tests for GetRectsForRange()
1361   Paragraph::RectHeightStyle rect_height_style =
1362       Paragraph::RectHeightStyle::kIncludeLineSpacingMiddle;
1363   Paragraph::RectWidthStyle rect_width_style =
1364       Paragraph::RectWidthStyle::kTight;
1365   paint.setColor(SK_ColorRED);
1366   std::vector<txt::Paragraph::TextBox> boxes =
1367       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
1368   for (size_t i = 0; i < boxes.size(); ++i) {
1369     GetCanvas()->drawRect(boxes[i].rect, paint);
1370   }
1371   EXPECT_EQ(boxes.size(), 0ull);
1372 
1373   boxes =
1374       paragraph->GetRectsForRange(0, 40, rect_height_style, rect_width_style);
1375   for (size_t i = 0; i < boxes.size(); ++i) {
1376     GetCanvas()->drawRect(boxes[i].rect, paint);
1377   }
1378   EXPECT_EQ(boxes.size(), 3ull);
1379   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
1380   EXPECT_NEAR(boxes[1].rect.top(), 92.805778503417969, 0.0001);
1381   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 43.84375);
1382   EXPECT_NEAR(boxes[1].rect.bottom(), 165.49578857421875, 0.0001);
1383 
1384   ASSERT_TRUE(Snapshot());
1385 }
1386 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (LeftAlignParagraph))1387 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(LeftAlignParagraph)) {
1388   const char* text =
1389       "This is a very long sentence to test if the text will properly wrap "
1390       "around and go to the next line. Sometimes, short sentence. Longer "
1391       "sentences are okay too because they are necessary. Very short. "
1392       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1393       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1394       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1395       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1396       "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1397       "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1398       "mollit anim id est laborum. "
1399       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1400       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1401       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1402       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1403       "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1404       "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1405       "mollit anim id est laborum.";
1406   auto icu_text = icu::UnicodeString::fromUTF8(text);
1407   std::u16string u16_text(icu_text.getBuffer(),
1408                           icu_text.getBuffer() + icu_text.length());
1409 
1410   txt::ParagraphStyle paragraph_style;
1411   paragraph_style.max_lines = 14;
1412   paragraph_style.text_align = TextAlign::left;
1413   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1414 
1415   txt::TextStyle text_style;
1416   text_style.font_families = std::vector<std::string>(1, "Roboto");
1417   text_style.font_size = 26;
1418   text_style.letter_spacing = 1;
1419   text_style.word_spacing = 5;
1420   text_style.color = SK_ColorBLACK;
1421   text_style.height = 1;
1422   text_style.decoration = TextDecoration::kUnderline;
1423   text_style.decoration_color = SK_ColorBLACK;
1424   builder.PushStyle(text_style);
1425 
1426   builder.AddText(u16_text);
1427 
1428   builder.Pop();
1429 
1430   auto paragraph = BuildParagraph(builder);
1431   paragraph->Layout(GetTestCanvasWidth() - 100);
1432 
1433   paragraph->Paint(GetCanvas(), 0, 0);
1434 
1435   ASSERT_TRUE(Snapshot());
1436 
1437   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1438   for (size_t i = 0; i < u16_text.length(); i++) {
1439     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1440   }
1441   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1442   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1443   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1444   ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines);
1445   double expected_y = 24;
1446 
1447   ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
1448   ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
1449   expected_y += 30;
1450   ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
1451 
1452   ASSERT_TRUE(paragraph->records_[1].style().equals(text_style));
1453   ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().y(), expected_y);
1454   expected_y += 30;
1455   ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
1456 
1457   ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
1458   ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
1459   expected_y += 30;
1460   ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
1461 
1462   ASSERT_TRUE(paragraph->records_[3].style().equals(text_style));
1463   ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().y(), expected_y);
1464   expected_y += 30 * 10;
1465   ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0);
1466 
1467   ASSERT_TRUE(paragraph->records_[13].style().equals(text_style));
1468   ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().y(), expected_y);
1469   ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().x(), 0);
1470 
1471   ASSERT_EQ(paragraph_style.text_align,
1472             paragraph->GetParagraphStyle().text_align);
1473 
1474   // Tests for GetGlyphPositionAtCoordinate()
1475   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0, 0).position, 0ull);
1476   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 1).position, 0ull);
1477   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 35).position, 68ull);
1478   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 70).position, 134ull);
1479   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(2000, 35).position, 134ull);
1480 
1481   ASSERT_TRUE(Snapshot());
1482 }
1483 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (RightAlignParagraph))1484 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(RightAlignParagraph)) {
1485   const char* text =
1486       "This is a very long sentence to test if the text will properly wrap "
1487       "around and go to the next line. Sometimes, short sentence. Longer "
1488       "sentences are okay too because they are necessary. Very short. "
1489       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1490       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1491       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1492       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1493       "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1494       "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1495       "mollit anim id est laborum. "
1496       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1497       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1498       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1499       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1500       "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1501       "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1502       "mollit anim id est laborum.";
1503   auto icu_text = icu::UnicodeString::fromUTF8(text);
1504   std::u16string u16_text(icu_text.getBuffer(),
1505                           icu_text.getBuffer() + icu_text.length());
1506 
1507   txt::ParagraphStyle paragraph_style;
1508   paragraph_style.max_lines = 14;
1509   paragraph_style.text_align = TextAlign::right;
1510   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1511 
1512   txt::TextStyle text_style;
1513   text_style.font_families = std::vector<std::string>(1, "Roboto");
1514   text_style.font_size = 26;
1515   text_style.letter_spacing = 1;
1516   text_style.word_spacing = 5;
1517   text_style.color = SK_ColorBLACK;
1518   text_style.height = 1;
1519   text_style.decoration = TextDecoration::kUnderline;
1520   text_style.decoration_color = SK_ColorBLACK;
1521   builder.PushStyle(text_style);
1522 
1523   builder.AddText(u16_text);
1524 
1525   builder.Pop();
1526 
1527   auto paragraph = BuildParagraph(builder);
1528   int available_width = GetTestCanvasWidth() - 100;
1529   paragraph->Layout(available_width);
1530 
1531   paragraph->Paint(GetCanvas(), 0, 0);
1532 
1533   ASSERT_TRUE(Snapshot());
1534   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1535   for (size_t i = 0; i < u16_text.length(); i++) {
1536     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1537   }
1538   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1539   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1540   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1541   // Two records for each due to 'ghost' trailing whitespace run.
1542   ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines * 2);
1543   double expected_y = 24;
1544 
1545   ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
1546   ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
1547   expected_y += 30;
1548   ASSERT_NEAR(
1549       paragraph->records_[0].offset().x(),
1550       paragraph->width_ -
1551           paragraph->breaker_.getWidths()[paragraph->records_[0].line()],
1552       2.0);
1553 
1554   // width_ takes the full available space, while longest_line_ wraps the glyphs
1555   // as tightly as possible. Even though this text is more than one line long,
1556   // no line perfectly spans the width of the full line, so longest_line_ is
1557   // less than width_.
1558   ASSERT_DOUBLE_EQ(paragraph->width_, available_width);
1559   ASSERT_TRUE(paragraph->longest_line_ < available_width);
1560   ASSERT_DOUBLE_EQ(paragraph->longest_line_, 880.765625);
1561 
1562   ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
1563   ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
1564   expected_y += 30;
1565   ASSERT_NEAR(
1566       paragraph->records_[2].offset().x(),
1567       paragraph->width_ -
1568           paragraph->breaker_.getWidths()[paragraph->records_[2].line()],
1569       2.0);
1570 
1571   ASSERT_TRUE(paragraph->records_[4].style().equals(text_style));
1572   ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y);
1573   expected_y += 30;
1574   ASSERT_NEAR(
1575       paragraph->records_[4].offset().x(),
1576       paragraph->width_ -
1577           paragraph->breaker_.getWidths()[paragraph->records_[4].line()],
1578       2.0);
1579 
1580   ASSERT_TRUE(paragraph->records_[6].style().equals(text_style));
1581   ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y);
1582   expected_y += 30 * 10;
1583   ASSERT_NEAR(
1584       paragraph->records_[6].offset().x(),
1585       paragraph->width_ -
1586           paragraph->breaker_.getWidths()[paragraph->records_[6].line()],
1587       2.0);
1588 
1589   ASSERT_TRUE(paragraph->records_[26].style().equals(text_style));
1590   ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y);
1591   ASSERT_NEAR(
1592       paragraph->records_[26].offset().x(),
1593       paragraph->width_ -
1594           paragraph->breaker_.getWidths()[paragraph->records_[26].line()],
1595       2.0);
1596 
1597   ASSERT_EQ(paragraph_style.text_align,
1598             paragraph->GetParagraphStyle().text_align);
1599 
1600   ASSERT_TRUE(Snapshot());
1601 }
1602 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (CenterAlignParagraph))1603 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(CenterAlignParagraph)) {
1604   const char* text =
1605       "This is a very long sentence to test if the text will properly wrap "
1606       "around and go to the next line. Sometimes, short sentence. Longer "
1607       "sentences are okay too because they are necessary. Very short. "
1608       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1609       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1610       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1611       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1612       "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1613       "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1614       "mollit anim id est laborum. "
1615       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1616       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1617       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1618       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1619       "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1620       "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1621       "mollit anim id est laborum.";
1622   auto icu_text = icu::UnicodeString::fromUTF8(text);
1623   std::u16string u16_text(icu_text.getBuffer(),
1624                           icu_text.getBuffer() + icu_text.length());
1625 
1626   txt::ParagraphStyle paragraph_style;
1627   paragraph_style.max_lines = 14;
1628   paragraph_style.text_align = TextAlign::center;
1629   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1630 
1631   txt::TextStyle text_style;
1632   text_style.font_families = std::vector<std::string>(1, "Roboto");
1633   text_style.font_size = 26;
1634   text_style.letter_spacing = 1;
1635   text_style.word_spacing = 5;
1636   text_style.color = SK_ColorBLACK;
1637   text_style.height = 1;
1638   text_style.decoration = TextDecoration::kUnderline;
1639   text_style.decoration_color = SK_ColorBLACK;
1640   builder.PushStyle(text_style);
1641 
1642   builder.AddText(u16_text);
1643 
1644   builder.Pop();
1645 
1646   auto paragraph = BuildParagraph(builder);
1647   paragraph->Layout(GetTestCanvasWidth() - 100);
1648 
1649   paragraph->Paint(GetCanvas(), 0, 0);
1650 
1651   ASSERT_TRUE(Snapshot());
1652   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1653   for (size_t i = 0; i < u16_text.length(); i++) {
1654     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1655   }
1656   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1657   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1658   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1659   // Two records for each due to 'ghost' trailing whitespace run.
1660   ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines * 2);
1661   double expected_y = 24;
1662 
1663   ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
1664   ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
1665   expected_y += 30;
1666   ASSERT_NEAR(paragraph->records_[0].offset().x(),
1667               (paragraph->width_ -
1668                paragraph->breaker_.getWidths()[paragraph->records_[0].line()]) /
1669                   2,
1670               2.0);
1671 
1672   ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
1673   ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
1674   expected_y += 30;
1675   ASSERT_NEAR(paragraph->records_[2].offset().x(),
1676               (paragraph->width_ -
1677                paragraph->breaker_.getWidths()[paragraph->records_[2].line()]) /
1678                   2,
1679               2.0);
1680 
1681   ASSERT_TRUE(paragraph->records_[4].style().equals(text_style));
1682   ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y);
1683   expected_y += 30;
1684   ASSERT_NEAR(paragraph->records_[4].offset().x(),
1685               (paragraph->width_ -
1686                paragraph->breaker_.getWidths()[paragraph->records_[4].line()]) /
1687                   2,
1688               2.0);
1689 
1690   ASSERT_TRUE(paragraph->records_[6].style().equals(text_style));
1691   ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y);
1692   expected_y += 30 * 10;
1693   ASSERT_NEAR(paragraph->records_[6].offset().x(),
1694               (paragraph->width_ -
1695                paragraph->breaker_.getWidths()[paragraph->records_[6].line()]) /
1696                   2,
1697               2.0);
1698 
1699   ASSERT_TRUE(paragraph->records_[26].style().equals(text_style));
1700   ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y);
1701   ASSERT_NEAR(
1702       paragraph->records_[26].offset().x(),
1703       (paragraph->width_ -
1704        paragraph->breaker_.getWidths()[paragraph->records_[26].line()]) /
1705           2,
1706       2.0);
1707 
1708   ASSERT_EQ(paragraph_style.text_align,
1709             paragraph->GetParagraphStyle().text_align);
1710 
1711   ASSERT_TRUE(Snapshot());
1712 }
1713 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (JustifyAlignParagraph))1714 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyAlignParagraph)) {
1715   const char* text =
1716       "This is a very long sentence to test if the text will properly wrap "
1717       "around and go to the next line. Sometimes, short sentence. Longer "
1718       "sentences are okay too because they are necessary. Very short. "
1719       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1720       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1721       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1722       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1723       "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1724       "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1725       "mollit anim id est laborum. "
1726       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1727       "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1728       "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1729       "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1730       "velit esse cillum dolore eu fugiat.";
1731   auto icu_text = icu::UnicodeString::fromUTF8(text);
1732   std::u16string u16_text(icu_text.getBuffer(),
1733                           icu_text.getBuffer() + icu_text.length());
1734 
1735   txt::ParagraphStyle paragraph_style;
1736   paragraph_style.max_lines = 14;
1737   paragraph_style.text_align = TextAlign::justify;
1738   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1739 
1740   txt::TextStyle text_style;
1741   text_style.font_families = std::vector<std::string>(1, "Roboto");
1742   text_style.font_size = 26;
1743   text_style.letter_spacing = 0;
1744   text_style.word_spacing = 5;
1745   text_style.color = SK_ColorBLACK;
1746   text_style.height = 1;
1747   text_style.decoration = TextDecoration::kUnderline;
1748   text_style.decoration_color = SK_ColorBLACK;
1749   builder.PushStyle(text_style);
1750 
1751   builder.AddText(u16_text);
1752 
1753   builder.Pop();
1754 
1755   auto paragraph = BuildParagraph(builder);
1756   paragraph->Layout(GetTestCanvasWidth() - 100);
1757 
1758   paragraph->Paint(GetCanvas(), 0, 0);
1759 
1760   ASSERT_TRUE(Snapshot());
1761   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1762   for (size_t i = 0; i < u16_text.length(); i++) {
1763     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1764   }
1765   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1766   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1767   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1768   ASSERT_EQ(paragraph->records_.size(), 27ull);
1769   double expected_y = 24;
1770 
1771   ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
1772   ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
1773   expected_y += 30;
1774   ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
1775 
1776   ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
1777   ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
1778   expected_y += 30;
1779   ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
1780 
1781   ASSERT_TRUE(paragraph->records_[4].style().equals(text_style));
1782   ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y);
1783   expected_y += 30;
1784   ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 0);
1785 
1786   ASSERT_TRUE(paragraph->records_[6].style().equals(text_style));
1787   ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y);
1788   expected_y += 30 * 10;
1789   ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().x(), 0);
1790 
1791   ASSERT_TRUE(paragraph->records_[26].style().equals(text_style));
1792   ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y);
1793   ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().x(), 0);
1794 
1795   ASSERT_EQ(paragraph_style.text_align,
1796             paragraph->GetParagraphStyle().text_align);
1797 
1798   ASSERT_TRUE(Snapshot());
1799 }
1800 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (JustifyRTL))1801 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyRTL)) {
1802   const char* text =
1803       "אאא בּבּבּבּ אאאא בּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ "
1804       "אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ "
1805       "אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ";
1806 
1807   auto icu_text = icu::UnicodeString::fromUTF8(text);
1808   std::u16string u16_text(icu_text.getBuffer(),
1809                           icu_text.getBuffer() + icu_text.length());
1810 
1811   txt::ParagraphStyle paragraph_style;
1812   paragraph_style.max_lines = 14;
1813   paragraph_style.text_align = TextAlign::justify;
1814   paragraph_style.text_direction = TextDirection::rtl;
1815   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1816 
1817   txt::TextStyle text_style;
1818   text_style.font_families = std::vector<std::string>(1, "Ahem");
1819   text_style.font_size = 26;
1820   text_style.color = SK_ColorBLACK;
1821   text_style.height = 1;
1822   builder.PushStyle(text_style);
1823 
1824   builder.AddText(u16_text);
1825 
1826   builder.Pop();
1827 
1828   auto paragraph = BuildParagraph(builder);
1829   size_t paragraph_width = GetTestCanvasWidth() - 100;
1830   paragraph->Layout(paragraph_width);
1831 
1832   paragraph->Paint(GetCanvas(), 0, 0);
1833 
1834   auto glyph_line_width = [&paragraph](int index) {
1835     size_t second_to_last_position_index =
1836         paragraph->glyph_lines_[index].positions.size() - 1;
1837     return paragraph->glyph_lines_[index]
1838         .positions[second_to_last_position_index]
1839         .x_pos.end;
1840   };
1841 
1842   SkPaint paint;
1843   paint.setStyle(SkPaint::kStroke_Style);
1844   paint.setAntiAlias(true);
1845   paint.setStrokeWidth(1);
1846 
1847   // Tests for GetRectsForRange()
1848   Paragraph::RectHeightStyle rect_height_style =
1849       Paragraph::RectHeightStyle::kMax;
1850   Paragraph::RectWidthStyle rect_width_style =
1851       Paragraph::RectWidthStyle::kTight;
1852   paint.setColor(SK_ColorRED);
1853   std::vector<txt::Paragraph::TextBox> boxes =
1854       paragraph->GetRectsForRange(0, 100, rect_height_style, rect_width_style);
1855   for (size_t i = 0; i < boxes.size(); ++i) {
1856     GetCanvas()->drawRect(boxes[i].rect, paint);
1857   }
1858   ASSERT_EQ(boxes.size(), 5ull);
1859 
1860   paint.setColor(SK_ColorBLUE);
1861   boxes = paragraph->GetRectsForRange(240, 250, rect_height_style,
1862                                       rect_width_style);
1863   for (size_t i = 0; i < boxes.size(); ++i) {
1864     GetCanvas()->drawRect(boxes[i].rect, paint);
1865   }
1866   ASSERT_EQ(boxes.size(), 1ull);
1867   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 588);
1868   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 130);
1869   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 640);
1870   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 156);
1871   ASSERT_TRUE(Snapshot());
1872 
1873   // All lines should be justified to the width of the
1874   // paragraph.
1875   for (size_t i = 0; i < paragraph->glyph_lines_.size(); ++i) {
1876     ASSERT_EQ(glyph_line_width(i), paragraph_width);
1877   }
1878 }
1879 
TEST_F(ParagraphTest,DecorationsParagraph)1880 TEST_F(ParagraphTest, DecorationsParagraph) {
1881   txt::ParagraphStyle paragraph_style;
1882   paragraph_style.max_lines = 14;
1883   paragraph_style.text_align = TextAlign::left;
1884   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1885 
1886   txt::TextStyle text_style;
1887   text_style.font_families = std::vector<std::string>(1, "Roboto");
1888   text_style.font_size = 26;
1889   text_style.letter_spacing = 0;
1890   text_style.word_spacing = 5;
1891   text_style.color = SK_ColorBLACK;
1892   text_style.height = 2;
1893   text_style.decoration = TextDecoration::kUnderline |
1894                           TextDecoration::kOverline |
1895                           TextDecoration::kLineThrough;
1896   text_style.decoration_style = txt::TextDecorationStyle::kSolid;
1897   text_style.decoration_color = SK_ColorBLACK;
1898   text_style.decoration_thickness_multiplier = 2.0;
1899   builder.PushStyle(text_style);
1900   builder.AddText(u"This text should be");
1901 
1902   text_style.decoration_style = txt::TextDecorationStyle::kDouble;
1903   text_style.decoration_color = SK_ColorBLUE;
1904   text_style.decoration_thickness_multiplier = 1.0;
1905   builder.PushStyle(text_style);
1906   builder.AddText(u" decorated even when");
1907 
1908   text_style.decoration_style = txt::TextDecorationStyle::kDotted;
1909   text_style.decoration_color = SK_ColorBLACK;
1910   builder.PushStyle(text_style);
1911   builder.AddText(u" wrapped around to");
1912 
1913   text_style.decoration_style = txt::TextDecorationStyle::kDashed;
1914   text_style.decoration_color = SK_ColorBLACK;
1915   text_style.decoration_thickness_multiplier = 3.0;
1916   builder.PushStyle(text_style);
1917   builder.AddText(u" the next line.");
1918 
1919   text_style.decoration_style = txt::TextDecorationStyle::kWavy;
1920   text_style.decoration_color = SK_ColorRED;
1921   text_style.decoration_thickness_multiplier = 1.0;
1922   builder.PushStyle(text_style);
1923 
1924   builder.AddText(u" Otherwise, bad things happen.");
1925 
1926   builder.Pop();
1927 
1928   auto paragraph = BuildParagraph(builder);
1929   paragraph->Layout(GetTestCanvasWidth() - 100);
1930 
1931   paragraph->Paint(GetCanvas(), 0, 0);
1932 
1933   ASSERT_TRUE(Snapshot());
1934   ASSERT_EQ(paragraph->runs_.size(), 5ull);
1935   ASSERT_EQ(paragraph->records_.size(), 6ull);
1936 
1937   for (size_t i = 0; i < 6; ++i) {
1938     ASSERT_EQ(paragraph->records_[i].style().decoration,
1939               TextDecoration::kUnderline | TextDecoration::kOverline |
1940                   TextDecoration::kLineThrough);
1941   }
1942 
1943   ASSERT_EQ(paragraph->records_[0].style().decoration_style,
1944             txt::TextDecorationStyle::kSolid);
1945   ASSERT_EQ(paragraph->records_[1].style().decoration_style,
1946             txt::TextDecorationStyle::kDouble);
1947   ASSERT_EQ(paragraph->records_[2].style().decoration_style,
1948             txt::TextDecorationStyle::kDotted);
1949   ASSERT_EQ(paragraph->records_[3].style().decoration_style,
1950             txt::TextDecorationStyle::kDashed);
1951   ASSERT_EQ(paragraph->records_[4].style().decoration_style,
1952             txt::TextDecorationStyle::kDashed);
1953   ASSERT_EQ(paragraph->records_[5].style().decoration_style,
1954             txt::TextDecorationStyle::kWavy);
1955 
1956   ASSERT_EQ(paragraph->records_[0].style().decoration_color, SK_ColorBLACK);
1957   ASSERT_EQ(paragraph->records_[1].style().decoration_color, SK_ColorBLUE);
1958   ASSERT_EQ(paragraph->records_[2].style().decoration_color, SK_ColorBLACK);
1959   ASSERT_EQ(paragraph->records_[3].style().decoration_color, SK_ColorBLACK);
1960   ASSERT_EQ(paragraph->records_[4].style().decoration_color, SK_ColorBLACK);
1961   ASSERT_EQ(paragraph->records_[5].style().decoration_color, SK_ColorRED);
1962 
1963   ASSERT_EQ(paragraph->records_[0].style().decoration_thickness_multiplier,
1964             2.0);
1965   ASSERT_EQ(paragraph->records_[1].style().decoration_thickness_multiplier,
1966             1.0);
1967   ASSERT_EQ(paragraph->records_[2].style().decoration_thickness_multiplier,
1968             1.0);
1969   ASSERT_EQ(paragraph->records_[3].style().decoration_thickness_multiplier,
1970             3.0);
1971   ASSERT_EQ(paragraph->records_[4].style().decoration_thickness_multiplier,
1972             3.0);
1973   ASSERT_EQ(paragraph->records_[5].style().decoration_thickness_multiplier,
1974             1.0);
1975 }
1976 
TEST_F(ParagraphTest,WavyDecorationParagraph)1977 TEST_F(ParagraphTest, WavyDecorationParagraph) {
1978   txt::ParagraphStyle paragraph_style;
1979   paragraph_style.max_lines = 14;
1980   paragraph_style.text_align = TextAlign::left;
1981   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1982 
1983   txt::TextStyle text_style;
1984   text_style.font_families = std::vector<std::string>(1, "Roboto");
1985   text_style.font_size = 26;
1986   text_style.letter_spacing = 0;
1987   text_style.word_spacing = 5;
1988   text_style.color = SK_ColorBLACK;
1989   text_style.height = 2;
1990   text_style.decoration = TextDecoration::kUnderline |
1991                           TextDecoration::kOverline |
1992                           TextDecoration::kLineThrough;
1993 
1994   text_style.decoration_style = txt::TextDecorationStyle::kWavy;
1995   text_style.decoration_color = SK_ColorRED;
1996   text_style.decoration_thickness_multiplier = 1.0;
1997   builder.PushStyle(text_style);
1998 
1999   builder.AddText(u" Otherwise, bad things happen.");
2000 
2001   builder.Pop();
2002 
2003   auto paragraph = BuildParagraph(builder);
2004   paragraph->Layout(GetTestCanvasWidth() - 100);
2005 
2006   paragraph->Paint(GetCanvas(), 0, 0);
2007 
2008   ASSERT_TRUE(Snapshot());
2009   ASSERT_EQ(paragraph->runs_.size(), 1ull);
2010   ASSERT_EQ(paragraph->records_.size(), 1ull);
2011 
2012   for (size_t i = 0; i < 1; ++i) {
2013     ASSERT_EQ(paragraph->records_[i].style().decoration,
2014               TextDecoration::kUnderline | TextDecoration::kOverline |
2015                   TextDecoration::kLineThrough);
2016   }
2017 
2018   ASSERT_EQ(paragraph->records_[0].style().decoration_style,
2019             txt::TextDecorationStyle::kWavy);
2020 
2021   ASSERT_EQ(paragraph->records_[0].style().decoration_color, SK_ColorRED);
2022 
2023   ASSERT_EQ(paragraph->records_[0].style().decoration_thickness_multiplier,
2024             1.0);
2025 
2026   SkPath path0;
2027   SkPath canonical_path0;
2028   paragraph->ComputeWavyDecoration(path0, 1, 1, 9.56, 1);
2029 
2030   canonical_path0.moveTo(1, 1);
2031   canonical_path0.rQuadTo(1, -1, 2, 0);
2032   canonical_path0.rQuadTo(1, 1, 2, 0);
2033   canonical_path0.rQuadTo(1, -1, 2, 0);
2034   canonical_path0.rQuadTo(1, 1, 2, 0);
2035   canonical_path0.rQuadTo(0.78, -0.78, 1.56, -0.3432);
2036 
2037   ASSERT_EQ(path0.countPoints(), canonical_path0.countPoints());
2038   for (int i = 0; i < canonical_path0.countPoints(); ++i) {
2039     ASSERT_EQ(path0.getPoint(i).x(), canonical_path0.getPoint(i).x());
2040     ASSERT_EQ(path0.getPoint(i).y(), canonical_path0.getPoint(i).y());
2041   }
2042 
2043   SkPath path1;
2044   SkPath canonical_path1;
2045   paragraph->ComputeWavyDecoration(path1, 1, 1, 8.35, 1);
2046 
2047   canonical_path1.moveTo(1, 1);
2048   canonical_path1.rQuadTo(1, -1, 2, 0);
2049   canonical_path1.rQuadTo(1, 1, 2, 0);
2050   canonical_path1.rQuadTo(1, -1, 2, 0);
2051   canonical_path1.rQuadTo(1, 1, 2, 0);
2052   canonical_path1.rQuadTo(0.175, -0.175, 0.35, -0.28875);
2053 
2054   ASSERT_EQ(path1.countPoints(), canonical_path1.countPoints());
2055   for (int i = 0; i < canonical_path1.countPoints(); ++i) {
2056     ASSERT_EQ(path1.getPoint(i).x(), canonical_path1.getPoint(i).x());
2057     ASSERT_EQ(path1.getPoint(i).y(), canonical_path1.getPoint(i).y());
2058   }
2059 
2060   SkPath path2;
2061   SkPath canonical_path2;
2062   paragraph->ComputeWavyDecoration(path2, 1, 1, 10.59, 1);
2063 
2064   canonical_path2.moveTo(1, 1);
2065   canonical_path2.rQuadTo(1, -1, 2, 0);
2066   canonical_path2.rQuadTo(1, 1, 2, 0);
2067   canonical_path2.rQuadTo(1, -1, 2, 0);
2068   canonical_path2.rQuadTo(1, 1, 2, 0);
2069   canonical_path2.rQuadTo(1, -1, 2, 0);
2070   canonical_path2.rQuadTo(0.295, 0.295, 0.59, 0.41595);
2071 
2072   ASSERT_EQ(path2.countPoints(), canonical_path2.countPoints());
2073   for (int i = 0; i < canonical_path2.countPoints(); ++i) {
2074     ASSERT_EQ(path2.getPoint(i).x(), canonical_path2.getPoint(i).x());
2075     ASSERT_EQ(path2.getPoint(i).y(), canonical_path2.getPoint(i).y());
2076   }
2077 
2078   SkPath path3;
2079   SkPath canonical_path3;
2080   paragraph->ComputeWavyDecoration(path3, 1, 1, 11.2, 1);
2081 
2082   canonical_path3.moveTo(1, 1);
2083   canonical_path3.rQuadTo(1, -1, 2, 0);
2084   canonical_path3.rQuadTo(1, 1, 2, 0);
2085   canonical_path3.rQuadTo(1, -1, 2, 0);
2086   canonical_path3.rQuadTo(1, 1, 2, 0);
2087   canonical_path3.rQuadTo(1, -1, 2, 0);
2088   canonical_path3.rQuadTo(0.6, 0.6, 1.2, 0.48);
2089 
2090   ASSERT_EQ(path3.countPoints(), canonical_path3.countPoints());
2091   for (int i = 0; i < canonical_path3.countPoints(); ++i) {
2092     ASSERT_EQ(path3.getPoint(i).x(), canonical_path3.getPoint(i).x());
2093     ASSERT_EQ(path3.getPoint(i).y(), canonical_path3.getPoint(i).y());
2094   }
2095 
2096   SkPath path4;
2097   SkPath canonical_path4;
2098   paragraph->ComputeWavyDecoration(path4, 1, 1, 12, 1);
2099 
2100   canonical_path4.moveTo(1, 1);
2101   canonical_path4.rQuadTo(1, -1, 2, 0);
2102   canonical_path4.rQuadTo(1, 1, 2, 0);
2103   canonical_path4.rQuadTo(1, -1, 2, 0);
2104   canonical_path4.rQuadTo(1, 1, 2, 0);
2105   canonical_path4.rQuadTo(1, -1, 2, 0);
2106   canonical_path4.rQuadTo(1, 1, 2, 0);
2107 
2108   ASSERT_EQ(path4.countPoints(), canonical_path4.countPoints());
2109   for (int i = 0; i < canonical_path4.countPoints(); ++i) {
2110     ASSERT_EQ(path4.getPoint(i).x(), canonical_path4.getPoint(i).x());
2111     ASSERT_EQ(path4.getPoint(i).y(), canonical_path4.getPoint(i).y());
2112   }
2113 }
2114 
TEST_F(ParagraphTest,ItalicsParagraph)2115 TEST_F(ParagraphTest, ItalicsParagraph) {
2116   txt::ParagraphStyle paragraph_style;
2117   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2118 
2119   txt::TextStyle text_style;
2120   text_style.font_families = std::vector<std::string>(1, "Roboto");
2121   text_style.color = SK_ColorRED;
2122   text_style.font_size = 10;
2123   builder.PushStyle(text_style);
2124   builder.AddText(u"No italic ");
2125 
2126   text_style.font_style = txt::FontStyle::italic;
2127   builder.PushStyle(text_style);
2128   builder.AddText(u"Yes Italic ");
2129 
2130   builder.Pop();
2131   builder.AddText(u"No Italic again.");
2132 
2133   auto paragraph = BuildParagraph(builder);
2134   paragraph->Layout(GetTestCanvasWidth());
2135 
2136   paragraph->Paint(GetCanvas(), 0, 0);
2137 
2138   ASSERT_EQ(paragraph->runs_.runs_.size(), 3ull);
2139   ASSERT_EQ(paragraph->runs_.styles_.size(), 3ull);
2140   ASSERT_EQ(paragraph->records_[1].style().color, text_style.color);
2141   ASSERT_EQ(paragraph->records_[1].style().font_style, txt::FontStyle::italic);
2142   ASSERT_EQ(paragraph->records_[2].style().font_style, txt::FontStyle::normal);
2143   ASSERT_EQ(paragraph->records_[0].style().font_style, txt::FontStyle::normal);
2144   ASSERT_TRUE(Snapshot());
2145 }
2146 
TEST_F(ParagraphTest,ChineseParagraph)2147 TEST_F(ParagraphTest, ChineseParagraph) {
2148   const char* text =
2149       "左線読設重説切後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
2150       "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得庭"
2151       "際輝求佐抗蒼提夜合逃表。注統天言件自謙雅載報紙喪。作画稿愛器灯女書利変探"
2152       "訃第金線朝開化建。子戦年帝励害表月幕株漠新期刊人秘。図的海力生禁挙保天戦"
2153       "聞条年所在口。";
2154   auto icu_text = icu::UnicodeString::fromUTF8(text);
2155   std::u16string u16_text(icu_text.getBuffer(),
2156                           icu_text.getBuffer() + icu_text.length());
2157 
2158   txt::ParagraphStyle paragraph_style;
2159   paragraph_style.max_lines = 14;
2160   paragraph_style.text_align = TextAlign::justify;
2161   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2162 
2163   txt::TextStyle text_style;
2164   text_style.color = SK_ColorBLACK;
2165   text_style.font_size = 35;
2166   text_style.letter_spacing = 2;
2167   text_style.font_families = std::vector<std::string>(1, "Source Han Serif CN");
2168   text_style.decoration = TextDecoration::kUnderline |
2169                           TextDecoration::kOverline |
2170                           TextDecoration::kLineThrough;
2171   text_style.decoration_style = txt::TextDecorationStyle::kSolid;
2172   text_style.decoration_color = SK_ColorBLACK;
2173   builder.PushStyle(text_style);
2174 
2175   builder.AddText(u16_text);
2176 
2177   builder.Pop();
2178 
2179   auto paragraph = BuildParagraph(builder);
2180   paragraph->Layout(GetTestCanvasWidth() - 100);
2181 
2182   paragraph->Paint(GetCanvas(), 0, 0);
2183 
2184   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
2185   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
2186   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
2187   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
2188   ASSERT_EQ(paragraph->records_.size(), 7ull);
2189 
2190   ASSERT_TRUE(Snapshot());
2191 }
2192 
2193 // TODO(garyq): Support RTL languages.
TEST_F(ParagraphTest,DISABLED_ArabicParagraph)2194 TEST_F(ParagraphTest, DISABLED_ArabicParagraph) {
2195   const char* text =
2196       "من أسر وإعلان الخاصّة وهولندا،, عل قائمة الضغوط بالمطالبة تلك. الصفحة "
2197       "بمباركة التقليدية قام عن. تصفح";
2198   auto icu_text = icu::UnicodeString::fromUTF8(text);
2199   std::u16string u16_text(icu_text.getBuffer(),
2200                           icu_text.getBuffer() + icu_text.length());
2201 
2202   txt::ParagraphStyle paragraph_style;
2203   paragraph_style.max_lines = 14;
2204   paragraph_style.text_align = TextAlign::right;
2205   paragraph_style.text_direction = TextDirection::rtl;
2206   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2207 
2208   txt::TextStyle text_style;
2209   text_style.color = SK_ColorBLACK;
2210   text_style.font_size = 35;
2211   text_style.letter_spacing = 2;
2212   text_style.font_families = std::vector<std::string>(1, "Katibeh");
2213   text_style.decoration = TextDecoration::kUnderline |
2214                           TextDecoration::kOverline |
2215                           TextDecoration::kLineThrough;
2216   text_style.decoration_style = txt::TextDecorationStyle::kSolid;
2217   text_style.decoration_color = SK_ColorBLACK;
2218   builder.PushStyle(text_style);
2219 
2220   builder.AddText(u16_text);
2221 
2222   builder.Pop();
2223 
2224   auto paragraph = BuildParagraph(builder);
2225   paragraph->Layout(GetTestCanvasWidth() - 100);
2226 
2227   paragraph->Paint(GetCanvas(), 0, 0);
2228 
2229   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
2230 
2231   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
2232   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
2233   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
2234   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
2235   ASSERT_EQ(paragraph->records_.size(), 2ull);
2236   ASSERT_EQ(paragraph->paragraph_style_.text_direction, TextDirection::rtl);
2237 
2238   for (size_t i = 0; i < u16_text.length(); i++) {
2239     ASSERT_EQ(paragraph->text_[i], u16_text[u16_text.length() - i]);
2240   }
2241 
2242   ASSERT_TRUE(Snapshot());
2243 }
2244 
2245 // Checks if the rects are in the correct positions after typing spaces in
2246 // Arabic.
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (ArabicRectsParagraph))2247 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsParagraph)) {
2248   const char* text = "بمباركة التقليدية قام عن. تصفح يد    ";
2249   auto icu_text = icu::UnicodeString::fromUTF8(text);
2250   std::u16string u16_text(icu_text.getBuffer(),
2251                           icu_text.getBuffer() + icu_text.length());
2252 
2253   txt::ParagraphStyle paragraph_style;
2254   paragraph_style.max_lines = 14;
2255   paragraph_style.text_align = TextAlign::right;
2256   paragraph_style.text_direction = TextDirection::rtl;
2257   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2258 
2259   txt::TextStyle text_style;
2260   text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
2261   text_style.font_size = 26;
2262   text_style.letter_spacing = 1;
2263   text_style.word_spacing = 5;
2264   text_style.color = SK_ColorBLACK;
2265   text_style.height = 1;
2266   text_style.decoration = TextDecoration::kUnderline;
2267   text_style.decoration_color = SK_ColorBLACK;
2268   builder.PushStyle(text_style);
2269 
2270   builder.AddText(u16_text);
2271 
2272   builder.Pop();
2273 
2274   auto paragraph = BuildParagraph(builder);
2275   paragraph->Layout(GetTestCanvasWidth() - 100);
2276 
2277   paragraph->Paint(GetCanvas(), 0, 0);
2278 
2279   SkPaint paint;
2280   paint.setStyle(SkPaint::kStroke_Style);
2281   paint.setAntiAlias(true);
2282   paint.setStrokeWidth(1);
2283 
2284   // Tests for GetRectsForRange()
2285   Paragraph::RectHeightStyle rect_height_style =
2286       Paragraph::RectHeightStyle::kMax;
2287   Paragraph::RectWidthStyle rect_width_style =
2288       Paragraph::RectWidthStyle::kTight;
2289   paint.setColor(SK_ColorRED);
2290   std::vector<txt::Paragraph::TextBox> boxes =
2291       paragraph->GetRectsForRange(0, 100, rect_height_style, rect_width_style);
2292   for (size_t i = 0; i < boxes.size(); ++i) {
2293     GetCanvas()->drawRect(boxes[i].rect, paint);
2294   }
2295   EXPECT_EQ(boxes.size(), 2ull);
2296 
2297   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 556.54688);
2298   EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
2299   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 900);
2300   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
2301 
2302   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 510.09375);
2303   EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469);
2304   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 557.04688);
2305   EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 44);
2306 
2307   ASSERT_EQ(paragraph_style.text_align,
2308             paragraph->GetParagraphStyle().text_align);
2309 
2310   ASSERT_TRUE(Snapshot());
2311 }
2312 
2313 // Trailing space at the end of the arabic rtl run should be at the left end of
2314 // the arabic run.
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (ArabicRectsLTRLeftAlignParagraph))2315 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRLeftAlignParagraph)) {
2316   const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
2317   auto icu_text = icu::UnicodeString::fromUTF8(text);
2318   std::u16string u16_text(icu_text.getBuffer(),
2319                           icu_text.getBuffer() + icu_text.length());
2320 
2321   txt::ParagraphStyle paragraph_style;
2322   paragraph_style.max_lines = 14;
2323   paragraph_style.text_align = TextAlign::left;
2324   paragraph_style.text_direction = TextDirection::ltr;
2325   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2326 
2327   txt::TextStyle text_style;
2328   text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
2329   text_style.font_size = 26;
2330   text_style.letter_spacing = 1;
2331   text_style.word_spacing = 5;
2332   text_style.color = SK_ColorBLACK;
2333   text_style.height = 1;
2334   text_style.decoration = TextDecoration::kUnderline;
2335   text_style.decoration_color = SK_ColorBLACK;
2336   builder.PushStyle(text_style);
2337 
2338   builder.AddText(u16_text);
2339 
2340   builder.Pop();
2341 
2342   auto paragraph = BuildParagraph(builder);
2343   paragraph->Layout(GetTestCanvasWidth() - 100);
2344 
2345   paragraph->Paint(GetCanvas(), 0, 0);
2346 
2347   SkPaint paint;
2348   paint.setStyle(SkPaint::kStroke_Style);
2349   paint.setAntiAlias(true);
2350   paint.setStrokeWidth(1);
2351 
2352   // Tests for GetRectsForRange()
2353   Paragraph::RectHeightStyle rect_height_style =
2354       Paragraph::RectHeightStyle::kMax;
2355   Paragraph::RectWidthStyle rect_width_style =
2356       Paragraph::RectWidthStyle::kTight;
2357   paint.setColor(SK_ColorRED);
2358   std::vector<txt::Paragraph::TextBox> boxes =
2359       paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style);
2360   for (size_t i = 0; i < boxes.size(); ++i) {
2361     GetCanvas()->drawRect(boxes[i].rect, paint);
2362   }
2363   EXPECT_EQ(boxes.size(), 1ull);
2364 
2365   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 89.40625);
2366   EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
2367   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 121.87891);
2368   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
2369 
2370   ASSERT_EQ(paragraph_style.text_align,
2371             paragraph->GetParagraphStyle().text_align);
2372 
2373   ASSERT_TRUE(Snapshot());
2374 }
2375 
2376 // Trailing space at the end of the arabic rtl run should be at the left end of
2377 // the arabic run and be a ghost space.
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (ArabicRectsLTRRightAlignParagraph))2378 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRRightAlignParagraph)) {
2379   const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
2380   auto icu_text = icu::UnicodeString::fromUTF8(text);
2381   std::u16string u16_text(icu_text.getBuffer(),
2382                           icu_text.getBuffer() + icu_text.length());
2383 
2384   txt::ParagraphStyle paragraph_style;
2385   paragraph_style.max_lines = 14;
2386   paragraph_style.text_align = TextAlign::right;
2387   paragraph_style.text_direction = TextDirection::ltr;
2388   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2389 
2390   txt::TextStyle text_style;
2391   text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
2392   text_style.font_size = 26;
2393   text_style.letter_spacing = 1;
2394   text_style.word_spacing = 5;
2395   text_style.color = SK_ColorBLACK;
2396   text_style.height = 1;
2397   text_style.decoration = TextDecoration::kUnderline;
2398   text_style.decoration_color = SK_ColorBLACK;
2399   builder.PushStyle(text_style);
2400 
2401   builder.AddText(u16_text);
2402 
2403   builder.Pop();
2404 
2405   auto paragraph = BuildParagraph(builder);
2406   paragraph->Layout(GetTestCanvasWidth() - 100);
2407 
2408   paragraph->Paint(GetCanvas(), 0, 0);
2409 
2410   SkPaint paint;
2411   paint.setStyle(SkPaint::kStroke_Style);
2412   paint.setAntiAlias(true);
2413   paint.setStrokeWidth(1);
2414 
2415   // Tests for GetRectsForRange()
2416   Paragraph::RectHeightStyle rect_height_style =
2417       Paragraph::RectHeightStyle::kMax;
2418   Paragraph::RectWidthStyle rect_width_style =
2419       Paragraph::RectWidthStyle::kTight;
2420   paint.setColor(SK_ColorRED);
2421   std::vector<txt::Paragraph::TextBox> boxes =
2422       paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style);
2423   for (size_t i = 0; i < boxes.size(); ++i) {
2424     GetCanvas()->drawRect(boxes[i].rect, paint);
2425   }
2426   EXPECT_EQ(boxes.size(), 2ull);
2427 
2428   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 556.54688);
2429   EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
2430   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 577.78125);
2431   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
2432 
2433   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 545.30859);
2434   EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469);
2435   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 557.04688);
2436   EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 44);
2437 
2438   ASSERT_EQ(paragraph_style.text_align,
2439             paragraph->GetParagraphStyle().text_align);
2440 
2441   ASSERT_TRUE(Snapshot());
2442 }
2443 
TEST_F(ParagraphTest,GetGlyphPositionAtCoordinateParagraph)2444 TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateParagraph) {
2445   const char* text =
2446       "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
2447       "67890 12345";
2448   auto icu_text = icu::UnicodeString::fromUTF8(text);
2449   std::u16string u16_text(icu_text.getBuffer(),
2450                           icu_text.getBuffer() + icu_text.length());
2451 
2452   txt::ParagraphStyle paragraph_style;
2453   paragraph_style.max_lines = 10;
2454   paragraph_style.text_align = TextAlign::left;
2455   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2456 
2457   txt::TextStyle text_style;
2458   text_style.font_families = std::vector<std::string>(1, "Roboto");
2459   text_style.font_size = 50;
2460   text_style.letter_spacing = 1;
2461   text_style.word_spacing = 5;
2462   text_style.color = SK_ColorBLACK;
2463   text_style.height = 1;
2464   builder.PushStyle(text_style);
2465 
2466   builder.AddText(u16_text);
2467 
2468   builder.Pop();
2469 
2470   auto paragraph = BuildParagraph(builder);
2471   paragraph->Layout(550);
2472 
2473   paragraph->Paint(GetCanvas(), 0, 0);
2474 
2475   ASSERT_TRUE(Snapshot());
2476 
2477   // Tests for GetGlyphPositionAtCoordinate()
2478   // NOTE: resulting values can be a few off from their respective positions in
2479   // the original text because the final trailing whitespaces are sometimes not
2480   // drawn (namely, when using "justify" alignment) and therefore are not active
2481   // glyphs.
2482   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-10000, -10000).position,
2483             0ull);
2484   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-1, -1).position, 0ull);
2485   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0, 0).position, 0ull);
2486   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(3, 3).position, 0ull);
2487   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(35, 1).position, 1ull);
2488   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(300, 2).position, 11ull);
2489   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(301, 2.2).position, 11ull);
2490   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(302, 2.6).position, 11ull);
2491   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(301, 2.1).position, 11ull);
2492   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(100000, 20).position,
2493             18ull);
2494   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(450, 20).position, 16ull);
2495   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(100000, 90).position,
2496             36ull);
2497   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-100000, 90).position,
2498             18ull);
2499   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20, -80).position, 1ull);
2500   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 90).position, 18ull);
2501   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 170).position, 36ull);
2502   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 180).position,
2503             72ull);
2504   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(70, 180).position, 56ull);
2505   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 270).position, 72ull);
2506   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(35, 90).position, 19ull);
2507   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 10000).position,
2508             77ull);
2509   ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(85, 10000).position, 75ull);
2510 }
2511 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeParagraph))2512 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
2513   const char* text =
2514       "12345,  \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
2515       "67890 12345";
2516   auto icu_text = icu::UnicodeString::fromUTF8(text);
2517   std::u16string u16_text(icu_text.getBuffer(),
2518                           icu_text.getBuffer() + icu_text.length());
2519 
2520   txt::ParagraphStyle paragraph_style;
2521   paragraph_style.max_lines = 10;
2522   paragraph_style.text_align = TextAlign::left;
2523   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2524 
2525   txt::TextStyle text_style;
2526   text_style.font_families = std::vector<std::string>(1, "Roboto");
2527   text_style.font_size = 50;
2528   text_style.letter_spacing = 0;
2529   text_style.font_weight = FontWeight::w500;
2530   text_style.word_spacing = 0;
2531   text_style.color = SK_ColorBLACK;
2532   text_style.height = 1;
2533   builder.PushStyle(text_style);
2534 
2535   builder.AddText(u16_text);
2536 
2537   builder.Pop();
2538 
2539   auto paragraph = BuildParagraph(builder);
2540   paragraph->Layout(550);
2541 
2542   paragraph->Paint(GetCanvas(), 0, 0);
2543 
2544   SkPaint paint;
2545   paint.setStyle(SkPaint::kStroke_Style);
2546   paint.setAntiAlias(true);
2547   paint.setStrokeWidth(1);
2548 
2549   // Tests for GetRectsForRange()
2550   // NOTE: The base truth values may still need adjustment as the specifics
2551   // are adjusted.
2552   Paragraph::RectHeightStyle rect_height_style =
2553       Paragraph::RectHeightStyle::kMax;
2554   Paragraph::RectWidthStyle rect_width_style =
2555       Paragraph::RectWidthStyle::kTight;
2556   paint.setColor(SK_ColorRED);
2557   std::vector<txt::Paragraph::TextBox> boxes =
2558       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
2559   for (size_t i = 0; i < boxes.size(); ++i) {
2560     GetCanvas()->drawRect(boxes[i].rect, paint);
2561   }
2562   EXPECT_EQ(boxes.size(), 0ull);
2563 
2564   boxes =
2565       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
2566   for (size_t i = 0; i < boxes.size(); ++i) {
2567     GetCanvas()->drawRect(boxes[i].rect, paint);
2568   }
2569   EXPECT_EQ(boxes.size(), 1ull);
2570   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
2571   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
2572   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 28.417969);
2573   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
2574 
2575   paint.setColor(SK_ColorBLUE);
2576   boxes =
2577       paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
2578   for (size_t i = 0; i < boxes.size(); ++i) {
2579     GetCanvas()->drawRect(boxes[i].rect, paint);
2580   }
2581   EXPECT_EQ(boxes.size(), 1ull);
2582   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 56.835938);
2583   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
2584   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 177.97266);
2585   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
2586 
2587   paint.setColor(SK_ColorGREEN);
2588   boxes =
2589       paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
2590   for (size_t i = 0; i < boxes.size(); ++i) {
2591     GetCanvas()->drawRect(boxes[i].rect, paint);
2592   }
2593   EXPECT_EQ(boxes.size(), 1ull);
2594   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177.97266);
2595   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
2596   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 507.02344);
2597   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
2598 
2599   paint.setColor(SK_ColorRED);
2600   boxes =
2601       paragraph->GetRectsForRange(30, 100, rect_height_style, rect_width_style);
2602   for (size_t i = 0; i < boxes.size(); ++i) {
2603     GetCanvas()->drawRect(boxes[i].rect, paint);
2604   }
2605   EXPECT_EQ(boxes.size(), 4ull);
2606   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 211.375);
2607   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
2608   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 463.61719);
2609   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
2610 
2611   // TODO(garyq): The following set of vals are definitely wrong and
2612   // end of paragraph handling needs to be fixed in a later patch.
2613   EXPECT_FLOAT_EQ(boxes[3].rect.left(), 0);
2614   EXPECT_FLOAT_EQ(boxes[3].rect.top(), 236.40625);
2615   EXPECT_FLOAT_EQ(boxes[3].rect.right(), 142.08984);
2616   EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 295);
2617 
2618   paint.setColor(SK_ColorBLUE);
2619   boxes =
2620       paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
2621   for (size_t i = 0; i < boxes.size(); ++i) {
2622     GetCanvas()->drawRect(boxes[i].rect, paint);
2623   }
2624   EXPECT_EQ(boxes.size(), 1ull);
2625   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 450.1875);
2626   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
2627   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519.47266);
2628   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
2629 
2630   paint.setColor(SK_ColorRED);
2631   boxes =
2632       paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
2633   for (size_t i = 0; i < boxes.size(); ++i) {
2634     GetCanvas()->drawRect(boxes[i].rect, paint);
2635   }
2636   EXPECT_EQ(boxes.size(), 0ull);
2637 
2638   ASSERT_TRUE(Snapshot());
2639 }
2640 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeTight))2641 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) {
2642   const char* text =
2643       "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
2644       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
2645       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
2646   auto icu_text = icu::UnicodeString::fromUTF8(text);
2647   std::u16string u16_text(icu_text.getBuffer(),
2648                           icu_text.getBuffer() + icu_text.length());
2649 
2650   txt::ParagraphStyle paragraph_style;
2651   paragraph_style.max_lines = 10;
2652   paragraph_style.text_align = TextAlign::left;
2653   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2654 
2655   txt::TextStyle text_style;
2656   text_style.font_families = std::vector<std::string>(1, "Noto Sans CJK JP");
2657   text_style.font_size = 50;
2658   text_style.letter_spacing = 0;
2659   text_style.font_weight = FontWeight::w500;
2660   text_style.word_spacing = 0;
2661   text_style.color = SK_ColorBLACK;
2662   text_style.height = 1;
2663   builder.PushStyle(text_style);
2664 
2665   builder.AddText(u16_text);
2666 
2667   builder.Pop();
2668 
2669   auto paragraph = BuildParagraph(builder);
2670   paragraph->Layout(550);
2671 
2672   paragraph->Paint(GetCanvas(), 0, 0);
2673 
2674   SkPaint paint;
2675   paint.setStyle(SkPaint::kStroke_Style);
2676   paint.setAntiAlias(true);
2677   paint.setStrokeWidth(1);
2678 
2679   // Tests for GetRectsForRange()
2680   // NOTE: The base truth values may still need adjustment as the specifics
2681   // are adjusted.
2682   Paragraph::RectHeightStyle rect_height_style =
2683       Paragraph::RectHeightStyle::kTight;
2684   Paragraph::RectWidthStyle rect_width_style =
2685       Paragraph::RectWidthStyle::kTight;
2686   paint.setColor(SK_ColorRED);
2687   std::vector<txt::Paragraph::TextBox> boxes =
2688       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
2689   for (size_t i = 0; i < boxes.size(); ++i) {
2690     GetCanvas()->drawRect(boxes[i].rect, paint);
2691   }
2692   EXPECT_EQ(boxes.size(), 0ull);
2693 
2694   boxes =
2695       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
2696   for (size_t i = 0; i < boxes.size(); ++i) {
2697     GetCanvas()->drawRect(boxes[i].rect, paint);
2698   }
2699   EXPECT_EQ(boxes.size(), 1ull);
2700   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
2701   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
2702   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.898438);
2703   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
2704 
2705   paint.setColor(SK_ColorBLUE);
2706   boxes =
2707       paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
2708   for (size_t i = 0; i < boxes.size(); ++i) {
2709     GetCanvas()->drawRect(boxes[i].rect, paint);
2710   }
2711   EXPECT_EQ(boxes.size(), 1ull);
2712   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
2713   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 264.09375);
2714   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
2715 
2716   paint.setColor(SK_ColorGREEN);
2717   boxes =
2718       paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
2719   for (size_t i = 0; i < boxes.size(); ++i) {
2720     GetCanvas()->drawRect(boxes[i].rect, paint);
2721   }
2722   EXPECT_EQ(boxes.size(), 2ull);
2723   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 264.09375);
2724   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
2725   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 595.08594);
2726   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
2727 
2728   ASSERT_TRUE(Snapshot());
2729 }
2730 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeIncludeLineSpacingMiddle))2731 TEST_F(ParagraphTest,
2732        DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingMiddle)) {
2733   const char* text =
2734       "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
2735       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
2736       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
2737   auto icu_text = icu::UnicodeString::fromUTF8(text);
2738   std::u16string u16_text(icu_text.getBuffer(),
2739                           icu_text.getBuffer() + icu_text.length());
2740 
2741   txt::ParagraphStyle paragraph_style;
2742   paragraph_style.max_lines = 10;
2743   paragraph_style.text_align = TextAlign::left;
2744   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2745 
2746   txt::TextStyle text_style;
2747   text_style.font_families = std::vector<std::string>(1, "Roboto");
2748   text_style.font_size = 50;
2749   text_style.letter_spacing = 0;
2750   text_style.font_weight = FontWeight::w500;
2751   text_style.word_spacing = 0;
2752   text_style.color = SK_ColorBLACK;
2753   text_style.height = 1.6;
2754   text_style.has_height_override = true;
2755   builder.PushStyle(text_style);
2756 
2757   builder.AddText(u16_text);
2758 
2759   builder.Pop();
2760 
2761   auto paragraph = BuildParagraph(builder);
2762   paragraph->Layout(550);
2763 
2764   paragraph->Paint(GetCanvas(), 0, 0);
2765 
2766   SkPaint paint;
2767   paint.setStyle(SkPaint::kStroke_Style);
2768   paint.setAntiAlias(true);
2769   paint.setStrokeWidth(1);
2770 
2771   // Tests for GetRectsForRange()
2772   // NOTE: The base truth values may still need adjustment as the specifics
2773   // are adjusted.
2774   Paragraph::RectHeightStyle rect_height_style =
2775       Paragraph::RectHeightStyle::kIncludeLineSpacingMiddle;
2776   Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax;
2777   paint.setColor(SK_ColorRED);
2778   std::vector<txt::Paragraph::TextBox> boxes =
2779       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
2780   for (size_t i = 0; i < boxes.size(); ++i) {
2781     GetCanvas()->drawRect(boxes[i].rect, paint);
2782   }
2783   EXPECT_EQ(boxes.size(), 0ull);
2784 
2785   boxes =
2786       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
2787   for (size_t i = 0; i < boxes.size(); ++i) {
2788     GetCanvas()->drawRect(boxes[i].rect, paint);
2789   }
2790   EXPECT_EQ(boxes.size(), 1ull);
2791   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
2792   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
2793   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688);
2794   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305);
2795 
2796   paint.setColor(SK_ColorBLUE);
2797   boxes =
2798       paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
2799   for (size_t i = 0; i < boxes.size(); ++i) {
2800     GetCanvas()->drawRect(boxes[i].rect, paint);
2801   }
2802   EXPECT_EQ(boxes.size(), 1ull);
2803   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688);
2804   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
2805   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781);
2806   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305);
2807 
2808   paint.setColor(SK_ColorGREEN);
2809   boxes =
2810       paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
2811   for (size_t i = 0; i < boxes.size(); ++i) {
2812     GetCanvas()->drawRect(boxes[i].rect, paint);
2813   }
2814   EXPECT_EQ(boxes.size(), 1ull);
2815   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781);
2816   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
2817   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625);
2818   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473312);
2819 
2820   paint.setColor(SK_ColorRED);
2821   boxes =
2822       paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style);
2823   for (size_t i = 0; i < boxes.size(); ++i) {
2824     GetCanvas()->drawRect(boxes[i].rect, paint);
2825   }
2826   EXPECT_EQ(boxes.size(), 8ull);
2827   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781);
2828   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 88.473312);
2829   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875);
2830   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 168.47331);
2831 
2832   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875);
2833   EXPECT_FLOAT_EQ(boxes[1].rect.top(), 88.473312);
2834   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344);
2835   EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 168.4733);
2836 
2837   EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0);
2838   EXPECT_FLOAT_EQ(boxes[2].rect.top(), 168.4733);
2839   EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422);
2840   EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 248.47331);
2841 
2842   EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422);
2843   EXPECT_FLOAT_EQ(boxes[3].rect.top(), 168.4733);
2844   EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344);
2845   EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 248.47331);
2846 
2847   EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0);
2848   EXPECT_FLOAT_EQ(boxes[4].rect.top(), 248.47331);
2849   EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344);
2850   EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 328.4733);
2851 
2852   EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0);
2853   EXPECT_FLOAT_EQ(boxes[5].rect.top(), 328.47333);
2854   EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344);
2855   EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 408.4733);
2856 
2857   paint.setColor(SK_ColorBLUE);
2858   boxes =
2859       paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
2860   for (size_t i = 0; i < boxes.size(); ++i) {
2861     GetCanvas()->drawRect(boxes[i].rect, paint);
2862   }
2863   EXPECT_EQ(boxes.size(), 1ull);
2864   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656);
2865   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
2866   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047);
2867   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305);
2868 
2869   paint.setColor(SK_ColorRED);
2870   boxes =
2871       paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
2872   for (size_t i = 0; i < boxes.size(); ++i) {
2873     GetCanvas()->drawRect(boxes[i].rect, paint);
2874   }
2875   EXPECT_EQ(boxes.size(), 0ull);
2876 
2877   ASSERT_TRUE(Snapshot());
2878 }
2879 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeIncludeLineSpacingTop))2880 TEST_F(ParagraphTest,
2881        DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingTop)) {
2882   const char* text =
2883       "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
2884       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
2885       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
2886   auto icu_text = icu::UnicodeString::fromUTF8(text);
2887   std::u16string u16_text(icu_text.getBuffer(),
2888                           icu_text.getBuffer() + icu_text.length());
2889 
2890   txt::ParagraphStyle paragraph_style;
2891   paragraph_style.max_lines = 10;
2892   paragraph_style.text_align = TextAlign::left;
2893   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2894 
2895   txt::TextStyle text_style;
2896   text_style.font_families = std::vector<std::string>(1, "Roboto");
2897   text_style.font_size = 50;
2898   text_style.letter_spacing = 0;
2899   text_style.font_weight = FontWeight::w500;
2900   text_style.word_spacing = 0;
2901   text_style.color = SK_ColorBLACK;
2902   text_style.height = 1.6;
2903   text_style.has_height_override = true;
2904   builder.PushStyle(text_style);
2905 
2906   builder.AddText(u16_text);
2907 
2908   builder.Pop();
2909 
2910   auto paragraph = BuildParagraph(builder);
2911   paragraph->Layout(550);
2912 
2913   paragraph->Paint(GetCanvas(), 0, 0);
2914 
2915   SkPaint paint;
2916   paint.setStyle(SkPaint::kStroke_Style);
2917   paint.setAntiAlias(true);
2918   paint.setStrokeWidth(1);
2919 
2920   // Tests for GetRectsForRange()
2921   // NOTE: The base truth values may still need adjustment as the specifics
2922   // are adjusted.
2923   Paragraph::RectHeightStyle rect_height_style =
2924       Paragraph::RectHeightStyle::kIncludeLineSpacingTop;
2925   Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax;
2926   paint.setColor(SK_ColorRED);
2927   std::vector<txt::Paragraph::TextBox> boxes =
2928       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
2929   for (size_t i = 0; i < boxes.size(); ++i) {
2930     GetCanvas()->drawRect(boxes[i].rect, paint);
2931   }
2932   EXPECT_EQ(boxes.size(), 0ull);
2933 
2934   boxes =
2935       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
2936   for (size_t i = 0; i < boxes.size(); ++i) {
2937     GetCanvas()->drawRect(boxes[i].rect, paint);
2938   }
2939   EXPECT_EQ(boxes.size(), 1ull);
2940   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
2941   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
2942   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688);
2943   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
2944 
2945   paint.setColor(SK_ColorBLUE);
2946   boxes =
2947       paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
2948   for (size_t i = 0; i < boxes.size(); ++i) {
2949     GetCanvas()->drawRect(boxes[i].rect, paint);
2950   }
2951   EXPECT_EQ(boxes.size(), 1ull);
2952   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688);
2953   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
2954   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781);
2955   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
2956 
2957   paint.setColor(SK_ColorGREEN);
2958   boxes =
2959       paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
2960   for (size_t i = 0; i < boxes.size(); ++i) {
2961     GetCanvas()->drawRect(boxes[i].rect, paint);
2962   }
2963   EXPECT_EQ(boxes.size(), 1ull);
2964   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781);
2965   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
2966   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625);
2967   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
2968 
2969   paint.setColor(SK_ColorRED);
2970   boxes =
2971       paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style);
2972   for (size_t i = 0; i < boxes.size(); ++i) {
2973     GetCanvas()->drawRect(boxes[i].rect, paint);
2974   }
2975   EXPECT_EQ(boxes.size(), 8ull);
2976   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781);
2977   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 80);
2978   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875);
2979   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
2980 
2981   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875);
2982   EXPECT_FLOAT_EQ(boxes[1].rect.top(), 80);
2983   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344);
2984   EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 160);
2985 
2986   EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0);
2987   EXPECT_FLOAT_EQ(boxes[2].rect.top(), 160);
2988   EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422);
2989   EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 240);
2990 
2991   EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422);
2992   EXPECT_FLOAT_EQ(boxes[3].rect.top(), 160);
2993   EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344);
2994   EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 240);
2995 
2996   EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0);
2997   EXPECT_FLOAT_EQ(boxes[4].rect.top(), 240);
2998   EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344);
2999   EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 320);
3000 
3001   EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0);
3002   EXPECT_FLOAT_EQ(boxes[5].rect.top(), 320);
3003   EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344);
3004   EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 400);
3005 
3006   paint.setColor(SK_ColorBLUE);
3007   boxes =
3008       paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
3009   for (size_t i = 0; i < boxes.size(); ++i) {
3010     GetCanvas()->drawRect(boxes[i].rect, paint);
3011   }
3012   EXPECT_EQ(boxes.size(), 1ull);
3013   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656);
3014   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3015   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047);
3016   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
3017 
3018   paint.setColor(SK_ColorRED);
3019   boxes =
3020       paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3021   for (size_t i = 0; i < boxes.size(); ++i) {
3022     GetCanvas()->drawRect(boxes[i].rect, paint);
3023   }
3024   EXPECT_EQ(boxes.size(), 0ull);
3025 
3026   ASSERT_TRUE(Snapshot());
3027 }
3028 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeIncludeLineSpacingBottom))3029 TEST_F(ParagraphTest,
3030        DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingBottom)) {
3031   const char* text =
3032       "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3033       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3034       " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
3035   auto icu_text = icu::UnicodeString::fromUTF8(text);
3036   std::u16string u16_text(icu_text.getBuffer(),
3037                           icu_text.getBuffer() + icu_text.length());
3038 
3039   txt::ParagraphStyle paragraph_style;
3040   paragraph_style.max_lines = 10;
3041   paragraph_style.text_align = TextAlign::left;
3042   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3043 
3044   txt::TextStyle text_style;
3045   text_style.font_families = std::vector<std::string>(1, "Roboto");
3046   text_style.font_size = 50;
3047   text_style.letter_spacing = 0;
3048   text_style.font_weight = FontWeight::w500;
3049   text_style.word_spacing = 0;
3050   text_style.color = SK_ColorBLACK;
3051   text_style.height = 1.6;
3052   text_style.has_height_override = true;
3053   builder.PushStyle(text_style);
3054 
3055   builder.AddText(u16_text);
3056 
3057   builder.Pop();
3058 
3059   auto paragraph = BuildParagraph(builder);
3060   paragraph->Layout(550);
3061 
3062   paragraph->Paint(GetCanvas(), 0, 0);
3063 
3064   SkPaint paint;
3065   paint.setStyle(SkPaint::kStroke_Style);
3066   paint.setAntiAlias(true);
3067   paint.setStrokeWidth(1);
3068 
3069   // Tests for GetRectsForRange()
3070   // NOTE: The base truth values may still need adjustment as the specifics
3071   // are adjusted.
3072   Paragraph::RectHeightStyle rect_height_style =
3073       Paragraph::RectHeightStyle::kIncludeLineSpacingBottom;
3074   Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax;
3075   paint.setColor(SK_ColorRED);
3076   std::vector<txt::Paragraph::TextBox> boxes =
3077       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3078   for (size_t i = 0; i < boxes.size(); ++i) {
3079     GetCanvas()->drawRect(boxes[i].rect, paint);
3080   }
3081   EXPECT_EQ(boxes.size(), 0ull);
3082 
3083   boxes =
3084       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3085   for (size_t i = 0; i < boxes.size(); ++i) {
3086     GetCanvas()->drawRect(boxes[i].rect, paint);
3087   }
3088   EXPECT_EQ(boxes.size(), 1ull);
3089   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
3090   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3091   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688);
3092   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3093 
3094   paint.setColor(SK_ColorBLUE);
3095   boxes =
3096       paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
3097   for (size_t i = 0; i < boxes.size(); ++i) {
3098     GetCanvas()->drawRect(boxes[i].rect, paint);
3099   }
3100   EXPECT_EQ(boxes.size(), 1ull);
3101   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688);
3102   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3103   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781);
3104   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3105 
3106   paint.setColor(SK_ColorGREEN);
3107   boxes =
3108       paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
3109   for (size_t i = 0; i < boxes.size(); ++i) {
3110     GetCanvas()->drawRect(boxes[i].rect, paint);
3111   }
3112   EXPECT_EQ(boxes.size(), 1ull);
3113   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781);
3114   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3115   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625);
3116   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3117 
3118   paint.setColor(SK_ColorRED);
3119   boxes =
3120       paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style);
3121   for (size_t i = 0; i < boxes.size(); ++i) {
3122     GetCanvas()->drawRect(boxes[i].rect, paint);
3123   }
3124   EXPECT_EQ(boxes.size(), 8ull);
3125   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781);
3126   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 96.946617);
3127   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875);
3128   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 176.94661);
3129 
3130   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875);
3131   EXPECT_FLOAT_EQ(boxes[1].rect.top(), 96.946617);
3132   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344);
3133   EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 176.94661);
3134 
3135   EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0);
3136   EXPECT_FLOAT_EQ(boxes[2].rect.top(), 176.94661);
3137   EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422);
3138   EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 256.94662);
3139 
3140   EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422);
3141   EXPECT_FLOAT_EQ(boxes[3].rect.top(), 176.94661);
3142   EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344);
3143   EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 256.94662);
3144 
3145   EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0);
3146   EXPECT_FLOAT_EQ(boxes[4].rect.top(), 256.94662);
3147   EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344);
3148   EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 336.94662);
3149 
3150   EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0);
3151   EXPECT_FLOAT_EQ(boxes[5].rect.top(), 336.94662);
3152   EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344);
3153   EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 416.94662);
3154 
3155   paint.setColor(SK_ColorBLUE);
3156   boxes =
3157       paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
3158   for (size_t i = 0; i < boxes.size(); ++i) {
3159     GetCanvas()->drawRect(boxes[i].rect, paint);
3160   }
3161   EXPECT_EQ(boxes.size(), 1ull);
3162   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656);
3163   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3164   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047);
3165   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3166 
3167   paint.setColor(SK_ColorRED);
3168   boxes =
3169       paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3170   for (size_t i = 0; i < boxes.size(); ++i) {
3171     GetCanvas()->drawRect(boxes[i].rect, paint);
3172   }
3173   EXPECT_EQ(boxes.size(), 0ull);
3174 
3175   ASSERT_TRUE(Snapshot());
3176 }
3177 
TEST_F(ParagraphTest,GetRectsForRangeIncludeCombiningCharacter)3178 TEST_F(ParagraphTest, GetRectsForRangeIncludeCombiningCharacter) {
3179   const char* text = "ดีสวัสดีชาวโลกที่น่ารัก";
3180   auto icu_text = icu::UnicodeString::fromUTF8(text);
3181   std::u16string u16_text(icu_text.getBuffer(),
3182                           icu_text.getBuffer() + icu_text.length());
3183 
3184   txt::ParagraphStyle paragraph_style;
3185   paragraph_style.max_lines = 10;
3186   paragraph_style.text_align = TextAlign::left;
3187   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3188 
3189   txt::TextStyle text_style;
3190   text_style.font_families = std::vector<std::string>(1, "Roboto");
3191   text_style.font_size = 50;
3192   text_style.letter_spacing = 1;
3193   text_style.word_spacing = 5;
3194   text_style.color = SK_ColorBLACK;
3195   text_style.height = 1;
3196   builder.PushStyle(text_style);
3197 
3198   builder.AddText(u16_text);
3199 
3200   builder.Pop();
3201 
3202   auto paragraph = BuildParagraph(builder);
3203   paragraph->Layout(GetTestCanvasWidth() - 100);
3204 
3205   paragraph->Paint(GetCanvas(), 0, 0);
3206 
3207   Paragraph::RectHeightStyle rect_height_style =
3208       Paragraph::RectHeightStyle::kTight;
3209   Paragraph::RectWidthStyle rect_width_style =
3210       Paragraph::RectWidthStyle::kTight;
3211 
3212   std::vector<txt::Paragraph::TextBox> boxes =
3213       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3214   EXPECT_EQ(boxes.size(), 0ull);
3215 
3216   // Case when the sentence starts with a combining character
3217   // We should get 0 box for ด because it's already been combined to ดี
3218   boxes =
3219       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3220   EXPECT_EQ(boxes.size(), 0ull);
3221 
3222   boxes =
3223       paragraph->GetRectsForRange(1, 2, rect_height_style, rect_width_style);
3224   EXPECT_EQ(boxes.size(), 1ull);
3225 
3226   boxes =
3227       paragraph->GetRectsForRange(0, 2, rect_height_style, rect_width_style);
3228   EXPECT_EQ(boxes.size(), 1ull);
3229 
3230   // Case when the sentence contains a combining character
3231   // We should get 0 box for ว because it's already been combined to วั
3232   boxes =
3233       paragraph->GetRectsForRange(3, 4, rect_height_style, rect_width_style);
3234   EXPECT_EQ(boxes.size(), 0ull);
3235 
3236   boxes =
3237       paragraph->GetRectsForRange(4, 5, rect_height_style, rect_width_style);
3238   EXPECT_EQ(boxes.size(), 1ull);
3239 
3240   boxes =
3241       paragraph->GetRectsForRange(3, 5, rect_height_style, rect_width_style);
3242   EXPECT_EQ(boxes.size(), 1ull);
3243 
3244   // Case when the sentence contains a combining character that contain 3
3245   // characters We should get 0 box for ท and ที because it's already been
3246   // combined to ที่
3247   boxes =
3248       paragraph->GetRectsForRange(14, 15, rect_height_style, rect_width_style);
3249   EXPECT_EQ(boxes.size(), 0ull);
3250 
3251   boxes =
3252       paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
3253   EXPECT_EQ(boxes.size(), 0ull);
3254 
3255   boxes =
3256       paragraph->GetRectsForRange(16, 17, rect_height_style, rect_width_style);
3257   EXPECT_EQ(boxes.size(), 1ull);
3258 
3259   boxes =
3260       paragraph->GetRectsForRange(14, 17, rect_height_style, rect_width_style);
3261   EXPECT_EQ(boxes.size(), 1ull);
3262 }
3263 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeCenterParagraph))3264 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraph)) {
3265   const char* text = "01234    ";  // includes ideographic space
3266                                     // and english space.
3267   auto icu_text = icu::UnicodeString::fromUTF8(text);
3268   std::u16string u16_text(icu_text.getBuffer(),
3269                           icu_text.getBuffer() + icu_text.length());
3270 
3271   txt::ParagraphStyle paragraph_style;
3272   paragraph_style.max_lines = 10;
3273   paragraph_style.text_align = TextAlign::center;
3274   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3275 
3276   txt::TextStyle text_style;
3277   text_style.font_families = std::vector<std::string>(1, "Roboto");
3278   text_style.font_size = 50;
3279   text_style.letter_spacing = 0;
3280   text_style.font_weight = FontWeight::w500;
3281   text_style.word_spacing = 0;
3282   text_style.color = SK_ColorBLACK;
3283   text_style.height = 1;
3284   builder.PushStyle(text_style);
3285 
3286   builder.AddText(u16_text);
3287 
3288   builder.Pop();
3289 
3290   auto paragraph = BuildParagraph(builder);
3291   paragraph->Layout(550);
3292 
3293   paragraph->Paint(GetCanvas(), 0, 0);
3294 
3295   SkPaint paint;
3296   paint.setStyle(SkPaint::kStroke_Style);
3297   paint.setAntiAlias(true);
3298   paint.setStrokeWidth(1);
3299 
3300   // Tests for GetRectsForRange()
3301   Paragraph::RectHeightStyle rect_height_style =
3302       Paragraph::RectHeightStyle::kMax;
3303   Paragraph::RectWidthStyle rect_width_style =
3304       Paragraph::RectWidthStyle::kTight;
3305   paint.setColor(SK_ColorRED);
3306   std::vector<txt::Paragraph::TextBox> boxes =
3307       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3308   for (size_t i = 0; i < boxes.size(); ++i) {
3309     GetCanvas()->drawRect(boxes[i].rect, paint);
3310   }
3311   EXPECT_EQ(boxes.size(), 0ull);
3312 
3313   boxes =
3314       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3315   for (size_t i = 0; i < boxes.size(); ++i) {
3316     GetCanvas()->drawRect(boxes[i].rect, paint);
3317   }
3318   EXPECT_EQ(boxes.size(), 1ull);
3319   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
3320   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3321   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
3322   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3323 
3324   paint.setColor(SK_ColorBLUE);
3325   boxes =
3326       paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style);
3327   for (size_t i = 0; i < boxes.size(); ++i) {
3328     GetCanvas()->drawRect(boxes[i].rect, paint);
3329   }
3330   EXPECT_EQ(boxes.size(), 1ull);
3331   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102);
3332   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3333   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695);
3334   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3335 
3336   paint.setColor(SK_ColorGREEN);
3337   boxes =
3338       paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style);
3339   for (size_t i = 0; i < boxes.size(); ++i) {
3340     GetCanvas()->drawRect(boxes[i].rect, paint);
3341   }
3342   EXPECT_EQ(boxes.size(), 2ull);
3343   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695);
3344   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3345   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
3346   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3347 
3348   paint.setColor(SK_ColorBLACK);
3349   boxes =
3350       paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
3351   for (size_t i = 0; i < boxes.size(); ++i) {
3352     GetCanvas()->drawRect(boxes[i].rect, paint);
3353   }
3354   EXPECT_EQ(boxes.size(), 1ull);
3355   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492);
3356   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3357   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 358.49414);
3358   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3359 
3360   paint.setColor(SK_ColorRED);
3361   boxes =
3362       paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3363   for (size_t i = 0; i < boxes.size(); ++i) {
3364     GetCanvas()->drawRect(boxes[i].rect, paint);
3365   }
3366   EXPECT_EQ(boxes.size(), 0ull);
3367 
3368   ASSERT_TRUE(Snapshot());
3369 }
3370 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeCenterParagraphNewlineCentered))3371 TEST_F(ParagraphTest,
3372        DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraphNewlineCentered)) {
3373   const char* text = "01234\n";
3374   auto icu_text = icu::UnicodeString::fromUTF8(text);
3375   std::u16string u16_text(icu_text.getBuffer(),
3376                           icu_text.getBuffer() + icu_text.length());
3377 
3378   txt::ParagraphStyle paragraph_style;
3379   paragraph_style.max_lines = 10;
3380   paragraph_style.text_align = TextAlign::center;
3381   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3382 
3383   txt::TextStyle text_style;
3384   text_style.font_families = std::vector<std::string>(1, "Roboto");
3385   text_style.font_size = 50;
3386   text_style.letter_spacing = 0;
3387   text_style.font_weight = FontWeight::w500;
3388   text_style.word_spacing = 0;
3389   text_style.color = SK_ColorBLACK;
3390   text_style.height = 1;
3391   builder.PushStyle(text_style);
3392 
3393   builder.AddText(u16_text);
3394 
3395   builder.Pop();
3396 
3397   auto paragraph = BuildParagraph(builder);
3398   paragraph->Layout(550);
3399 
3400   paragraph->Paint(GetCanvas(), 0, 0);
3401 
3402   SkPaint paint;
3403   paint.setStyle(SkPaint::kStroke_Style);
3404   paint.setAntiAlias(true);
3405   paint.setStrokeWidth(1);
3406 
3407   // Tests for GetRectsForRange()
3408   Paragraph::RectHeightStyle rect_height_style =
3409       Paragraph::RectHeightStyle::kMax;
3410   Paragraph::RectWidthStyle rect_width_style =
3411       Paragraph::RectWidthStyle::kTight;
3412   paint.setColor(SK_ColorRED);
3413   std::vector<txt::Paragraph::TextBox> boxes =
3414       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3415   for (size_t i = 0; i < boxes.size(); ++i) {
3416     GetCanvas()->drawRect(boxes[i].rect, paint);
3417   }
3418   EXPECT_EQ(boxes.size(), 0ull);
3419 
3420   boxes =
3421       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3422   for (size_t i = 0; i < boxes.size(); ++i) {
3423     GetCanvas()->drawRect(boxes[i].rect, paint);
3424   }
3425   EXPECT_EQ(boxes.size(), 1ull);
3426   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
3427   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3428   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
3429   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3430 
3431   paint.setColor(SK_ColorGREEN);
3432   boxes =
3433       paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style);
3434   for (size_t i = 0; i < boxes.size(); ++i) {
3435     GetCanvas()->drawRect(boxes[i].rect, paint);
3436   }
3437   EXPECT_EQ(boxes.size(), 1ull);
3438   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 275);
3439   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275);
3440   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(),
3441                   75);  // TODO(garyq): This value can be improved... Should be
3442                         // taller, but we need a good way to obtain a height
3443                         // without any glyphs on the line.
3444 
3445   ASSERT_TRUE(Snapshot());
3446 }
3447 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeCenterMultiLineParagraph))3448 TEST_F(ParagraphTest,
3449        DISABLE_ON_WINDOWS(GetRectsForRangeCenterMultiLineParagraph)) {
3450   const char* text = "01234    \n0123         ";  // includes ideographic
3451                                                     // space and english space.
3452   auto icu_text = icu::UnicodeString::fromUTF8(text);
3453   std::u16string u16_text(icu_text.getBuffer(),
3454                           icu_text.getBuffer() + icu_text.length());
3455 
3456   txt::ParagraphStyle paragraph_style;
3457   paragraph_style.max_lines = 10;
3458   paragraph_style.text_align = TextAlign::center;
3459   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3460 
3461   txt::TextStyle text_style;
3462   text_style.font_families = std::vector<std::string>(1, "Roboto");
3463   text_style.font_size = 50;
3464   text_style.letter_spacing = 0;
3465   text_style.font_weight = FontWeight::w500;
3466   text_style.word_spacing = 0;
3467   text_style.color = SK_ColorBLACK;
3468   text_style.height = 1;
3469   builder.PushStyle(text_style);
3470 
3471   builder.AddText(u16_text);
3472 
3473   builder.Pop();
3474 
3475   auto paragraph = BuildParagraph(builder);
3476   paragraph->Layout(550);
3477 
3478   paragraph->Paint(GetCanvas(), 0, 0);
3479 
3480   SkPaint paint;
3481   paint.setStyle(SkPaint::kStroke_Style);
3482   paint.setAntiAlias(true);
3483   paint.setStrokeWidth(1);
3484 
3485   // Tests for GetRectsForRange()
3486   Paragraph::RectHeightStyle rect_height_style =
3487       Paragraph::RectHeightStyle::kMax;
3488   Paragraph::RectWidthStyle rect_width_style =
3489       Paragraph::RectWidthStyle::kTight;
3490   paint.setColor(SK_ColorRED);
3491   std::vector<txt::Paragraph::TextBox> boxes =
3492       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3493   for (size_t i = 0; i < boxes.size(); ++i) {
3494     GetCanvas()->drawRect(boxes[i].rect, paint);
3495   }
3496   EXPECT_EQ(boxes.size(), 0ull);
3497 
3498   boxes =
3499       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3500   for (size_t i = 0; i < boxes.size(); ++i) {
3501     GetCanvas()->drawRect(boxes[i].rect, paint);
3502   }
3503   EXPECT_EQ(boxes.size(), 1ull);
3504   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
3505   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3506   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
3507   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3508 
3509   paint.setColor(SK_ColorBLUE);
3510   boxes =
3511       paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style);
3512   for (size_t i = 0; i < boxes.size(); ++i) {
3513     GetCanvas()->drawRect(boxes[i].rect, paint);
3514   }
3515   EXPECT_EQ(boxes.size(), 1ull);
3516   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102);
3517   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3518   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695);
3519   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3520 
3521   paint.setColor(SK_ColorGREEN);
3522   boxes =
3523       paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style);
3524   for (size_t i = 0; i < boxes.size(); ++i) {
3525     GetCanvas()->drawRect(boxes[i].rect, paint);
3526   }
3527   EXPECT_EQ(boxes.size(), 2ull);
3528   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695);
3529   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3530   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
3531   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3532 
3533   paint.setColor(SK_ColorBLACK);
3534   boxes =
3535       paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
3536   for (size_t i = 0; i < boxes.size(); ++i) {
3537     GetCanvas()->drawRect(boxes[i].rect, paint);
3538   }
3539   EXPECT_EQ(boxes.size(), 1ull);
3540   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492);
3541   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3542   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 358.49414);
3543   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3544 
3545   paint.setColor(SK_ColorBLACK);
3546   boxes =
3547       paragraph->GetRectsForRange(10, 12, rect_height_style, rect_width_style);
3548   for (size_t i = 0; i < boxes.size(); ++i) {
3549     GetCanvas()->drawRect(boxes[i].rect, paint);
3550   }
3551   EXPECT_EQ(boxes.size(), 1ull);
3552   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 218.16406);
3553   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
3554   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275);
3555   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
3556 
3557   paint.setColor(SK_ColorBLACK);
3558   boxes =
3559       paragraph->GetRectsForRange(14, 18, rect_height_style, rect_width_style);
3560   for (size_t i = 0; i < boxes.size(); ++i) {
3561     GetCanvas()->drawRect(boxes[i].rect, paint);
3562   }
3563   EXPECT_EQ(boxes.size(), 1ull);
3564   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 331.83594);
3565   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
3566   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 419.18359);
3567   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
3568 
3569   paint.setColor(SK_ColorRED);
3570   boxes =
3571       paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3572   for (size_t i = 0; i < boxes.size(); ++i) {
3573     GetCanvas()->drawRect(boxes[i].rect, paint);
3574   }
3575   EXPECT_EQ(boxes.size(), 0ull);
3576 
3577   ASSERT_TRUE(Snapshot());
3578 }
3579 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeStrut))3580 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeStrut)) {
3581   const char* text = "Chinese 字典";
3582 
3583   auto icu_text = icu::UnicodeString::fromUTF8(text);
3584   std::u16string u16_text(icu_text.getBuffer(),
3585                           icu_text.getBuffer() + icu_text.length());
3586 
3587   txt::ParagraphStyle paragraph_style;
3588   paragraph_style.strut_enabled = true;
3589   paragraph_style.strut_font_families.push_back("Roboto");
3590   paragraph_style.strut_font_size = 14;
3591   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3592 
3593   txt::TextStyle text_style;
3594   text_style.font_families.push_back("Noto Sans CJK JP");
3595   text_style.font_size = 20;
3596   text_style.color = SK_ColorBLACK;
3597   builder.PushStyle(text_style);
3598 
3599   builder.AddText(u16_text);
3600 
3601   builder.Pop();
3602 
3603   auto paragraph = BuildParagraph(builder);
3604   paragraph->Layout(550);
3605 
3606   paragraph->Paint(GetCanvas(), 0, 0);
3607 
3608   SkPaint paint;
3609   paint.setStyle(SkPaint::kStroke_Style);
3610   paint.setAntiAlias(true);
3611   paint.setStrokeWidth(1);
3612 
3613   std::vector<txt::Paragraph::TextBox> strut_boxes =
3614       paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kStrut,
3615                                   Paragraph::RectWidthStyle::kMax);
3616   ASSERT_EQ(strut_boxes.size(), 1ull);
3617   const SkRect& strut_rect = strut_boxes.front().rect;
3618   paint.setColor(SK_ColorRED);
3619   GetCanvas()->drawRect(strut_rect, paint);
3620 
3621   std::vector<txt::Paragraph::TextBox> tight_boxes =
3622       paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kTight,
3623                                   Paragraph::RectWidthStyle::kMax);
3624   ASSERT_EQ(tight_boxes.size(), 1ull);
3625   const SkRect& tight_rect = tight_boxes.front().rect;
3626   paint.setColor(SK_ColorGREEN);
3627   GetCanvas()->drawRect(tight_rect, paint);
3628 
3629   EXPECT_FLOAT_EQ(strut_rect.left(), 0);
3630   EXPECT_FLOAT_EQ(strut_rect.top(), 10.611719);
3631   EXPECT_FLOAT_EQ(strut_rect.right(), 118.60547);
3632   EXPECT_FLOAT_EQ(strut_rect.bottom(), 27.017969);
3633 
3634   ASSERT_TRUE(tight_rect.contains(strut_rect));
3635 
3636   ASSERT_TRUE(Snapshot());
3637 }
3638 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (GetRectsForRangeStrutFallback))3639 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeStrutFallback)) {
3640   const char* text = "Chinese 字典";
3641 
3642   auto icu_text = icu::UnicodeString::fromUTF8(text);
3643   std::u16string u16_text(icu_text.getBuffer(),
3644                           icu_text.getBuffer() + icu_text.length());
3645 
3646   txt::ParagraphStyle paragraph_style;
3647   paragraph_style.strut_enabled = false;
3648   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3649 
3650   txt::TextStyle text_style;
3651   text_style.font_families.push_back("Noto Sans CJK JP");
3652   text_style.font_size = 20;
3653   builder.PushStyle(text_style);
3654 
3655   builder.AddText(u16_text);
3656 
3657   builder.Pop();
3658 
3659   auto paragraph = BuildParagraph(builder);
3660   paragraph->Layout(550);
3661 
3662   std::vector<txt::Paragraph::TextBox> strut_boxes =
3663       paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kStrut,
3664                                   Paragraph::RectWidthStyle::kMax);
3665   std::vector<txt::Paragraph::TextBox> tight_boxes =
3666       paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kTight,
3667                                   Paragraph::RectWidthStyle::kMax);
3668 
3669   ASSERT_EQ(strut_boxes.size(), 1ull);
3670   ASSERT_EQ(tight_boxes.size(), 1ull);
3671   ASSERT_EQ(strut_boxes.front().rect, tight_boxes.front().rect);
3672 }
3673 
GetCoordinatesForGlyphPosition(txt::Paragraph & paragraph,size_t pos)3674 SkRect GetCoordinatesForGlyphPosition(txt::Paragraph& paragraph, size_t pos) {
3675   std::vector<txt::Paragraph::TextBox> boxes =
3676       paragraph.GetRectsForRange(pos, pos + 1, Paragraph::RectHeightStyle::kMax,
3677                                  Paragraph::RectWidthStyle::kTight);
3678   return !boxes.empty() ? boxes.front().rect : SkRect::MakeEmpty();
3679 }
3680 
TEST_F(ParagraphTest,GetWordBoundaryParagraph)3681 TEST_F(ParagraphTest, GetWordBoundaryParagraph) {
3682   const char* text =
3683       "12345  67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
3684       "67890 12345";
3685   auto icu_text = icu::UnicodeString::fromUTF8(text);
3686   std::u16string u16_text(icu_text.getBuffer(),
3687                           icu_text.getBuffer() + icu_text.length());
3688 
3689   txt::ParagraphStyle paragraph_style;
3690   paragraph_style.max_lines = 10;
3691   paragraph_style.text_align = TextAlign::left;
3692   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3693 
3694   txt::TextStyle text_style;
3695   text_style.font_families = std::vector<std::string>(1, "Roboto");
3696   text_style.font_size = 52;
3697   text_style.letter_spacing = 1.19039;
3698   text_style.word_spacing = 5;
3699   text_style.color = SK_ColorBLACK;
3700   text_style.height = 1.5;
3701   text_style.has_height_override = true;
3702   builder.PushStyle(text_style);
3703 
3704   builder.AddText(u16_text);
3705 
3706   builder.Pop();
3707 
3708   auto paragraph = BuildParagraph(builder);
3709   paragraph->Layout(550);
3710 
3711   paragraph->Paint(GetCanvas(), 0, 0);
3712 
3713   SkPaint paint;
3714   paint.setStyle(SkPaint::kStroke_Style);
3715   paint.setAntiAlias(true);
3716   paint.setStrokeWidth(1);
3717   paint.setColor(SK_ColorRED);
3718 
3719   SkRect rect = GetCoordinatesForGlyphPosition(*paragraph, 0);
3720   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3721 
3722   EXPECT_EQ(paragraph->GetWordBoundary(0), txt::Paragraph::Range<size_t>(0, 5));
3723   EXPECT_EQ(paragraph->GetWordBoundary(1), txt::Paragraph::Range<size_t>(0, 5));
3724   EXPECT_EQ(paragraph->GetWordBoundary(2), txt::Paragraph::Range<size_t>(0, 5));
3725   EXPECT_EQ(paragraph->GetWordBoundary(3), txt::Paragraph::Range<size_t>(0, 5));
3726   EXPECT_EQ(paragraph->GetWordBoundary(4), txt::Paragraph::Range<size_t>(0, 5));
3727   rect = GetCoordinatesForGlyphPosition(*paragraph, 5);
3728   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3729 
3730   EXPECT_EQ(paragraph->GetWordBoundary(5), txt::Paragraph::Range<size_t>(5, 7));
3731   rect = GetCoordinatesForGlyphPosition(*paragraph, 6);
3732   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3733 
3734   EXPECT_EQ(paragraph->GetWordBoundary(6), txt::Paragraph::Range<size_t>(5, 7));
3735   rect = GetCoordinatesForGlyphPosition(*paragraph, 7);
3736   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3737 
3738   EXPECT_EQ(paragraph->GetWordBoundary(7),
3739             txt::Paragraph::Range<size_t>(7, 12));
3740   EXPECT_EQ(paragraph->GetWordBoundary(8),
3741             txt::Paragraph::Range<size_t>(7, 12));
3742   EXPECT_EQ(paragraph->GetWordBoundary(9),
3743             txt::Paragraph::Range<size_t>(7, 12));
3744   EXPECT_EQ(paragraph->GetWordBoundary(10),
3745             txt::Paragraph::Range<size_t>(7, 12));
3746   EXPECT_EQ(paragraph->GetWordBoundary(11),
3747             txt::Paragraph::Range<size_t>(7, 12));
3748   rect = GetCoordinatesForGlyphPosition(*paragraph, 12);
3749   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3750 
3751   EXPECT_EQ(paragraph->GetWordBoundary(12),
3752             txt::Paragraph::Range<size_t>(12, 13));
3753   rect = GetCoordinatesForGlyphPosition(*paragraph, 13);
3754   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3755 
3756   EXPECT_EQ(paragraph->GetWordBoundary(13),
3757             txt::Paragraph::Range<size_t>(13, 18));
3758   rect = GetCoordinatesForGlyphPosition(*paragraph, 18);
3759   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3760 
3761   rect = GetCoordinatesForGlyphPosition(*paragraph, 19);
3762   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3763 
3764   rect = GetCoordinatesForGlyphPosition(*paragraph, 24);
3765   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3766 
3767   rect = GetCoordinatesForGlyphPosition(*paragraph, 25);
3768   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3769 
3770   rect = GetCoordinatesForGlyphPosition(*paragraph, 30);
3771   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3772 
3773   EXPECT_EQ(paragraph->GetWordBoundary(30),
3774             txt::Paragraph::Range<size_t>(30, 31));
3775   rect = GetCoordinatesForGlyphPosition(*paragraph, 31);
3776   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3777 
3778   rect = GetCoordinatesForGlyphPosition(*paragraph, icu_text.length() - 5);
3779   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3780 
3781   EXPECT_EQ(
3782       paragraph->GetWordBoundary(icu_text.length() - 1),
3783       txt::Paragraph::Range<size_t>(icu_text.length() - 5, icu_text.length()));
3784   rect = GetCoordinatesForGlyphPosition(*paragraph, icu_text.length());
3785   GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
3786 
3787   ASSERT_TRUE(Snapshot());
3788 }
3789 
TEST_F(ParagraphTest,SpacingParagraph)3790 TEST_F(ParagraphTest, SpacingParagraph) {
3791   const char* text = "H";
3792   auto icu_text = icu::UnicodeString::fromUTF8(text);
3793   std::u16string u16_text(icu_text.getBuffer(),
3794                           icu_text.getBuffer() + icu_text.length());
3795 
3796   txt::ParagraphStyle paragraph_style;
3797   paragraph_style.max_lines = 10;
3798   paragraph_style.text_align = TextAlign::left;
3799   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3800 
3801   txt::TextStyle text_style;
3802   text_style.font_families = std::vector<std::string>(1, "Roboto");
3803   text_style.font_size = 50;
3804   text_style.letter_spacing = 20;
3805   text_style.word_spacing = 0;
3806   text_style.color = SK_ColorBLACK;
3807   text_style.height = 1;
3808   builder.PushStyle(text_style);
3809   builder.AddText(u16_text);
3810   builder.Pop();
3811 
3812   text_style.font_size = 50;
3813   text_style.letter_spacing = 10;
3814   text_style.word_spacing = 0;
3815   builder.PushStyle(text_style);
3816   builder.AddText(u16_text);
3817   builder.Pop();
3818 
3819   text_style.font_size = 50;
3820   text_style.letter_spacing = 20;
3821   text_style.word_spacing = 0;
3822   builder.PushStyle(text_style);
3823   builder.AddText(u16_text);
3824   builder.Pop();
3825 
3826   text_style.font_size = 50;
3827   text_style.letter_spacing = 0;
3828   text_style.word_spacing = 0;
3829   builder.PushStyle(text_style);
3830   builder.AddText(u"|");
3831   builder.Pop();
3832 
3833   text_style.font_size = 50;
3834   text_style.letter_spacing = 0;
3835   text_style.word_spacing = 20;
3836   builder.PushStyle(text_style);
3837   builder.AddText(u"H ");
3838   builder.Pop();
3839 
3840   text_style.font_size = 50;
3841   text_style.letter_spacing = 0;
3842   text_style.word_spacing = 0;
3843   builder.PushStyle(text_style);
3844   builder.AddText(u"H ");
3845   builder.Pop();
3846 
3847   text_style.font_size = 50;
3848   text_style.letter_spacing = 0;
3849   text_style.word_spacing = 20;
3850   builder.PushStyle(text_style);
3851   builder.AddText(u"H ");
3852   builder.Pop();
3853 
3854   auto paragraph = BuildParagraph(builder);
3855   paragraph->Layout(550);
3856 
3857   paragraph->Paint(GetCanvas(), 0, 0);
3858 
3859   SkPaint paint;
3860   paint.setStyle(SkPaint::kStroke_Style);
3861   paint.setAntiAlias(true);
3862   paint.setStrokeWidth(1);
3863   paint.setColor(SK_ColorRED);
3864 
3865   ASSERT_TRUE(Snapshot());
3866 
3867   ASSERT_EQ(paragraph->records_.size(), 7ull);
3868   ASSERT_EQ(paragraph->records_[0].style().letter_spacing, 20);
3869   ASSERT_EQ(paragraph->records_[1].style().letter_spacing, 10);
3870   ASSERT_EQ(paragraph->records_[2].style().letter_spacing, 20);
3871 
3872   ASSERT_EQ(paragraph->records_[4].style().word_spacing, 20);
3873   ASSERT_EQ(paragraph->records_[5].style().word_spacing, 0);
3874   ASSERT_EQ(paragraph->records_[6].style().word_spacing, 20);
3875 }
3876 
TEST_F(ParagraphTest,LongWordParagraph)3877 TEST_F(ParagraphTest, LongWordParagraph) {
3878   const char* text =
3879       "A "
3880       "veryverylongwordtoseewherethiswillwraporifitwillatallandifitdoesthenthat"
3881       "wouldbeagoodthingbecausethebreakingisworking.";
3882   auto icu_text = icu::UnicodeString::fromUTF8(text);
3883   std::u16string u16_text(icu_text.getBuffer(),
3884                           icu_text.getBuffer() + icu_text.length());
3885 
3886   txt::ParagraphStyle paragraph_style;
3887   paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality;
3888   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3889 
3890   txt::TextStyle text_style;
3891   text_style.font_families = std::vector<std::string>(1, "Roboto");
3892   text_style.font_size = 31;
3893   text_style.letter_spacing = 0;
3894   text_style.word_spacing = 0;
3895   text_style.color = SK_ColorBLACK;
3896   text_style.height = 1;
3897   builder.PushStyle(text_style);
3898   builder.AddText(u16_text);
3899 
3900   builder.Pop();
3901 
3902   auto paragraph = BuildParagraph(builder);
3903   paragraph->Layout(GetTestCanvasWidth() / 2);
3904 
3905   paragraph->Paint(GetCanvas(), 0, 0);
3906 
3907   ASSERT_TRUE(Snapshot());
3908   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
3909   for (size_t i = 0; i < u16_text.length(); i++) {
3910     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
3911   }
3912   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
3913   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
3914   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
3915   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
3916   ASSERT_EQ(paragraph->GetLineCount(), 4ull);
3917   ASSERT_TRUE(Snapshot());
3918 }
3919 
TEST_F(ParagraphTest,KernScaleParagraph)3920 TEST_F(ParagraphTest, KernScaleParagraph) {
3921   float scale = 3.0f;
3922 
3923   txt::ParagraphStyle paragraph_style;
3924   paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality;
3925   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3926 
3927   txt::TextStyle text_style;
3928   text_style.font_families = std::vector<std::string>(1, "Droid Serif");
3929   text_style.font_size = 100 / scale;
3930   text_style.letter_spacing = 0;
3931   text_style.word_spacing = 0;
3932   text_style.color = SK_ColorBLACK;
3933   text_style.height = 1;
3934   builder.PushStyle(text_style);
3935   builder.AddText(u"AVAVAWAH A0 V0 VA To The Lo");
3936   builder.PushStyle(text_style);
3937   builder.AddText(u"A");
3938   builder.PushStyle(text_style);
3939   builder.AddText(u"V");
3940   text_style.font_size = 14 / scale;
3941   builder.PushStyle(text_style);
3942   builder.AddText(
3943       u" Dialog Text List lots of words to see if kerning works on a bigger "
3944       u"set of characters AVAVAW");
3945 
3946   builder.Pop();
3947 
3948   auto paragraph = BuildParagraph(builder);
3949   paragraph->Layout(GetTestCanvasWidth() / scale);
3950   GetCanvas()->scale(scale, scale);
3951   paragraph->Paint(GetCanvas(), 0, 0);
3952   GetCanvas()->scale(1.0, 1.0);
3953   ASSERT_TRUE(Snapshot());
3954 
3955   EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
3956   EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
3957   EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 207.37109375f);
3958   EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 230.87109375f);
3959   EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 253.36328125f);
3960 }
3961 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (NewlineParagraph))3962 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(NewlineParagraph)) {
3963   txt::ParagraphStyle paragraph_style;
3964   paragraph_style.font_family = "Roboto";
3965   paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality;
3966 
3967   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3968 
3969   txt::TextStyle text_style;
3970   text_style.font_families = std::vector<std::string>(1, "Roboto");
3971   text_style.font_size = 60;
3972   text_style.letter_spacing = 0;
3973   text_style.word_spacing = 0;
3974   text_style.color = SK_ColorBLACK;
3975   text_style.height = 1;
3976   builder.PushStyle(text_style);
3977   builder.AddText(
3978       u"line1\nline2 test1 test2 test3 test4 test5 test6 test7\nline3\n\nline4 "
3979       "test1 test2 test3 test4");
3980 
3981   builder.Pop();
3982 
3983   auto paragraph = BuildParagraph(builder);
3984   paragraph->Layout(GetTestCanvasWidth() - 300);
3985 
3986   paragraph->Paint(GetCanvas(), 0, 0);
3987 
3988   ASSERT_TRUE(Snapshot());
3989 
3990   ASSERT_EQ(paragraph->records_.size(), 6ull);
3991   EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
3992   EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
3993   EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().y(), 126);
3994   EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
3995   EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0);
3996   EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 0);
3997   EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().y(), 266);
3998   EXPECT_DOUBLE_EQ(paragraph->records_[5].offset().x(), 0);
3999 }
4000 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (EmojiParagraph))4001 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(EmojiParagraph)) {
4002   const char* text =
4003       "����������������☺��������������������������������������‍����‍����‍♂️����‍��‍��‍��\
4004       ������☂��������������������������������������������������������\
4005       ❄����������������⚽��‍♀️������������⚓������������⏰��������������\
4006       ������❤������♠♣��❗������️‍��������������������������";
4007   auto icu_text = icu::UnicodeString::fromUTF8(text);
4008   std::u16string u16_text(icu_text.getBuffer(),
4009                           icu_text.getBuffer() + icu_text.length());
4010 
4011   txt::ParagraphStyle paragraph_style;
4012 
4013   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4014 
4015   txt::TextStyle text_style;
4016   text_style.color = SK_ColorBLACK;
4017   text_style.font_families = std::vector<std::string>(1, "Noto Color Emoji");
4018   text_style.font_size = 50;
4019   text_style.decoration = TextDecoration::kUnderline;
4020   builder.PushStyle(text_style);
4021   builder.AddText(u16_text);
4022 
4023   builder.Pop();
4024 
4025   auto paragraph = BuildParagraph(builder);
4026   paragraph->Layout(GetTestCanvasWidth());
4027 
4028   paragraph->Paint(GetCanvas(), 0, 0);
4029 
4030   ASSERT_TRUE(Snapshot());
4031 
4032   for (size_t i = 0; i < u16_text.length(); i++) {
4033     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
4034   }
4035 
4036   ASSERT_EQ(paragraph->records_.size(), 8ull);
4037 
4038   EXPECT_EQ(paragraph->records_[0].line(), 0ull);
4039   EXPECT_EQ(paragraph->records_[1].line(), 1ull);
4040   EXPECT_EQ(paragraph->records_[2].line(), 2ull);
4041   EXPECT_EQ(paragraph->records_[3].line(), 3ull);
4042   EXPECT_EQ(paragraph->records_[7].line(), 7ull);
4043 }
4044 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (EmojiMultiLineRectsParagraph))4045 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(EmojiMultiLineRectsParagraph)) {
4046   // clang-format off
4047   const char* text =
4048       "��‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍��i������‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍������"
4049       "��‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍������"
4050       "��‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍������"
4051       "��‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍��������‍��‍����‍��‍��‍������"
4052       "❄����������������⚽��‍♀️������������⚓������������⏰��������������"
4053       "������❤������♠♣��❗������️‍��������������������������";
4054   // clang-format on
4055   auto icu_text = icu::UnicodeString::fromUTF8(text);
4056   std::u16string u16_text(icu_text.getBuffer(),
4057                           icu_text.getBuffer() + icu_text.length());
4058 
4059   txt::ParagraphStyle paragraph_style;
4060 
4061   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4062 
4063   txt::TextStyle text_style;
4064   text_style.color = SK_ColorBLACK;
4065   text_style.font_families = std::vector<std::string>(1, "Noto Color Emoji");
4066   text_style.font_size = 50;
4067   builder.PushStyle(text_style);
4068   builder.AddText(u16_text);
4069 
4070   builder.Pop();
4071 
4072   auto paragraph = BuildParagraph(builder);
4073   paragraph->Layout(GetTestCanvasWidth() - 300);
4074 
4075   paragraph->Paint(GetCanvas(), 0, 0);
4076 
4077   for (size_t i = 0; i < u16_text.length(); i++) {
4078     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
4079   }
4080 
4081   ASSERT_EQ(paragraph->records_.size(), 10ull);
4082 
4083   SkPaint paint;
4084   paint.setStyle(SkPaint::kStroke_Style);
4085   paint.setAntiAlias(true);
4086   paint.setStrokeWidth(1);
4087 
4088   // Tests for GetRectsForRange()
4089   Paragraph::RectHeightStyle rect_height_style =
4090       Paragraph::RectHeightStyle::kTight;
4091   Paragraph::RectWidthStyle rect_width_style =
4092       Paragraph::RectWidthStyle::kTight;
4093   paint.setColor(SK_ColorRED);
4094   std::vector<txt::Paragraph::TextBox> boxes =
4095       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4096   for (size_t i = 0; i < boxes.size(); ++i) {
4097     GetCanvas()->drawRect(boxes[i].rect, paint);
4098   }
4099   EXPECT_EQ(boxes.size(), 0ull);
4100 
4101   // Ligature style indexing.
4102   boxes =
4103       paragraph->GetRectsForRange(0, 119, rect_height_style, rect_width_style);
4104   for (size_t i = 0; i < boxes.size(); ++i) {
4105     GetCanvas()->drawRect(boxes[i].rect, paint);
4106   }
4107   EXPECT_EQ(boxes.size(), 2ull);
4108   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
4109   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 334.61475);
4110 
4111   boxes = paragraph->GetRectsForRange(122, 132, rect_height_style,
4112                                       rect_width_style);
4113   paint.setColor(SK_ColorBLUE);
4114   for (size_t i = 0; i < boxes.size(); ++i) {
4115     GetCanvas()->drawRect(boxes[i].rect, paint);
4116   }
4117   EXPECT_EQ(boxes.size(), 1ull);
4118   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 357.95996);
4119   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 418.79901);
4120 
4121   // GetPositionForCoordinates should not return inter-emoji positions.
4122   boxes = paragraph->GetRectsForRange(
4123       0, paragraph->GetGlyphPositionAtCoordinate(610, 100).position,
4124       rect_height_style, rect_width_style);
4125   paint.setColor(SK_ColorGREEN);
4126   for (size_t i = 0; i < boxes.size(); ++i) {
4127     GetCanvas()->drawRect(boxes[i].rect, paint);
4128   }
4129   EXPECT_EQ(boxes.size(), 2ull);
4130   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
4131   // The following is expected to change to a higher value when
4132   // rounding up is added to getGlyphPositionForCoordinate.
4133   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 560.28516);
4134 
4135   boxes = paragraph->GetRectsForRange(
4136       0, paragraph->GetGlyphPositionAtCoordinate(580, 100).position,
4137       rect_height_style, rect_width_style);
4138   paint.setColor(SK_ColorGREEN);
4139   for (size_t i = 0; i < boxes.size(); ++i) {
4140     GetCanvas()->drawRect(boxes[i].rect, paint);
4141   }
4142   EXPECT_EQ(boxes.size(), 2ull);
4143   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
4144   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 560.28516);
4145 
4146   boxes = paragraph->GetRectsForRange(
4147       0, paragraph->GetGlyphPositionAtCoordinate(560, 100).position,
4148       rect_height_style, rect_width_style);
4149   paint.setColor(SK_ColorGREEN);
4150   for (size_t i = 0; i < boxes.size(); ++i) {
4151     GetCanvas()->drawRect(boxes[i].rect, paint);
4152   }
4153   EXPECT_EQ(boxes.size(), 2ull);
4154   EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
4155   // The following is expected to change to the 560.28516 value when
4156   // rounding up is added to getGlyphPositionForCoordinate.
4157   EXPECT_FLOAT_EQ(boxes[1].rect.right(), 498.03125);
4158 
4159   ASSERT_TRUE(Snapshot());
4160 }
4161 
TEST_F(ParagraphTest,HyphenBreakParagraph)4162 TEST_F(ParagraphTest, HyphenBreakParagraph) {
4163   const char* text =
4164       "A "
4165       "very-very-long-Hyphen-word-to-see-where-this-will-wrap-or-if-it-will-at-"
4166       "all-and-if-it-does-thent-hat-"
4167       "would-be-a-good-thing-because-the-breaking.";
4168   auto icu_text = icu::UnicodeString::fromUTF8(text);
4169   std::u16string u16_text(icu_text.getBuffer(),
4170                           icu_text.getBuffer() + icu_text.length());
4171 
4172   txt::ParagraphStyle paragraph_style;
4173   paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality;
4174 
4175   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4176 
4177   txt::TextStyle text_style;
4178   text_style.font_families = std::vector<std::string>(1, "Roboto");
4179   text_style.font_size = 31;
4180   text_style.letter_spacing = 0;
4181   text_style.word_spacing = 0;
4182   text_style.color = SK_ColorBLACK;
4183   text_style.height = 1;
4184   builder.PushStyle(text_style);
4185   builder.AddText(u16_text);
4186 
4187   builder.Pop();
4188 
4189   auto paragraph = BuildParagraph(builder);
4190   paragraph->Layout(GetTestCanvasWidth() / 2);
4191 
4192   paragraph->Paint(GetCanvas(), 0, 0);
4193 
4194   ASSERT_TRUE(Snapshot());
4195   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
4196   for (size_t i = 0; i < u16_text.length(); i++) {
4197     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
4198   }
4199   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
4200   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
4201   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
4202   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
4203   ASSERT_EQ(paragraph->GetLineCount(), 5ull);
4204   ASSERT_TRUE(Snapshot());
4205 }
4206 
TEST_F(ParagraphTest,RepeatLayoutParagraph)4207 TEST_F(ParagraphTest, RepeatLayoutParagraph) {
4208   const char* text =
4209       "Sentence to layout at diff widths to get diff line counts. short words "
4210       "short words short words short words short words short words short words "
4211       "short words short words short words short words short words short words "
4212       "end";
4213   auto icu_text = icu::UnicodeString::fromUTF8(text);
4214   std::u16string u16_text(icu_text.getBuffer(),
4215                           icu_text.getBuffer() + icu_text.length());
4216 
4217   txt::ParagraphStyle paragraph_style;
4218   paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality;
4219   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4220 
4221   txt::TextStyle text_style;
4222   text_style.font_families = std::vector<std::string>(1, "Roboto");
4223   text_style.font_size = 31;
4224   text_style.letter_spacing = 0;
4225   text_style.word_spacing = 0;
4226   text_style.color = SK_ColorBLACK;
4227   text_style.height = 1;
4228   builder.PushStyle(text_style);
4229   builder.AddText(u16_text);
4230 
4231   builder.Pop();
4232 
4233   // First Layout.
4234   auto paragraph = BuildParagraph(builder);
4235   paragraph->Layout(300);
4236 
4237   paragraph->Paint(GetCanvas(), 0, 0);
4238 
4239   ASSERT_TRUE(Snapshot());
4240   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
4241   for (size_t i = 0; i < u16_text.length(); i++) {
4242     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
4243   }
4244   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
4245   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
4246   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
4247   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
4248   ASSERT_EQ(paragraph->GetLineCount(), 12ull);
4249 
4250   // Second Layout.
4251   SetUp();
4252   paragraph->Layout(600);
4253   paragraph->Paint(GetCanvas(), 0, 0);
4254 
4255   ASSERT_TRUE(Snapshot());
4256   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
4257   for (size_t i = 0; i < u16_text.length(); i++) {
4258     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
4259   }
4260   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
4261   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
4262   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
4263   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
4264   ASSERT_EQ(paragraph->GetLineCount(), 6ull);
4265   ASSERT_TRUE(Snapshot());
4266 }
4267 
TEST_F(ParagraphTest,Ellipsize)4268 TEST_F(ParagraphTest, Ellipsize) {
4269   const char* text =
4270       "This is a very long sentence to test if the text will properly wrap "
4271       "around and go to the next line. Sometimes, short sentence. Longer "
4272       "sentences are okay too because they are necessary. Very short. ";
4273   auto icu_text = icu::UnicodeString::fromUTF8(text);
4274   std::u16string u16_text(icu_text.getBuffer(),
4275                           icu_text.getBuffer() + icu_text.length());
4276 
4277   txt::ParagraphStyle paragraph_style;
4278   paragraph_style.ellipsis = u"\u2026";
4279   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4280 
4281   txt::TextStyle text_style;
4282   text_style.font_families = std::vector<std::string>(1, "Roboto");
4283   text_style.color = SK_ColorBLACK;
4284   builder.PushStyle(text_style);
4285   builder.AddText(u16_text);
4286 
4287   builder.Pop();
4288 
4289   auto paragraph = BuildParagraph(builder);
4290   paragraph->Layout(GetTestCanvasWidth());
4291 
4292   paragraph->Paint(GetCanvas(), 0, 0);
4293 
4294   ASSERT_TRUE(Snapshot());
4295 
4296   // Check that the ellipsizer limited the text to one line and did not wrap
4297   // to a second line.
4298   ASSERT_EQ(paragraph->records_.size(), 1ull);
4299 }
4300 
4301 // Test for shifting when identical runs of text are built as multiple runs.
TEST_F(ParagraphTest,UnderlineShiftParagraph)4302 TEST_F(ParagraphTest, UnderlineShiftParagraph) {
4303   const char* text1 = "fluttser ";
4304   auto icu_text1 = icu::UnicodeString::fromUTF8(text1);
4305   std::u16string u16_text1(icu_text1.getBuffer(),
4306                            icu_text1.getBuffer() + icu_text1.length());
4307   const char* text2 = "mdje";
4308   auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
4309   std::u16string u16_text2(icu_text2.getBuffer(),
4310                            icu_text2.getBuffer() + icu_text2.length());
4311   const char* text3 = "fluttser mdje";
4312   auto icu_text3 = icu::UnicodeString::fromUTF8(text3);
4313   std::u16string u16_text3(icu_text3.getBuffer(),
4314                            icu_text3.getBuffer() + icu_text3.length());
4315 
4316   // Construct multi-run paragraph.
4317   txt::ParagraphStyle paragraph_style;
4318   paragraph_style.max_lines = 2;
4319   paragraph_style.text_align = TextAlign::left;
4320   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4321 
4322   txt::TextStyle text_style1;
4323   text_style1.color = SK_ColorBLACK;
4324   text_style1.font_families = std::vector<std::string>(1, "Roboto");
4325   builder.PushStyle(text_style1);
4326 
4327   builder.AddText(u16_text1);
4328 
4329   txt::TextStyle text_style2;
4330   text_style2.color = SK_ColorBLACK;
4331   text_style2.font_families = std::vector<std::string>(1, "Roboto");
4332   text_style2.decoration = TextDecoration::kUnderline;
4333   text_style2.decoration_color = SK_ColorBLACK;
4334   builder.PushStyle(text_style2);
4335 
4336   builder.AddText(u16_text2);
4337 
4338   builder.Pop();
4339 
4340   // Construct single run paragraph.
4341   txt::ParagraphBuilderTxt builder2(paragraph_style, GetTestFontCollection());
4342 
4343   builder2.PushStyle(text_style1);
4344 
4345   builder2.AddText(u16_text3);
4346 
4347   builder2.Pop();
4348 
4349   // Build multi-run paragraph
4350   auto paragraph = BuildParagraph(builder);
4351   paragraph->Layout(GetTestCanvasWidth());
4352 
4353   paragraph->Paint(GetCanvas(), 0, 0);
4354 
4355   // Build single-run paragraph
4356   auto paragraph2 = BuildParagraph(builder2);
4357   paragraph2->Layout(GetTestCanvasWidth());
4358 
4359   paragraph2->Paint(GetCanvas(), 0, 25);
4360 
4361   ASSERT_TRUE(Snapshot());
4362 
4363   ASSERT_EQ(paragraph->records_[0].GetRunWidth() +
4364                 paragraph->records_[1].GetRunWidth(),
4365             paragraph2->records_[0].GetRunWidth());
4366 
4367   auto rects1 =
4368       paragraph->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax,
4369                                   Paragraph::RectWidthStyle::kTight);
4370   auto rects2 =
4371       paragraph2->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax,
4372                                    Paragraph::RectWidthStyle::kTight);
4373 
4374   for (size_t i = 0; i < 12; ++i) {
4375     auto r1 = GetCoordinatesForGlyphPosition(*paragraph, i);
4376     auto r2 = GetCoordinatesForGlyphPosition(*paragraph2, i);
4377 
4378     ASSERT_EQ(r1.fLeft, r2.fLeft);
4379     ASSERT_EQ(r1.fRight, r2.fRight);
4380   }
4381 }
4382 
TEST_F(ParagraphTest,SimpleShadow)4383 TEST_F(ParagraphTest, SimpleShadow) {
4384   const char* text = "Hello World Text Dialog";
4385   auto icu_text = icu::UnicodeString::fromUTF8(text);
4386   std::u16string u16_text(icu_text.getBuffer(),
4387                           icu_text.getBuffer() + icu_text.length());
4388 
4389   txt::ParagraphStyle paragraph_style;
4390   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4391 
4392   txt::TextStyle text_style;
4393   text_style.font_families = std::vector<std::string>(1, "Roboto");
4394   text_style.color = SK_ColorBLACK;
4395   text_style.text_shadows.emplace_back(SK_ColorBLACK, SkPoint::Make(2.0, 2.0),
4396                                        1.0);
4397   builder.PushStyle(text_style);
4398   builder.AddText(u16_text);
4399 
4400   builder.Pop();
4401 
4402   auto paragraph = BuildParagraph(builder);
4403   paragraph->Layout(GetTestCanvasWidth());
4404   paragraph->Paint(GetCanvas(), 10.0, 15.0);
4405 
4406   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
4407   for (size_t i = 0; i < u16_text.length(); i++) {
4408     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
4409   }
4410   ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
4411   ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
4412   ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
4413   ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
4414 
4415   ASSERT_EQ(paragraph->records_[0].style().text_shadows.size(), 1ull);
4416   ASSERT_EQ(paragraph->records_[0].style().text_shadows[0],
4417             text_style.text_shadows[0]);
4418 
4419   ASSERT_TRUE(Snapshot());
4420 }
4421 
TEST_F(ParagraphTest,ComplexShadow)4422 TEST_F(ParagraphTest, ComplexShadow) {
4423   const char* text = "Text Chunk ";
4424   auto icu_text = icu::UnicodeString::fromUTF8(text);
4425   std::u16string u16_text(icu_text.getBuffer(),
4426                           icu_text.getBuffer() + icu_text.length());
4427 
4428   txt::ParagraphStyle paragraph_style;
4429   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4430 
4431   txt::TextStyle text_style;
4432   text_style.font_families = std::vector<std::string>(1, "Roboto");
4433   text_style.color = SK_ColorBLACK;
4434   text_style.text_shadows.emplace_back(SK_ColorBLACK, SkPoint::Make(2.0, 2.0),
4435                                        1.0);
4436   builder.PushStyle(text_style);
4437   builder.AddText(u16_text);
4438 
4439   text_style.text_shadows.emplace_back(SK_ColorRED, SkPoint::Make(2.0, 2.0),
4440                                        5.0);
4441   text_style.text_shadows.emplace_back(SK_ColorGREEN, SkPoint::Make(10.0, -5.0),
4442                                        3.0);
4443   builder.PushStyle(text_style);
4444   builder.AddText(u16_text);
4445 
4446   builder.Pop();
4447   builder.AddText(u16_text);
4448 
4449   text_style.text_shadows.emplace_back(SK_ColorGREEN, SkPoint::Make(0.0, -1.0),
4450                                        0.0);
4451   builder.PushStyle(text_style);
4452   builder.AddText(u16_text);
4453 
4454   builder.Pop();
4455   builder.AddText(u16_text);
4456 
4457   builder.Pop();
4458 
4459   auto paragraph = BuildParagraph(builder);
4460   paragraph->Layout(GetTestCanvasWidth());
4461   paragraph->Paint(GetCanvas(), 10.0, 15.0);
4462 
4463   ASSERT_EQ(paragraph->text_.size(), std::string{text}.length() * 5);
4464   for (size_t i = 0; i < u16_text.length(); i++) {
4465     ASSERT_EQ(paragraph->text_[i], u16_text[i]);
4466   }
4467 
4468   ASSERT_EQ(paragraph->records_[0].style().text_shadows.size(), 1ull);
4469   ASSERT_EQ(paragraph->records_[1].style().text_shadows.size(), 3ull);
4470   ASSERT_EQ(paragraph->records_[2].style().text_shadows.size(), 1ull);
4471   ASSERT_EQ(paragraph->records_[3].style().text_shadows.size(), 4ull);
4472   ASSERT_EQ(paragraph->records_[4].style().text_shadows.size(), 1ull);
4473   for (size_t i = 0; i < 1; ++i)
4474     ASSERT_EQ(paragraph->records_[0].style().text_shadows[i],
4475               text_style.text_shadows[i]);
4476   for (size_t i = 0; i < 3; ++i)
4477     ASSERT_EQ(paragraph->records_[1].style().text_shadows[i],
4478               text_style.text_shadows[i]);
4479   for (size_t i = 0; i < 1; ++i)
4480     ASSERT_EQ(paragraph->records_[2].style().text_shadows[i],
4481               text_style.text_shadows[i]);
4482   for (size_t i = 0; i < 4; ++i)
4483     ASSERT_EQ(paragraph->records_[3].style().text_shadows[i],
4484               text_style.text_shadows[i]);
4485   for (size_t i = 0; i < 1; ++i)
4486     ASSERT_EQ(paragraph->records_[4].style().text_shadows[i],
4487               text_style.text_shadows[i]);
4488 
4489   ASSERT_TRUE(Snapshot());
4490 }
4491 
TEST_F(ParagraphTest,BaselineParagraph)4492 TEST_F(ParagraphTest, BaselineParagraph) {
4493   const char* text =
4494       "左線読設Byg後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
4495       "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得";
4496   auto icu_text = icu::UnicodeString::fromUTF8(text);
4497   std::u16string u16_text(icu_text.getBuffer(),
4498                           icu_text.getBuffer() + icu_text.length());
4499 
4500   txt::ParagraphStyle paragraph_style;
4501   paragraph_style.max_lines = 14;
4502   paragraph_style.text_align = TextAlign::justify;
4503   paragraph_style.height = 1.5;
4504   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4505 
4506   txt::TextStyle text_style;
4507   text_style.color = SK_ColorBLACK;
4508   text_style.font_size = 55;
4509   text_style.letter_spacing = 2;
4510   text_style.font_families = std::vector<std::string>(1, "Source Han Serif CN");
4511   text_style.decoration_style = txt::TextDecorationStyle::kSolid;
4512   text_style.decoration_color = SK_ColorBLACK;
4513   builder.PushStyle(text_style);
4514 
4515   builder.AddText(u16_text);
4516 
4517   builder.Pop();
4518 
4519   auto paragraph = BuildParagraph(builder);
4520   paragraph->Layout(GetTestCanvasWidth() - 100);
4521 
4522   paragraph->Paint(GetCanvas(), 0, 0);
4523 
4524   SkPaint paint;
4525   paint.setStyle(SkPaint::kStroke_Style);
4526   paint.setAntiAlias(true);
4527   paint.setStrokeWidth(1);
4528   paint.setColor(SK_ColorRED);
4529   GetCanvas()->drawLine(0, paragraph->GetIdeographicBaseline(),
4530                         paragraph->GetMaxWidth(),
4531                         paragraph->GetIdeographicBaseline(), paint);
4532 
4533   paint.setColor(SK_ColorGREEN);
4534 
4535   GetCanvas()->drawLine(0, paragraph->GetAlphabeticBaseline(),
4536                         paragraph->GetMaxWidth(),
4537                         paragraph->GetAlphabeticBaseline(), paint);
4538   ASSERT_DOUBLE_EQ(paragraph->GetIdeographicBaseline(), 79.035000801086426);
4539   ASSERT_DOUBLE_EQ(paragraph->GetAlphabeticBaseline(), 63.305000305175781);
4540 
4541   ASSERT_TRUE(Snapshot());
4542 }
4543 
TEST_F(ParagraphTest,FontFallbackParagraph)4544 TEST_F(ParagraphTest, FontFallbackParagraph) {
4545   const char* text = "Roboto 字典 ";
4546   auto icu_text = icu::UnicodeString::fromUTF8(text);
4547   std::u16string u16_text(icu_text.getBuffer(),
4548                           icu_text.getBuffer() + icu_text.length());
4549   const char* text2 = "Homemade Apple 字典";
4550   icu_text = icu::UnicodeString::fromUTF8(text2);
4551   std::u16string u16_text2(icu_text.getBuffer(),
4552                            icu_text.getBuffer() + icu_text.length());
4553   const char* text3 = "Chinese 字典";
4554   icu_text = icu::UnicodeString::fromUTF8(text3);
4555   std::u16string u16_text3(icu_text.getBuffer(),
4556                            icu_text.getBuffer() + icu_text.length());
4557 
4558   txt::ParagraphStyle paragraph_style;
4559   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4560 
4561   txt::TextStyle text_style;
4562   // No chinese fallback provided, should not be able to render the chinese.
4563   text_style.font_families = std::vector<std::string>(1, "Not a real font");
4564   text_style.font_families.push_back("Also a fake font");
4565   text_style.font_families.push_back("So fake it is obvious");
4566   text_style.font_families.push_back("Next one should be a real font...");
4567   text_style.font_families.push_back("Roboto");
4568   text_style.font_families.push_back("another fake one in between");
4569   text_style.font_families.push_back("Homemade Apple");
4570   text_style.color = SK_ColorBLACK;
4571   builder.PushStyle(text_style);
4572   builder.AddText(u16_text);
4573 
4574   // Japanese version of the chinese should be rendered.
4575   text_style.font_families = std::vector<std::string>(1, "Not a real font");
4576   text_style.font_families.push_back("Also a fake font");
4577   text_style.font_families.push_back("So fake it is obvious");
4578   text_style.font_families.push_back("Homemade Apple");
4579   text_style.font_families.push_back("Next one should be a real font...");
4580   text_style.font_families.push_back("Roboto");
4581   text_style.font_families.push_back("another fake one in between");
4582   text_style.font_families.push_back("Noto Sans CJK JP");
4583   text_style.font_families.push_back("Source Han Serif CN");
4584   text_style.color = SK_ColorBLACK;
4585   builder.PushStyle(text_style);
4586   builder.AddText(u16_text2);
4587 
4588   // Chinese font defiend first
4589   text_style.font_families = std::vector<std::string>(1, "Not a real font");
4590   text_style.font_families.push_back("Also a fake font");
4591   text_style.font_families.push_back("So fake it is obvious");
4592   text_style.font_families.push_back("Homemade Apple");
4593   text_style.font_families.push_back("Next one should be a real font...");
4594   text_style.font_families.push_back("Roboto");
4595   text_style.font_families.push_back("another fake one in between");
4596   text_style.font_families.push_back("Source Han Serif CN");
4597   text_style.font_families.push_back("Noto Sans CJK JP");
4598   text_style.color = SK_ColorBLACK;
4599   builder.PushStyle(text_style);
4600   builder.AddText(u16_text3);
4601 
4602   builder.Pop();
4603 
4604   auto paragraph = BuildParagraph(builder);
4605   paragraph->Layout(GetTestCanvasWidth());
4606 
4607   paragraph->Paint(GetCanvas(), 10.0, 15.0);
4608 
4609   ASSERT_TRUE(Snapshot());
4610 
4611   ASSERT_EQ(paragraph->records_.size(), 5ull);
4612   ASSERT_DOUBLE_EQ(paragraph->records_[0].GetRunWidth(), 64.19921875);
4613   ASSERT_DOUBLE_EQ(paragraph->records_[1].GetRunWidth(), 139.1171875);
4614   ASSERT_DOUBLE_EQ(paragraph->records_[2].GetRunWidth(), 28);
4615   ASSERT_DOUBLE_EQ(paragraph->records_[3].GetRunWidth(), 62.24609375);
4616   ASSERT_DOUBLE_EQ(paragraph->records_[4].GetRunWidth(), 28);
4617   // When a different font is resolved, then the metrics are different.
4618   ASSERT_TRUE(paragraph->records_[2].metrics().fTop -
4619                   paragraph->records_[4].metrics().fTop !=
4620               0);
4621   ASSERT_TRUE(paragraph->records_[2].metrics().fAscent -
4622                   paragraph->records_[4].metrics().fAscent !=
4623               0);
4624   ASSERT_TRUE(paragraph->records_[2].metrics().fDescent -
4625                   paragraph->records_[4].metrics().fDescent !=
4626               0);
4627   ASSERT_TRUE(paragraph->records_[2].metrics().fBottom -
4628                   paragraph->records_[4].metrics().fBottom !=
4629               0);
4630   ASSERT_TRUE(paragraph->records_[2].metrics().fAvgCharWidth -
4631                   paragraph->records_[4].metrics().fAvgCharWidth !=
4632               0);
4633 }
4634 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (StrutParagraph1))4635 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph1)) {
4636   // The chinese extra height should be absorbed by the strut.
4637   const char* text = "01234満毎冠p来É本可\nabcd\n満毎É行p昼本可";
4638   auto icu_text = icu::UnicodeString::fromUTF8(text);
4639   std::u16string u16_text(icu_text.getBuffer(),
4640                           icu_text.getBuffer() + icu_text.length());
4641 
4642   txt::ParagraphStyle paragraph_style;
4643   paragraph_style.max_lines = 10;
4644   paragraph_style.strut_font_families = std::vector<std::string>(1, "BlahFake");
4645   paragraph_style.strut_font_families.push_back("ahem");
4646   paragraph_style.strut_font_size = 50;
4647   paragraph_style.strut_height = 1.8;
4648   paragraph_style.strut_has_height_override = true;
4649   paragraph_style.strut_leading = 0.1;
4650   paragraph_style.strut_enabled = true;
4651 
4652   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4653 
4654   txt::TextStyle text_style;
4655   text_style.font_families = std::vector<std::string>(1, "ahem");
4656   text_style.font_families.push_back("ahem");
4657   text_style.font_size = 50;
4658   text_style.letter_spacing = 0;
4659   text_style.font_weight = FontWeight::w500;
4660   text_style.word_spacing = 0;
4661   text_style.color = SK_ColorBLACK;
4662   text_style.height = .5;
4663   builder.PushStyle(text_style);
4664 
4665   builder.AddText(u16_text);
4666 
4667   builder.Pop();
4668 
4669   auto paragraph = BuildParagraph(builder);
4670   paragraph->Layout(550);
4671 
4672   paragraph->Paint(GetCanvas(), 0, 0);
4673 
4674   SkPaint paint;
4675   paint.setStyle(SkPaint::kStroke_Style);
4676   paint.setAntiAlias(true);
4677   paint.setStrokeWidth(1);
4678 
4679   // Tests for GetRectsForRange()
4680   Paragraph::RectHeightStyle rect_height_style =
4681       Paragraph::RectHeightStyle::kTight;
4682   Paragraph::RectHeightStyle rect_height_max_style =
4683       Paragraph::RectHeightStyle::kMax;
4684   Paragraph::RectWidthStyle rect_width_style =
4685       Paragraph::RectWidthStyle::kTight;
4686   paint.setColor(SK_ColorRED);
4687   std::vector<txt::Paragraph::TextBox> boxes =
4688       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4689   for (size_t i = 0; i < boxes.size(); ++i) {
4690     GetCanvas()->drawRect(boxes[i].rect, paint);
4691   }
4692   EXPECT_EQ(boxes.size(), 0ull);
4693 
4694   boxes =
4695       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4696   for (size_t i = 0; i < boxes.size(); ++i) {
4697     GetCanvas()->drawRect(boxes[i].rect, paint);
4698   }
4699   EXPECT_EQ(boxes.size(), 1ull);
4700   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4701   EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001);
4702   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
4703   EXPECT_NEAR(boxes[0].rect.bottom(), 84.5, 0.0001);
4704 
4705   boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
4706                                       rect_width_style);
4707   for (size_t i = 0; i < boxes.size(); ++i) {
4708     GetCanvas()->drawRect(boxes[i].rect, paint);
4709   }
4710   EXPECT_EQ(boxes.size(), 1ull);
4711   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4712   EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001);
4713   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
4714   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 95);
4715 
4716   boxes =
4717       paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
4718   for (size_t i = 0; i < boxes.size(); ++i) {
4719     GetCanvas()->drawRect(boxes[i].rect, paint);
4720   }
4721   EXPECT_EQ(boxes.size(), 1ull);
4722   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
4723   EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001);
4724   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
4725   EXPECT_NEAR(boxes[0].rect.bottom(), 84.5, 0.0001);
4726   ;
4727 
4728   boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
4729                                       rect_width_style);
4730   for (size_t i = 0; i < boxes.size(); ++i) {
4731     GetCanvas()->drawRect(boxes[i].rect, paint);
4732   }
4733   EXPECT_EQ(boxes.size(), 1ull);
4734   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
4735   EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001);
4736   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
4737   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 95);
4738 
4739   boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
4740                                       rect_width_style);
4741   for (size_t i = 0; i < boxes.size(); ++i) {
4742     GetCanvas()->drawRect(boxes[i].rect, paint);
4743   }
4744   EXPECT_EQ(boxes.size(), 1ull);
4745   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4746   EXPECT_NEAR(boxes[0].rect.top(), 224.5, 0.0001);
4747   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
4748   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 285);
4749 
4750   boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
4751                                       rect_width_style);
4752   for (size_t i = 0; i < boxes.size(); ++i) {
4753     GetCanvas()->drawRect(boxes[i].rect, paint);
4754   }
4755   EXPECT_EQ(boxes.size(), 1ull);
4756   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
4757   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 319.5);
4758   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
4759   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 380);
4760 
4761   ASSERT_TRUE(Snapshot());
4762 }
4763 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (StrutParagraph2))4764 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph2)) {
4765   // This string is all one size and smaller than the strut metrics.
4766   const char* text = "01234ABCDEFGH\nabcd\nABCDEFGH";
4767   auto icu_text = icu::UnicodeString::fromUTF8(text);
4768   std::u16string u16_text(icu_text.getBuffer(),
4769                           icu_text.getBuffer() + icu_text.length());
4770 
4771   txt::ParagraphStyle paragraph_style;
4772   paragraph_style.max_lines = 10;
4773   paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
4774   paragraph_style.strut_font_size = 50;
4775   paragraph_style.strut_height = 1.6;
4776   paragraph_style.strut_has_height_override = true;
4777   paragraph_style.strut_enabled = true;
4778   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4779 
4780   txt::TextStyle text_style;
4781   text_style.font_families = std::vector<std::string>(1, "ahem");
4782   text_style.font_families.push_back("ahem");
4783   text_style.font_size = 50;
4784   text_style.letter_spacing = 0;
4785   text_style.font_weight = FontWeight::w500;
4786   text_style.word_spacing = 0;
4787   text_style.color = SK_ColorBLACK;
4788   text_style.height = 1;
4789   builder.PushStyle(text_style);
4790 
4791   builder.AddText(u16_text);
4792 
4793   builder.Pop();
4794 
4795   auto paragraph = BuildParagraph(builder);
4796   paragraph->Layout(550);
4797 
4798   paragraph->Paint(GetCanvas(), 0, 0);
4799 
4800   SkPaint paint;
4801   paint.setStyle(SkPaint::kStroke_Style);
4802   paint.setAntiAlias(true);
4803   paint.setStrokeWidth(1);
4804 
4805   // Tests for GetRectsForRange()
4806   Paragraph::RectHeightStyle rect_height_style =
4807       Paragraph::RectHeightStyle::kTight;
4808   Paragraph::RectHeightStyle rect_height_max_style =
4809       Paragraph::RectHeightStyle::kMax;
4810   Paragraph::RectWidthStyle rect_width_style =
4811       Paragraph::RectWidthStyle::kTight;
4812   paint.setColor(SK_ColorRED);
4813   std::vector<txt::Paragraph::TextBox> boxes =
4814       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4815   for (size_t i = 0; i < boxes.size(); ++i) {
4816     GetCanvas()->drawRect(boxes[i].rect, paint);
4817   }
4818   EXPECT_EQ(boxes.size(), 0ull);
4819 
4820   boxes =
4821       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4822   for (size_t i = 0; i < boxes.size(); ++i) {
4823     GetCanvas()->drawRect(boxes[i].rect, paint);
4824   }
4825   EXPECT_EQ(boxes.size(), 1ull);
4826   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4827   EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001);
4828   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
4829   EXPECT_NEAR(boxes[0].rect.bottom(), 74, 0.0001);
4830 
4831   boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
4832                                       rect_width_style);
4833   for (size_t i = 0; i < boxes.size(); ++i) {
4834     GetCanvas()->drawRect(boxes[i].rect, paint);
4835   }
4836   EXPECT_EQ(boxes.size(), 1ull);
4837   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4838   EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001);
4839   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
4840   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
4841 
4842   boxes =
4843       paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
4844   for (size_t i = 0; i < boxes.size(); ++i) {
4845     GetCanvas()->drawRect(boxes[i].rect, paint);
4846   }
4847   EXPECT_EQ(boxes.size(), 1ull);
4848   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
4849   EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001);
4850   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
4851   EXPECT_NEAR(boxes[0].rect.bottom(), 74, 0.0001);
4852 
4853   boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
4854                                       rect_width_style);
4855   for (size_t i = 0; i < boxes.size(); ++i) {
4856     GetCanvas()->drawRect(boxes[i].rect, paint);
4857   }
4858   EXPECT_EQ(boxes.size(), 1ull);
4859   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
4860   EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001);
4861   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
4862   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
4863 
4864   boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
4865                                       rect_width_style);
4866   for (size_t i = 0; i < boxes.size(); ++i) {
4867     GetCanvas()->drawRect(boxes[i].rect, paint);
4868   }
4869   EXPECT_EQ(boxes.size(), 1ull);
4870   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4871   EXPECT_NEAR(boxes[0].rect.top(), 184, 0.0001);
4872   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
4873   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240);
4874 
4875   boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
4876                                       rect_width_style);
4877   for (size_t i = 0; i < boxes.size(); ++i) {
4878     GetCanvas()->drawRect(boxes[i].rect, paint);
4879   }
4880   EXPECT_EQ(boxes.size(), 1ull);
4881   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
4882   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 264);
4883   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
4884   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 320);
4885 
4886   ASSERT_TRUE(Snapshot());
4887 }
4888 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (StrutParagraph3))4889 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph3)) {
4890   // The strut is too small to absorb the extra chinese height, but the english
4891   // second line height is increased due to strut.
4892   const char* text = "01234満毎p行来昼本可\nabcd\n満毎冠行来昼本可";
4893   auto icu_text = icu::UnicodeString::fromUTF8(text);
4894   std::u16string u16_text(icu_text.getBuffer(),
4895                           icu_text.getBuffer() + icu_text.length());
4896 
4897   txt::ParagraphStyle paragraph_style;
4898   paragraph_style.max_lines = 10;
4899   paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
4900   paragraph_style.strut_font_size = 50;
4901   paragraph_style.strut_height = 1.2;
4902   paragraph_style.strut_has_height_override = true;
4903   paragraph_style.strut_enabled = true;
4904   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4905 
4906   txt::TextStyle text_style;
4907   text_style.font_families = std::vector<std::string>(1, "ahem");
4908   text_style.font_families.push_back("ahem");
4909   text_style.font_size = 50;
4910   text_style.letter_spacing = 0;
4911   text_style.font_weight = FontWeight::w500;
4912   text_style.word_spacing = 0;
4913   text_style.color = SK_ColorBLACK;
4914   text_style.height = 1;
4915   builder.PushStyle(text_style);
4916 
4917   builder.AddText(u16_text);
4918 
4919   builder.Pop();
4920 
4921   auto paragraph = BuildParagraph(builder);
4922   paragraph->Layout(550);
4923 
4924   paragraph->Paint(GetCanvas(), 0, 0);
4925 
4926   SkPaint paint;
4927   paint.setStyle(SkPaint::kStroke_Style);
4928   paint.setAntiAlias(true);
4929   paint.setStrokeWidth(1);
4930 
4931   // Tests for GetRectsForRange()
4932   Paragraph::RectHeightStyle rect_height_style =
4933       Paragraph::RectHeightStyle::kTight;
4934   Paragraph::RectHeightStyle rect_height_max_style =
4935       Paragraph::RectHeightStyle::kMax;
4936   Paragraph::RectWidthStyle rect_width_style =
4937       Paragraph::RectWidthStyle::kTight;
4938   paint.setColor(SK_ColorRED);
4939   std::vector<txt::Paragraph::TextBox> boxes =
4940       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4941   for (size_t i = 0; i < boxes.size(); ++i) {
4942     GetCanvas()->drawRect(boxes[i].rect, paint);
4943   }
4944   EXPECT_EQ(boxes.size(), 0ull);
4945 
4946   boxes =
4947       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4948   for (size_t i = 0; i < boxes.size(); ++i) {
4949     GetCanvas()->drawRect(boxes[i].rect, paint);
4950   }
4951   EXPECT_EQ(boxes.size(), 1ull);
4952   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4953   EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001);
4954   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
4955   EXPECT_NEAR(boxes[0].rect.bottom(), 58, 0.0001);
4956 
4957   boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
4958                                       rect_width_style);
4959   for (size_t i = 0; i < boxes.size(); ++i) {
4960     GetCanvas()->drawRect(boxes[i].rect, paint);
4961   }
4962   EXPECT_EQ(boxes.size(), 1ull);
4963   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4964   EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001);
4965   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
4966   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 60);
4967 
4968   boxes =
4969       paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
4970   for (size_t i = 0; i < boxes.size(); ++i) {
4971     GetCanvas()->drawRect(boxes[i].rect, paint);
4972   }
4973   EXPECT_EQ(boxes.size(), 1ull);
4974   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
4975   EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001);
4976   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
4977   EXPECT_NEAR(boxes[0].rect.bottom(), 58, 0.0001);
4978 
4979   boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
4980                                       rect_width_style);
4981   for (size_t i = 0; i < boxes.size(); ++i) {
4982     GetCanvas()->drawRect(boxes[i].rect, paint);
4983   }
4984   EXPECT_EQ(boxes.size(), 1ull);
4985   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
4986   EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001);
4987   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
4988   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 60);
4989 
4990   boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
4991                                       rect_width_style);
4992   for (size_t i = 0; i < boxes.size(); ++i) {
4993     GetCanvas()->drawRect(boxes[i].rect, paint);
4994   }
4995   EXPECT_EQ(boxes.size(), 1ull);
4996   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4997   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 128);
4998   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
4999   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 180);
5000 
5001   boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
5002                                       rect_width_style);
5003   for (size_t i = 0; i < boxes.size(); ++i) {
5004     GetCanvas()->drawRect(boxes[i].rect, paint);
5005   }
5006   EXPECT_EQ(boxes.size(), 1ull);
5007   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
5008   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 188);
5009   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
5010   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240);
5011 
5012   ASSERT_TRUE(Snapshot());
5013 }
5014 
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (StrutForceParagraph))5015 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutForceParagraph)) {
5016   // The strut is too small to absorb the extra chinese height, but the english
5017   // second line height is increased due to strut.
5018   const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
5019   auto icu_text = icu::UnicodeString::fromUTF8(text);
5020   std::u16string u16_text(icu_text.getBuffer(),
5021                           icu_text.getBuffer() + icu_text.length());
5022 
5023   txt::ParagraphStyle paragraph_style;
5024   paragraph_style.max_lines = 10;
5025   paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
5026   paragraph_style.strut_font_size = 50;
5027   paragraph_style.strut_height = 1.5;
5028   paragraph_style.strut_has_height_override = true;
5029   paragraph_style.strut_leading = 0.1;
5030   paragraph_style.force_strut_height = true;
5031   paragraph_style.strut_enabled = true;
5032   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5033 
5034   txt::TextStyle text_style;
5035   text_style.font_families = std::vector<std::string>(1, "ahem");
5036   text_style.font_families.push_back("ahem");
5037   text_style.font_size = 50;
5038   text_style.letter_spacing = 0;
5039   text_style.word_spacing = 0;
5040   text_style.color = SK_ColorBLACK;
5041   text_style.height = 1;
5042   builder.PushStyle(text_style);
5043 
5044   builder.AddText(u16_text);
5045 
5046   builder.Pop();
5047 
5048   auto paragraph = BuildParagraph(builder);
5049   paragraph->Layout(550);
5050 
5051   paragraph->Paint(GetCanvas(), 0, 0);
5052 
5053   SkPaint paint;
5054   paint.setStyle(SkPaint::kStroke_Style);
5055   paint.setAntiAlias(true);
5056   paint.setStrokeWidth(1);
5057 
5058   // Tests for GetRectsForRange()
5059   Paragraph::RectHeightStyle rect_height_style =
5060       Paragraph::RectHeightStyle::kTight;
5061   Paragraph::RectHeightStyle rect_height_max_style =
5062       Paragraph::RectHeightStyle::kMax;
5063   Paragraph::RectWidthStyle rect_width_style =
5064       Paragraph::RectWidthStyle::kTight;
5065   paint.setColor(SK_ColorRED);
5066   std::vector<txt::Paragraph::TextBox> boxes =
5067       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
5068   for (size_t i = 0; i < boxes.size(); ++i) {
5069     GetCanvas()->drawRect(boxes[i].rect, paint);
5070   }
5071   EXPECT_EQ(boxes.size(), 0ull);
5072 
5073   boxes =
5074       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
5075   for (size_t i = 0; i < boxes.size(); ++i) {
5076     GetCanvas()->drawRect(boxes[i].rect, paint);
5077   }
5078   EXPECT_EQ(boxes.size(), 1ull);
5079   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5080   EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001);
5081   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
5082   EXPECT_NEAR(boxes[0].rect.bottom(), 72.5, 0.0001);
5083 
5084   boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
5085                                       rect_width_style);
5086   for (size_t i = 0; i < boxes.size(); ++i) {
5087     GetCanvas()->drawRect(boxes[i].rect, paint);
5088   }
5089   EXPECT_EQ(boxes.size(), 1ull);
5090   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5091   EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001);
5092   ;
5093   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
5094   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
5095 
5096   boxes =
5097       paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
5098   for (size_t i = 0; i < boxes.size(); ++i) {
5099     GetCanvas()->drawRect(boxes[i].rect, paint);
5100   }
5101   EXPECT_EQ(boxes.size(), 1ull);
5102   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
5103   EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001);
5104   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
5105   EXPECT_NEAR(boxes[0].rect.bottom(), 72.5, 0.0001);
5106 
5107   boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
5108                                       rect_width_style);
5109   for (size_t i = 0; i < boxes.size(); ++i) {
5110     GetCanvas()->drawRect(boxes[i].rect, paint);
5111   }
5112   EXPECT_EQ(boxes.size(), 1ull);
5113   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
5114   EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001);
5115   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
5116   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
5117 
5118   boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
5119                                       rect_width_style);
5120   for (size_t i = 0; i < boxes.size(); ++i) {
5121     GetCanvas()->drawRect(boxes[i].rect, paint);
5122   }
5123   EXPECT_EQ(boxes.size(), 1ull);
5124   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5125   EXPECT_NEAR(boxes[0].rect.top(), 182.5, 0.0001);
5126   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
5127   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240);
5128 
5129   boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
5130                                       rect_width_style);
5131   for (size_t i = 0; i < boxes.size(); ++i) {
5132     GetCanvas()->drawRect(boxes[i].rect, paint);
5133   }
5134   EXPECT_EQ(boxes.size(), 1ull);
5135   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
5136   EXPECT_FLOAT_EQ(boxes[0].rect.top(), 262.5);
5137   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
5138   EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 320);
5139 
5140   ASSERT_TRUE(Snapshot());
5141 }
5142 
5143 // The height override is disabled for this test. Direct metrics from the font.
TEST_F(ParagraphTest,DISABLE_ON_WINDOWS (StrutDefaultParagraph))5144 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutDefaultParagraph)) {
5145   const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
5146   auto icu_text = icu::UnicodeString::fromUTF8(text);
5147   std::u16string u16_text(icu_text.getBuffer(),
5148                           icu_text.getBuffer() + icu_text.length());
5149 
5150   txt::ParagraphStyle paragraph_style;
5151   paragraph_style.max_lines = 10;
5152   paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
5153   paragraph_style.strut_font_size = 50;
5154   paragraph_style.strut_height = 1.5;
5155   paragraph_style.strut_leading = 0.1;
5156   paragraph_style.force_strut_height = false;
5157   paragraph_style.strut_enabled = true;
5158   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5159 
5160   txt::TextStyle text_style;
5161   text_style.font_families = std::vector<std::string>(1, "ahem");
5162   text_style.font_families.push_back("ahem");
5163   text_style.font_size = 20;
5164   text_style.letter_spacing = 0;
5165   text_style.word_spacing = 0;
5166   text_style.color = SK_ColorBLACK;
5167   text_style.height = 1;
5168   builder.PushStyle(text_style);
5169 
5170   builder.AddText(u16_text);
5171 
5172   builder.Pop();
5173 
5174   auto paragraph = BuildParagraph(builder);
5175   paragraph->Layout(550);
5176 
5177   paragraph->Paint(GetCanvas(), 0, 0);
5178 
5179   SkPaint paint;
5180   paint.setStyle(SkPaint::kStroke_Style);
5181   paint.setAntiAlias(true);
5182   paint.setStrokeWidth(1);
5183 
5184   // Tests for GetRectsForRange()
5185   Paragraph::RectHeightStyle rect_height_style =
5186       Paragraph::RectHeightStyle::kTight;
5187   Paragraph::RectHeightStyle rect_height_strut_style =
5188       Paragraph::RectHeightStyle::kStrut;
5189   Paragraph::RectWidthStyle rect_width_style =
5190       Paragraph::RectWidthStyle::kTight;
5191   paint.setColor(SK_ColorRED);
5192   std::vector<txt::Paragraph::TextBox> boxes =
5193       paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
5194   for (size_t i = 0; i < boxes.size(); ++i) {
5195     GetCanvas()->drawRect(boxes[i].rect, paint);
5196   }
5197   EXPECT_EQ(boxes.size(), 0ull);
5198 
5199   boxes =
5200       paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
5201   for (size_t i = 0; i < boxes.size(); ++i) {
5202     GetCanvas()->drawRect(boxes[i].rect, paint);
5203   }
5204   EXPECT_EQ(boxes.size(), 1ull);
5205   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5206   EXPECT_NEAR(boxes[0].rect.top(), 26.5, 0.0001);
5207   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 20);
5208   EXPECT_NEAR(boxes[0].rect.bottom(), 46.5, 0.0001);
5209 
5210   boxes = paragraph->GetRectsForRange(0, 2, rect_height_strut_style,
5211                                       rect_width_style);
5212   for (size_t i = 0; i < boxes.size(); ++i) {
5213     GetCanvas()->drawRect(boxes[i].rect, paint);
5214   }
5215   EXPECT_EQ(boxes.size(), 1ull);
5216   EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5217   EXPECT_NEAR(boxes[0].rect.top(), 2.5, 0.0001);
5218   EXPECT_FLOAT_EQ(boxes[0].rect.right(), 40);
5219   EXPECT_NEAR(boxes[0].rect.bottom(), 52.5, 0.0001);
5220 
5221   ASSERT_TRUE(Snapshot());
5222 }
5223 
TEST_F(ParagraphTest,FontFeaturesParagraph)5224 TEST_F(ParagraphTest, FontFeaturesParagraph) {
5225   const char* text = "12ab\n";
5226   auto icu_text = icu::UnicodeString::fromUTF8(text);
5227   std::u16string u16_text(icu_text.getBuffer(),
5228                           icu_text.getBuffer() + icu_text.length());
5229 
5230   txt::ParagraphStyle paragraph_style;
5231   txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5232 
5233   txt::TextStyle text_style;
5234   text_style.font_families = std::vector<std::string>(1, "Roboto");
5235   text_style.color = SK_ColorBLACK;
5236   text_style.font_features.SetFeature("tnum", 1);
5237   builder.PushStyle(text_style);
5238   builder.AddText(u16_text);
5239 
5240   text_style.font_features.SetFeature("tnum", 0);
5241   text_style.font_features.SetFeature("pnum", 1);
5242   builder.PushStyle(text_style);
5243   builder.AddText(u16_text);
5244 
5245   builder.Pop();
5246   builder.Pop();
5247 
5248   auto paragraph = BuildParagraph(builder);
5249   paragraph->Layout(GetTestCanvasWidth());
5250 
5251   paragraph->Paint(GetCanvas(), 10.0, 15.0);
5252 
5253   ASSERT_EQ(paragraph->glyph_lines_.size(), 3ull);
5254 
5255   // Tabular numbers should have equal widths.
5256   const txt::ParagraphTxt::GlyphLine& tnum_line = paragraph->glyph_lines_[0];
5257   ASSERT_EQ(tnum_line.positions.size(), 4ull);
5258   EXPECT_FLOAT_EQ(tnum_line.positions[0].x_pos.width(),
5259                   tnum_line.positions[1].x_pos.width());
5260 
5261   // Proportional numbers should have variable widths.
5262   const txt::ParagraphTxt::GlyphLine& pnum_line = paragraph->glyph_lines_[1];
5263   ASSERT_EQ(pnum_line.positions.size(), 4ull);
5264   EXPECT_NE(pnum_line.positions[0].x_pos.width(),
5265             pnum_line.positions[1].x_pos.width());
5266 
5267   // Alphabetic characters should be unaffected.
5268   EXPECT_FLOAT_EQ(tnum_line.positions[2].x_pos.width(),
5269                   pnum_line.positions[2].x_pos.width());
5270 
5271   ASSERT_TRUE(Snapshot());
5272 }
5273 
5274 }  // namespace txt
5275