Flutter Engine
paragraph_unittests.cc
Go to the documentation of this file.
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 <cstring>
18 #include <iostream>
19 
20 #include "flutter/fml/logging.h"
21 #include "render_test.h"
22 #include "third_party/icu/source/common/unicode/unistr.h"
23 #include "third_party/skia/include/core/SkColor.h"
24 #include "third_party/skia/include/core/SkPath.h"
25 #include "txt/font_style.h"
26 #include "txt/font_weight.h"
28 #include "txt/paragraph_txt.h"
29 #include "txt/placeholder_run.h"
30 #include "txt_test_utils.h"
31 
32 #define DISABLE_ON_WINDOWS(TEST) DISABLE_TEST_WINDOWS(TEST)
33 #define DISABLE_ON_MAC(TEST) DISABLE_TEST_MAC(TEST)
34 
35 namespace txt {
36 
38 
39 TEST_F(ParagraphTest, SimpleParagraph) {
40  const char* text = "Hello World Text Dialog";
41  auto icu_text = icu::UnicodeString::fromUTF8(text);
42  std::u16string u16_text(icu_text.getBuffer(),
43  icu_text.getBuffer() + icu_text.length());
44 
45  txt::ParagraphStyle paragraph_style;
46  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
47 
48  txt::TextStyle text_style;
49  // We must supply a font here, as the default is Arial, and we do not
50  // include Arial in our test fonts as it is proprietary. We want it to
51  // be Arial default though as it is one of the most common fonts on host
52  // platforms. On real devices/apps, Arial should be able to be resolved.
53  text_style.font_families = std::vector<std::string>(1, "Roboto");
54  text_style.color = SK_ColorBLACK;
55  builder.PushStyle(text_style);
56  builder.AddText(u16_text);
57 
58  builder.Pop();
59 
60  auto paragraph = BuildParagraph(builder);
61  paragraph->Layout(GetTestCanvasWidth());
62 
63  paragraph->Paint(GetCanvas(), 10.0, 15.0);
64 
65  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
66  for (size_t i = 0; i < u16_text.length(); i++) {
67  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
68  }
69  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
70  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
71  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
72  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
73  ASSERT_TRUE(Snapshot());
74 }
75 
76 TEST_F(ParagraphTest, SimpleParagraphSmall) {
77  const char* text =
78  "Hello World Text Dialog. This is a very small text in order to check "
79  "for constant advance additions that are only visible when the advance "
80  "of the glyphs are small.";
81  auto icu_text = icu::UnicodeString::fromUTF8(text);
82  std::u16string u16_text(icu_text.getBuffer(),
83  icu_text.getBuffer() + icu_text.length());
84 
85  txt::ParagraphStyle paragraph_style;
86  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
87 
88  txt::TextStyle text_style;
89  text_style.font_size = 6;
90  // We must supply a font here, as the default is Arial, and we do not
91  // include Arial in our test fonts as it is proprietary. We want it to
92  // be Arial default though as it is one of the most common fonts on host
93  // platforms. On real devices/apps, Arial should be able to be resolved.
94  text_style.font_families = std::vector<std::string>(1, "Roboto");
95  text_style.color = SK_ColorBLACK;
96  builder.PushStyle(text_style);
97  builder.AddText(u16_text);
98 
99  builder.Pop();
100 
101  auto paragraph = BuildParagraph(builder);
102  paragraph->Layout(GetTestCanvasWidth());
103 
104  paragraph->Paint(GetCanvas(), 10.0, 15.0);
105 
106  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
107  for (size_t i = 0; i < u16_text.length(); i++) {
108  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
109  }
110  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
111  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
112  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
113  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
114  ASSERT_TRUE(Snapshot());
115 }
116 
117 // It is possible for the line_metrics_ vector in paragraph to have an empty
118 // line at the end as a result of the line breaking algorithm. This causes
119 // the final_line_count_ to be one less than line metrics. This tests that we
120 // properly handle this case and do not segfault.
121 TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateSegfault) {
122  const char* text = "Hello World\nText Dialog";
123  auto icu_text = icu::UnicodeString::fromUTF8(text);
124  std::u16string u16_text(icu_text.getBuffer(),
125  icu_text.getBuffer() + icu_text.length());
126 
127  txt::ParagraphStyle paragraph_style;
128  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
129 
130  txt::TextStyle text_style;
131  // We must supply a font here, as the default is Arial, and we do not
132  // include Arial in our test fonts as it is proprietary. We want it to
133  // be Arial default though as it is one of the most common fonts on host
134  // platforms. On real devices/apps, Arial should be able to be resolved.
135  text_style.font_families = std::vector<std::string>(1, "Roboto");
136  text_style.color = SK_ColorBLACK;
137  builder.PushStyle(text_style);
138  builder.AddText(u16_text);
139 
140  builder.Pop();
141 
142  auto paragraph = BuildParagraph(builder);
143  paragraph->Layout(GetTestCanvasWidth());
144 
145  paragraph->Paint(GetCanvas(), 10.0, 15.0);
146 
147  ASSERT_EQ(paragraph->final_line_count_, paragraph->line_metrics_.size());
148  ASSERT_EQ(paragraph->final_line_count_, 2ull);
149  ASSERT_EQ(paragraph->GetLineCount(), 2ull);
150 
151  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 0.2).position, 0ull);
152  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20.2, 0.2).position, 3ull);
153  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 20.2).position, 12ull);
154 
155  // We artificially reproduce the conditions that cause segfaults in very
156  // specific circumstances in the wild. By adding this empty un-laid-out
157  // LineMetrics at the end, we force the case where final_line_count_
158  // represents the true number of lines whereas line_metrics_ has one
159  // extra empty one.
160  paragraph->line_metrics_.emplace_back(23, 24, 24, 24, true);
161 
162  ASSERT_EQ(paragraph->final_line_count_, paragraph->line_metrics_.size() - 1);
163  ASSERT_EQ(paragraph->final_line_count_, 2ull);
164  ASSERT_EQ(paragraph->GetLineCount(), 2ull);
165 
166  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 20.2).position, 12ull);
167  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 0.2).position, 0ull);
168  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20.2, 0.2).position, 3ull);
169 
170  paragraph->line_metrics_.emplace_back(24, 25, 25, 25, true);
171 
172  ASSERT_EQ(paragraph->final_line_count_, paragraph->line_metrics_.size() - 2);
173  ASSERT_EQ(paragraph->final_line_count_, 2ull);
174  ASSERT_EQ(paragraph->GetLineCount(), 2ull);
175 
176  ASSERT_TRUE(Snapshot());
177 }
178 
179 // Check that GetGlyphPositionAtCoordinate computes correct text positions for
180 // a paragraph containing multiple styled runs.
181 TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateMultiRun) {
182  txt::ParagraphStyle paragraph_style;
183  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
184 
185  txt::TextStyle text_style;
186  text_style.font_families = std::vector<std::string>(1, "Ahem");
187  text_style.color = SK_ColorBLACK;
188  text_style.font_size = 10;
189  builder.PushStyle(text_style);
190  builder.AddText(u"A");
191  text_style.font_size = 20;
192  builder.PushStyle(text_style);
193  builder.AddText(u"B");
194  text_style.font_size = 30;
195  builder.PushStyle(text_style);
196  builder.AddText(u"C");
197 
198  auto paragraph = BuildParagraph(builder);
199  paragraph->Layout(GetTestCanvasWidth());
200 
201  paragraph->Paint(GetCanvas(), 10.0, 15.0);
202 
203  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(2.0, 5.0).position, 0ull);
204  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(12.0, 5.0).position, 1ull);
205  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(32.0, 5.0).position, 2ull);
206 
207  ASSERT_TRUE(Snapshot());
208 }
209 
210 TEST_F(ParagraphTest, LineMetricsParagraph1) {
211  const char* text = "Hello! What is going on?\nSecond line \nthirdline";
212  auto icu_text = icu::UnicodeString::fromUTF8(text);
213  std::u16string u16_text(icu_text.getBuffer(),
214  icu_text.getBuffer() + icu_text.length());
215 
216  txt::ParagraphStyle paragraph_style;
217  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
218 
219  txt::TextStyle text_style;
220  // We must supply a font here, as the default is Arial, and we do not
221  // include Arial in our test fonts as it is proprietary. We want it to
222  // be Arial default though as it is one of the most common fonts on host
223  // platforms. On real devices/apps, Arial should be able to be resolved.
224  text_style.font_families = std::vector<std::string>(1, "Roboto");
225  text_style.color = SK_ColorBLACK;
226  builder.PushStyle(text_style);
227  builder.AddText(u16_text);
228 
229  builder.Pop();
230 
231  auto paragraph = BuildParagraph(builder);
232  paragraph->Layout(GetTestCanvasWidth());
233 
234  paragraph->Paint(GetCanvas(), 0, 0);
235 
236  ASSERT_TRUE(Snapshot());
237 
238  ASSERT_EQ(paragraph->GetLineMetrics().size(), 3ull);
239  ASSERT_EQ(paragraph->GetLineMetrics()[0].start_index, 0ull);
240  ASSERT_EQ(paragraph->GetLineMetrics()[0].end_index, 24ull);
241  ASSERT_EQ(paragraph->GetLineMetrics()[0].end_including_newline, 25ull);
242  ASSERT_EQ(paragraph->GetLineMetrics()[0].end_excluding_whitespace, 24ull);
243  ASSERT_EQ(paragraph->GetLineMetrics()[0].hard_break, true);
244  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].ascent, 12.988281);
245  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].descent, 3.4179688);
246  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].width, 149.72266);
247  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].left, 0.0);
248  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].baseline, 12.582031);
249  ASSERT_EQ(paragraph->GetLineMetrics()[0].line_number, 0ull);
250  ASSERT_EQ(paragraph->GetLineMetrics()[0].run_metrics.size(), 1ull);
251  ASSERT_EQ(
252  paragraph->GetLineMetrics()[0]
253  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
254  ->second.text_style->color,
255  SK_ColorBLACK);
256  ASSERT_EQ(
257  paragraph->GetLineMetrics()[0]
258  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
259  ->second.text_style->font_families,
260  std::vector<std::string>(1, "Roboto"));
261  ASSERT_FLOAT_EQ(
262  paragraph->GetLineMetrics()[0]
263  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
264  ->second.font_metrics.fAscent,
265  -12.988281);
266  ASSERT_FLOAT_EQ(
267  paragraph->GetLineMetrics()[0]
268  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
269  ->second.font_metrics.fDescent,
270  3.4179688);
271  ASSERT_FLOAT_EQ(
272  paragraph->GetLineMetrics()[0]
273  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
274  ->second.font_metrics.fXHeight,
275  7.3964844);
276  ASSERT_FLOAT_EQ(
277  paragraph->GetLineMetrics()[0]
278  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
279  ->second.font_metrics.fLeading,
280  0);
281  ASSERT_FLOAT_EQ(
282  paragraph->GetLineMetrics()[0]
283  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
284  ->second.font_metrics.fTop,
285  -14.786133);
286  ASSERT_FLOAT_EQ(
287  paragraph->GetLineMetrics()[0]
288  .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index)
289  ->second.font_metrics.fUnderlinePosition,
290  1.0253906);
291 
292  ASSERT_EQ(paragraph->GetLineMetrics()[1].start_index, 25ull);
293  ASSERT_EQ(paragraph->GetLineMetrics()[1].end_index, 37ull);
294  ASSERT_EQ(paragraph->GetLineMetrics()[1].end_including_newline, 38ull);
295  ASSERT_EQ(paragraph->GetLineMetrics()[1].end_excluding_whitespace, 36ull);
296  ASSERT_EQ(paragraph->GetLineMetrics()[1].hard_break, true);
297  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].ascent, 12.988281);
298  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].descent, 3.4179688);
299  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].width, 72.0625);
300  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].left, 0.0);
301  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].baseline, 28.582031);
302  ASSERT_EQ(paragraph->GetLineMetrics()[1].line_number, 1ull);
303  ASSERT_EQ(paragraph->GetLineMetrics()[1].run_metrics.size(), 1ull);
304  ASSERT_EQ(
305  paragraph->GetLineMetrics()[1]
306  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
307  ->second.text_style->color,
308  SK_ColorBLACK);
309  ASSERT_EQ(
310  paragraph->GetLineMetrics()[1]
311  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
312  ->second.text_style->font_families,
313  std::vector<std::string>(1, "Roboto"));
314  ASSERT_FLOAT_EQ(
315  paragraph->GetLineMetrics()[1]
316  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
317  ->second.font_metrics.fAscent,
318  -12.988281);
319  ASSERT_FLOAT_EQ(
320  paragraph->GetLineMetrics()[1]
321  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
322  ->second.font_metrics.fDescent,
323  3.4179688);
324  ASSERT_FLOAT_EQ(
325  paragraph->GetLineMetrics()[1]
326  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
327  ->second.font_metrics.fXHeight,
328  7.3964844);
329  ASSERT_FLOAT_EQ(
330  paragraph->GetLineMetrics()[1]
331  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
332  ->second.font_metrics.fLeading,
333  0);
334  ASSERT_FLOAT_EQ(
335  paragraph->GetLineMetrics()[1]
336  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
337  ->second.font_metrics.fTop,
338  -14.786133);
339  ASSERT_FLOAT_EQ(
340  paragraph->GetLineMetrics()[1]
341  .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index)
342  ->second.font_metrics.fUnderlinePosition,
343  1.0253906);
344 }
345 
346 TEST_F(ParagraphTest, DISABLE_ON_MAC(LineMetricsParagraph2)) {
347  const char* text = "test string alphabetic";
348  auto icu_text = icu::UnicodeString::fromUTF8(text);
349  std::u16string alphabetic(icu_text.getBuffer(),
350  icu_text.getBuffer() + icu_text.length());
351 
352  const char* text2 = "测试中文日本語한국어";
353  auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
354  std::u16string cjk(icu_text2.getBuffer(),
355  icu_text2.getBuffer() + icu_text2.length());
356 
357  txt::ParagraphStyle paragraph_style;
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_families.push_back("Noto Sans CJK JP");
363  text_style.font_size = 27;
364  text_style.color = SK_ColorBLACK;
365  builder.PushStyle(text_style);
366  builder.AddText(alphabetic);
367 
368  text_style.font_size = 24;
369  builder.PushStyle(text_style);
370  builder.AddText(cjk);
371 
372  builder.Pop();
373 
374  auto paragraph = BuildParagraph(builder);
375  paragraph->Layout(350);
376 
377  paragraph->Paint(GetCanvas(), 0, 0);
378 
379  ASSERT_TRUE(Snapshot());
380 
381  ASSERT_EQ(paragraph->GetLineMetrics().size(), 2ull);
382  ASSERT_EQ(paragraph->GetLineMetrics()[0].start_index, 0ull);
383  ASSERT_EQ(paragraph->GetLineMetrics()[0].end_index, 26ull);
384  ASSERT_EQ(paragraph->GetLineMetrics()[0].end_including_newline, 26ull);
385  ASSERT_EQ(paragraph->GetLineMetrics()[0].end_excluding_whitespace, 26ull);
386  ASSERT_EQ(paragraph->GetLineMetrics()[0].hard_break, false);
387  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].ascent, 27.84);
388  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].descent, 7.6799998);
389  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].width, 348.61328);
390  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].left, 0.0);
391  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].baseline, 28.32);
392  ASSERT_EQ(paragraph->GetLineMetrics()[0].line_number, 0ull);
393  ASSERT_EQ(paragraph->GetLineMetrics()[0].run_metrics.size(), 2ull);
394  // First run
395  ASSERT_EQ(paragraph->GetLineMetrics()[0]
396  .run_metrics.lower_bound(2)
397  ->second.text_style->font_size,
398  27);
399  ASSERT_EQ(paragraph->GetLineMetrics()[0]
400  .run_metrics.lower_bound(2)
401  ->second.text_style->font_families,
402  text_style.font_families);
403  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
404  .run_metrics.lower_bound(2)
405  ->second.font_metrics.fAscent,
406  -25.048828);
407  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
408  .run_metrics.lower_bound(2)
409  ->second.font_metrics.fDescent,
410  6.5917969);
411 
412  ASSERT_EQ(paragraph->GetLineMetrics()[0]
413  .run_metrics.lower_bound(21)
414  ->second.text_style->font_size,
415  27);
416  ASSERT_EQ(paragraph->GetLineMetrics()[0]
417  .run_metrics.lower_bound(21)
418  ->second.text_style->font_families,
419  text_style.font_families);
420  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
421  .run_metrics.lower_bound(21)
422  ->second.font_metrics.fAscent,
423  -25.048828);
424  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
425  .run_metrics.lower_bound(21)
426  ->second.font_metrics.fDescent,
427  6.5917969);
428 
429  // Second run
430  ASSERT_EQ(paragraph->GetLineMetrics()[0]
431  .run_metrics.lower_bound(22)
432  ->second.text_style->font_size,
433  24);
434  ASSERT_EQ(paragraph->GetLineMetrics()[0]
435  .run_metrics.lower_bound(22)
436  ->second.text_style->font_families,
437  text_style.font_families);
438  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
439  .run_metrics.lower_bound(22)
440  ->second.font_metrics.fAscent,
441  -27.84);
442  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
443  .run_metrics.lower_bound(22)
444  ->second.font_metrics.fDescent,
445  7.6799998);
446 
447  ASSERT_EQ(paragraph->GetLineMetrics()[0]
448  .run_metrics.lower_bound(24)
449  ->second.text_style->font_size,
450  24);
451  ASSERT_EQ(paragraph->GetLineMetrics()[0]
452  .run_metrics.lower_bound(24)
453  ->second.text_style->font_families,
454  text_style.font_families);
455  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
456  .run_metrics.lower_bound(24)
457  ->second.font_metrics.fAscent,
458  -27.84);
459  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0]
460  .run_metrics.lower_bound(24)
461  ->second.font_metrics.fDescent,
462  7.6799998);
463 
464  ASSERT_EQ(paragraph->GetLineMetrics()[1].start_index, 26ull);
465  ASSERT_EQ(paragraph->GetLineMetrics()[1].end_index, 32ull);
466  ASSERT_EQ(paragraph->GetLineMetrics()[1].end_including_newline, 32ull);
467  ASSERT_EQ(paragraph->GetLineMetrics()[1].end_excluding_whitespace, 32ull);
468  ASSERT_EQ(paragraph->GetLineMetrics()[1].hard_break, true);
469  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].ascent, 27.84);
470  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].descent, 7.6799998);
471  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].width, 138.23438);
472  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].left, 0.0);
473  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].baseline, 64.32);
474  ASSERT_EQ(paragraph->GetLineMetrics()[1].line_number, 1ull);
475  ASSERT_EQ(paragraph->GetLineMetrics()[1].run_metrics.size(), 1ull);
476  // Indexing below the line will just resolve to the first run in the line.
477  ASSERT_EQ(paragraph->GetLineMetrics()[1]
478  .run_metrics.lower_bound(3)
479  ->second.text_style->font_size,
480  24);
481  ASSERT_EQ(paragraph->GetLineMetrics()[1]
482  .run_metrics.lower_bound(3)
483  ->second.text_style->font_families,
484  text_style.font_families);
485  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1]
486  .run_metrics.lower_bound(3)
487  ->second.font_metrics.fAscent,
488  -27.84);
489  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1]
490  .run_metrics.lower_bound(3)
491  ->second.font_metrics.fDescent,
492  7.6799998);
493 
494  // Indexing within the line
495  ASSERT_EQ(paragraph->GetLineMetrics()[1]
496  .run_metrics.lower_bound(31)
497  ->second.text_style->font_size,
498  24);
499  ASSERT_EQ(paragraph->GetLineMetrics()[1]
500  .run_metrics.lower_bound(31)
501  ->second.text_style->font_families,
502  text_style.font_families);
503  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1]
504  .run_metrics.lower_bound(31)
505  ->second.font_metrics.fAscent,
506  -27.84);
507  ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1]
508  .run_metrics.lower_bound(31)
509  ->second.font_metrics.fDescent,
510  7.6799998);
511 }
512 
513 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderParagraph)) {
514  const char* text = "012 34";
515  auto icu_text = icu::UnicodeString::fromUTF8(text);
516  std::u16string u16_text(icu_text.getBuffer(),
517  icu_text.getBuffer() + icu_text.length());
518 
519  txt::ParagraphStyle paragraph_style;
520  paragraph_style.max_lines = 14;
521  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
522 
523  txt::TextStyle text_style;
524  text_style.font_families = std::vector<std::string>(1, "Roboto");
525  text_style.font_size = 26;
526  text_style.letter_spacing = 1;
527  text_style.word_spacing = 5;
528  text_style.color = SK_ColorBLACK;
529  text_style.height = 1;
531  text_style.decoration_color = SK_ColorBLACK;
532  builder.PushStyle(text_style);
533 
534  builder.AddText(u16_text);
535 
538  builder.AddPlaceholder(placeholder_run);
539 
540  builder.AddText(u16_text);
541 
542  builder.AddPlaceholder(placeholder_run);
545  builder.AddPlaceholder(placeholder_run2);
546  builder.AddPlaceholder(placeholder_run);
547  builder.AddPlaceholder(placeholder_run2);
548  builder.AddText(u16_text);
549  builder.AddPlaceholder(placeholder_run2);
550 
551  builder.AddText(u16_text);
552  builder.AddText(u16_text);
553  builder.AddPlaceholder(placeholder_run2);
554  builder.AddPlaceholder(placeholder_run2);
555  builder.AddPlaceholder(placeholder_run2);
556  builder.AddPlaceholder(placeholder_run2);
557  builder.AddPlaceholder(placeholder_run2);
558  builder.AddPlaceholder(placeholder_run);
559  builder.AddText(u16_text);
560  builder.AddText(u16_text);
561  builder.AddText(u16_text);
562  builder.AddText(u16_text);
563  builder.AddText(u16_text);
564  builder.AddPlaceholder(placeholder_run2);
565  builder.AddPlaceholder(placeholder_run);
566  builder.AddText(u16_text);
567  builder.AddText(u16_text);
568 
569  builder.Pop();
570 
571  auto paragraph = BuildParagraph(builder);
572  paragraph->Layout(GetTestCanvasWidth());
573 
574  paragraph->Paint(GetCanvas(), 0, 0);
575 
576  SkPaint paint;
577  paint.setStyle(SkPaint::kStroke_Style);
578  paint.setAntiAlias(true);
579  paint.setStrokeWidth(1);
580 
581  Paragraph::RectHeightStyle rect_height_style =
583  Paragraph::RectWidthStyle rect_width_style =
585  paint.setColor(SK_ColorRED);
586  std::vector<txt::Paragraph::TextBox> boxes =
587  paragraph->GetRectsForRange(0, 3, rect_height_style, rect_width_style);
588  for (size_t i = 0; i < boxes.size(); ++i) {
589  GetCanvas()->drawRect(boxes[i].rect, paint);
590  }
591  // ASSERT_TRUE(Snapshot());
592  EXPECT_EQ(boxes.size(), 1ull);
593 
594  paint.setColor(SK_ColorGREEN);
595  boxes =
596  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
597  for (size_t i = 0; i < boxes.size(); ++i) {
598  GetCanvas()->drawRect(boxes[i].rect, paint);
599  }
600  EXPECT_EQ(boxes.size(), 1ull);
601 
602  paint.setColor(SK_ColorRED);
603  boxes = paragraph->GetRectsForPlaceholders();
604  for (size_t i = 0; i < boxes.size(); ++i) {
605  GetCanvas()->drawRect(boxes[i].rect, paint);
606  }
607 
608  paint.setColor(SK_ColorBLUE);
609  boxes =
610  paragraph->GetRectsForRange(4, 17, rect_height_style, rect_width_style);
611  for (size_t i = 0; i < boxes.size(); ++i) {
612  GetCanvas()->drawRect(boxes[i].rect, paint);
613  }
614  EXPECT_EQ(boxes.size(), 7ull);
615  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 90.945312);
616  EXPECT_FLOAT_EQ(boxes[1].rect.top(), 50);
617  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 140.94531);
618  EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 100);
619 
620  EXPECT_FLOAT_EQ(boxes[3].rect.left(), 231.39062);
621  EXPECT_FLOAT_EQ(boxes[3].rect.top(), 50);
622  EXPECT_FLOAT_EQ(boxes[3].rect.right(), 231.39062 + 50);
623  EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 100);
624 
625  EXPECT_FLOAT_EQ(boxes[4].rect.left(), 281.39062);
626  EXPECT_FLOAT_EQ(boxes[4].rect.top(), 0);
627  EXPECT_FLOAT_EQ(boxes[4].rect.right(), 281.39062 + 5);
628  EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 50);
629 
630  EXPECT_FLOAT_EQ(boxes[6].rect.left(), 336.39062);
631  EXPECT_FLOAT_EQ(boxes[6].rect.top(), 0);
632  EXPECT_FLOAT_EQ(boxes[6].rect.right(), 336.39062 + 5);
633  EXPECT_FLOAT_EQ(boxes[6].rect.bottom(), 50);
634 
635  ASSERT_TRUE(Snapshot());
636 }
637 
638 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBaselineParagraph)) {
639  const char* text = "012 34";
640  auto icu_text = icu::UnicodeString::fromUTF8(text);
641  std::u16string u16_text(icu_text.getBuffer(),
642  icu_text.getBuffer() + icu_text.length());
643 
644  txt::ParagraphStyle paragraph_style;
645  paragraph_style.max_lines = 14;
646  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
647 
648  txt::TextStyle text_style;
649  text_style.font_families = std::vector<std::string>(1, "Roboto");
650  text_style.font_size = 26;
651  text_style.letter_spacing = 1;
652  text_style.word_spacing = 5;
653  text_style.color = SK_ColorBLACK;
654  text_style.height = 1;
656  text_style.decoration_color = SK_ColorBLACK;
657  builder.PushStyle(text_style);
658 
659  builder.AddText(u16_text);
660 
662  TextBaseline::kAlphabetic, 38.34734);
663  builder.AddPlaceholder(placeholder_run);
664 
665  builder.AddText(u16_text);
666 
667  builder.Pop();
668 
669  auto paragraph = BuildParagraph(builder);
670  paragraph->Layout(GetTestCanvasWidth());
671 
672  paragraph->Paint(GetCanvas(), 0, 0);
673 
674  SkPaint paint;
675  paint.setStyle(SkPaint::kStroke_Style);
676  paint.setAntiAlias(true);
677  paint.setStrokeWidth(1);
678 
679  Paragraph::RectHeightStyle rect_height_style =
681  Paragraph::RectWidthStyle rect_width_style =
683  paint.setColor(SK_ColorRED);
684  std::vector<txt::Paragraph::TextBox> boxes =
685  paragraph->GetRectsForPlaceholders();
686  for (size_t i = 0; i < boxes.size(); ++i) {
687  GetCanvas()->drawRect(boxes[i].rect, paint);
688  }
689  EXPECT_EQ(boxes.size(), 1ull);
690  // Verify the box is in the right place
691  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.945312);
692  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
693  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531);
694  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
695 
696  paint.setColor(SK_ColorBLUE);
697  boxes =
698  paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
699  for (size_t i = 0; i < boxes.size(); ++i) {
700  GetCanvas()->drawRect(boxes[i].rect, paint);
701  }
702  EXPECT_EQ(boxes.size(), 1ull);
703  // Verify the other text didn't just shift to accomodate it.
704  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375);
705  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 14.226246);
706  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312);
707  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44.694996);
708 
709  ASSERT_TRUE(Snapshot());
710 }
711 
713  DISABLE_ON_WINDOWS(InlinePlaceholderAboveBaselineParagraph)) {
714  const char* text = "012 34";
715  auto icu_text = icu::UnicodeString::fromUTF8(text);
716  std::u16string u16_text(icu_text.getBuffer(),
717  icu_text.getBuffer() + icu_text.length());
718 
719  txt::ParagraphStyle paragraph_style;
720  paragraph_style.max_lines = 14;
721  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
722 
723  txt::TextStyle text_style;
724  text_style.font_families = std::vector<std::string>(1, "Roboto");
725  text_style.font_size = 26;
726  text_style.letter_spacing = 1;
727  text_style.word_spacing = 5;
728  text_style.color = SK_ColorBLACK;
729  text_style.height = 1;
731  text_style.decoration_color = SK_ColorBLACK;
732  builder.PushStyle(text_style);
733 
734  builder.AddText(u16_text);
735 
736  txt::PlaceholderRun placeholder_run(55, 50,
738  TextBaseline::kAlphabetic, 903129.129308);
739  builder.AddPlaceholder(placeholder_run);
740 
741  builder.AddText(u16_text);
742 
743  builder.Pop();
744 
745  auto paragraph = BuildParagraph(builder);
746  paragraph->Layout(GetTestCanvasWidth());
747 
748  paragraph->Paint(GetCanvas(), 0, 0);
749 
750  SkPaint paint;
751  paint.setStyle(SkPaint::kStroke_Style);
752  paint.setAntiAlias(true);
753  paint.setStrokeWidth(1);
754 
755  Paragraph::RectHeightStyle rect_height_style =
757  Paragraph::RectWidthStyle rect_width_style =
759  paint.setColor(SK_ColorRED);
760  std::vector<txt::Paragraph::TextBox> boxes =
761  paragraph->GetRectsForPlaceholders();
762  for (size_t i = 0; i < boxes.size(); ++i) {
763  GetCanvas()->drawRect(boxes[i].rect, paint);
764  }
765  EXPECT_EQ(boxes.size(), 1ull);
766  // Verify the box is in the right place
767  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.945312);
768  EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.34765625);
769  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531);
770  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 49.652344);
771 
772  paint.setColor(SK_ColorBLUE);
773  boxes =
774  paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
775  for (size_t i = 0; i < boxes.size(); ++i) {
776  GetCanvas()->drawRect(boxes[i].rect, paint);
777  }
778  EXPECT_EQ(boxes.size(), 1ull);
779  // Verify the other text didn't just shift to accomodate it.
780  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375);
781  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 25.53125);
782  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312);
783  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 56);
784 
785  ASSERT_TRUE(Snapshot());
786 }
787 
789  DISABLE_ON_WINDOWS(InlinePlaceholderBelowBaselineParagraph)) {
790  const char* text = "012 34";
791  auto icu_text = icu::UnicodeString::fromUTF8(text);
792  std::u16string u16_text(icu_text.getBuffer(),
793  icu_text.getBuffer() + icu_text.length());
794 
795  txt::ParagraphStyle paragraph_style;
796  paragraph_style.max_lines = 14;
797  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
798 
799  txt::TextStyle text_style;
800  text_style.font_families = std::vector<std::string>(1, "Roboto");
801  text_style.font_size = 26;
802  text_style.letter_spacing = 1;
803  text_style.word_spacing = 5;
804  text_style.color = SK_ColorBLACK;
805  text_style.height = 1;
807  text_style.decoration_color = SK_ColorBLACK;
808  builder.PushStyle(text_style);
809 
810  builder.AddText(u16_text);
811 
812  txt::PlaceholderRun placeholder_run(55, 50,
814  TextBaseline::kAlphabetic, 903129.129308);
815  builder.AddPlaceholder(placeholder_run);
816 
817  builder.AddText(u16_text);
818 
819  builder.Pop();
820 
821  auto paragraph = BuildParagraph(builder);
822  paragraph->Layout(GetTestCanvasWidth());
823 
824  paragraph->Paint(GetCanvas(), 0, 0);
825 
826  SkPaint paint;
827  paint.setStyle(SkPaint::kStroke_Style);
828  paint.setAntiAlias(true);
829  paint.setStrokeWidth(1);
830 
831  Paragraph::RectHeightStyle rect_height_style =
833  Paragraph::RectWidthStyle rect_width_style =
835  paint.setColor(SK_ColorRED);
836  std::vector<txt::Paragraph::TextBox> boxes =
837  paragraph->GetRectsForPlaceholders();
838  for (size_t i = 0; i < boxes.size(); ++i) {
839  GetCanvas()->drawRect(boxes[i].rect, paint);
840  }
841  EXPECT_EQ(boxes.size(), 1ull);
842  // Verify the box is in the right place
843  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.945312);
844  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 24);
845  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531);
846  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
847 
848  paint.setColor(SK_ColorBLUE);
849  boxes =
850  paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
851  for (size_t i = 0; i < boxes.size(); ++i) {
852  GetCanvas()->drawRect(boxes[i].rect, paint);
853  }
854  EXPECT_EQ(boxes.size(), 1ull);
855  // Verify the other text didn't just shift to accomodate it.
856  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375);
857  EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.12109375);
858  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312);
859  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 30.347656);
860 
861  ASSERT_TRUE(Snapshot());
862 }
863 
864 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBottomParagraph)) {
865  const char* text = "012 34";
866  auto icu_text = icu::UnicodeString::fromUTF8(text);
867  std::u16string u16_text(icu_text.getBuffer(),
868  icu_text.getBuffer() + icu_text.length());
869 
870  txt::ParagraphStyle paragraph_style;
871  paragraph_style.max_lines = 14;
872  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
873 
874  txt::TextStyle text_style;
875  text_style.font_families = std::vector<std::string>(1, "Roboto");
876  text_style.font_size = 26;
877  text_style.letter_spacing = 1;
878  text_style.word_spacing = 5;
879  text_style.color = SK_ColorBLACK;
880  text_style.height = 1;
882  text_style.decoration_color = SK_ColorBLACK;
883  builder.PushStyle(text_style);
884 
885  builder.AddText(u16_text);
886 
887  txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBottom,
889  builder.AddPlaceholder(placeholder_run);
890 
891  builder.AddText(u16_text);
892 
893  builder.Pop();
894 
895  auto paragraph = BuildParagraph(builder);
896  paragraph->Layout(GetTestCanvasWidth());
897 
898  paragraph->Paint(GetCanvas(), 0, 0);
899 
900  SkPaint paint;
901  paint.setStyle(SkPaint::kStroke_Style);
902  paint.setAntiAlias(true);
903  paint.setStrokeWidth(1);
904 
905  Paragraph::RectHeightStyle rect_height_style =
907  Paragraph::RectWidthStyle rect_width_style =
909  paint.setColor(SK_ColorRED);
910  std::vector<txt::Paragraph::TextBox> boxes =
911  paragraph->GetRectsForPlaceholders();
912  for (size_t i = 0; i < boxes.size(); ++i) {
913  GetCanvas()->drawRect(boxes[i].rect, paint);
914  }
915  EXPECT_EQ(boxes.size(), 1ull);
916  // Verify the box is in the right place
917  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.945312);
918  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
919  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531);
920  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
921 
922  paint.setColor(SK_ColorBLUE);
923  boxes =
924  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
925  for (size_t i = 0; i < boxes.size(); ++i) {
926  GetCanvas()->drawRect(boxes[i].rect, paint);
927  }
928  EXPECT_EQ(boxes.size(), 1ull);
929  // Verify the other text didn't just shift to accomodate it.
930  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0.5);
931  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 19.53125);
932  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.101562);
933  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
934 
935  ASSERT_TRUE(Snapshot());
936 }
937 
938 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderTopParagraph)) {
939  const char* text = "012 34";
940  auto icu_text = icu::UnicodeString::fromUTF8(text);
941  std::u16string u16_text(icu_text.getBuffer(),
942  icu_text.getBuffer() + icu_text.length());
943 
944  txt::ParagraphStyle paragraph_style;
945  paragraph_style.max_lines = 14;
946  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
947 
948  txt::TextStyle text_style;
949  text_style.font_families = std::vector<std::string>(1, "Roboto");
950  text_style.font_size = 26;
951  text_style.letter_spacing = 1;
952  text_style.word_spacing = 5;
953  text_style.color = SK_ColorBLACK;
954  text_style.height = 1;
956  text_style.decoration_color = SK_ColorBLACK;
957  builder.PushStyle(text_style);
958 
959  builder.AddText(u16_text);
960 
961  txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kTop,
963  builder.AddPlaceholder(placeholder_run);
964 
965  builder.AddText(u16_text);
966 
967  builder.Pop();
968 
969  auto paragraph = BuildParagraph(builder);
970  paragraph->Layout(GetTestCanvasWidth());
971 
972  paragraph->Paint(GetCanvas(), 0, 0);
973 
974  SkPaint paint;
975  paint.setStyle(SkPaint::kStroke_Style);
976  paint.setAntiAlias(true);
977  paint.setStrokeWidth(1);
978 
979  Paragraph::RectHeightStyle rect_height_style =
981  Paragraph::RectWidthStyle rect_width_style =
983  paint.setColor(SK_ColorRED);
984  std::vector<txt::Paragraph::TextBox> boxes =
985  paragraph->GetRectsForPlaceholders();
986  for (size_t i = 0; i < boxes.size(); ++i) {
987  GetCanvas()->drawRect(boxes[i].rect, paint);
988  }
989  EXPECT_EQ(boxes.size(), 1ull);
990  // Verify the box is in the right place
991  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.945312);
992  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
993  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531);
994  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
995 
996  paint.setColor(SK_ColorBLUE);
997  boxes =
998  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
999  for (size_t i = 0; i < boxes.size(); ++i) {
1000  GetCanvas()->drawRect(boxes[i].rect, paint);
1001  }
1002  EXPECT_EQ(boxes.size(), 1ull);
1003  // Verify the other text didn't just shift to accomodate it.
1004  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0.5);
1005  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
1006  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.101562);
1007  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 30.46875);
1008 
1009  ASSERT_TRUE(Snapshot());
1010 }
1011 
1012 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderMiddleParagraph)) {
1013  const char* text = "012 34";
1014  auto icu_text = icu::UnicodeString::fromUTF8(text);
1015  std::u16string u16_text(icu_text.getBuffer(),
1016  icu_text.getBuffer() + icu_text.length());
1017 
1018  txt::ParagraphStyle paragraph_style;
1019  paragraph_style.max_lines = 14;
1020  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1021 
1022  txt::TextStyle text_style;
1023  text_style.font_families = std::vector<std::string>(1, "Roboto");
1024  text_style.font_size = 26;
1025  text_style.letter_spacing = 1;
1026  text_style.word_spacing = 5;
1027  text_style.color = SK_ColorBLACK;
1028  text_style.height = 1;
1030  text_style.decoration_color = SK_ColorBLACK;
1031  builder.PushStyle(text_style);
1032 
1033  builder.AddText(u16_text);
1034 
1035  txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kMiddle,
1037  builder.AddPlaceholder(placeholder_run);
1038 
1039  builder.AddText(u16_text);
1040 
1041  builder.Pop();
1042 
1043  auto paragraph = BuildParagraph(builder);
1044  paragraph->Layout(GetTestCanvasWidth());
1045 
1046  paragraph->Paint(GetCanvas(), 0, 0);
1047 
1048  SkPaint paint;
1049  paint.setStyle(SkPaint::kStroke_Style);
1050  paint.setAntiAlias(true);
1051  paint.setStrokeWidth(1);
1052 
1053  Paragraph::RectHeightStyle rect_height_style =
1055  Paragraph::RectWidthStyle rect_width_style =
1057  paint.setColor(SK_ColorRED);
1058  std::vector<txt::Paragraph::TextBox> boxes =
1059  paragraph->GetRectsForPlaceholders();
1060  for (size_t i = 0; i < boxes.size(); ++i) {
1061  GetCanvas()->drawRect(boxes[i].rect, paint);
1062  }
1063  EXPECT_EQ(boxes.size(), 1ull);
1064  // Verify the box is in the right place
1065  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.945312);
1066  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
1067  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531);
1068  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
1069 
1070  paint.setColor(SK_ColorBLUE);
1071  boxes =
1072  paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
1073  for (size_t i = 0; i < boxes.size(); ++i) {
1074  GetCanvas()->drawRect(boxes[i].rect, paint);
1075  }
1076  EXPECT_EQ(boxes.size(), 1ull);
1077  // Verify the other text didn't just shift to accomodate it.
1078  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375);
1079  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 9.765625);
1080  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312);
1081  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 40.234375);
1082 
1083  ASSERT_TRUE(Snapshot());
1084 }
1085 
1088  DISABLE_ON_WINDOWS(InlinePlaceholderIdeographicBaselineParagraph))) {
1089  const char* text = "給能上目秘使";
1090  auto icu_text = icu::UnicodeString::fromUTF8(text);
1091  std::u16string u16_text(icu_text.getBuffer(),
1092  icu_text.getBuffer() + icu_text.length());
1093 
1094  txt::ParagraphStyle paragraph_style;
1095  paragraph_style.max_lines = 14;
1096  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1097 
1098  txt::TextStyle text_style;
1099  text_style.font_families = std::vector<std::string>(1, "Source Han Serif CN");
1100  text_style.font_size = 26;
1101  text_style.letter_spacing = 1;
1102  text_style.word_spacing = 5;
1103  text_style.color = SK_ColorBLACK;
1104  text_style.height = 1;
1106  text_style.decoration_color = SK_ColorBLACK;
1107  builder.PushStyle(text_style);
1108 
1109  builder.AddText(u16_text);
1110 
1111  txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBaseline,
1112  TextBaseline::kIdeographic, 38.34734);
1113  builder.AddPlaceholder(placeholder_run);
1114 
1115  builder.AddText(u16_text);
1116 
1117  builder.Pop();
1118 
1119  auto paragraph = BuildParagraph(builder);
1120  paragraph->Layout(GetTestCanvasWidth());
1121 
1122  paragraph->Paint(GetCanvas(), 0, 0);
1123 
1124  SkPaint paint;
1125  paint.setStyle(SkPaint::kStroke_Style);
1126  paint.setAntiAlias(true);
1127  paint.setStrokeWidth(1);
1128 
1129  Paragraph::RectHeightStyle rect_height_style =
1131  Paragraph::RectWidthStyle rect_width_style =
1133  paint.setColor(SK_ColorRED);
1134  std::vector<txt::Paragraph::TextBox> boxes =
1135  paragraph->GetRectsForPlaceholders();
1136  for (size_t i = 0; i < boxes.size(); ++i) {
1137  GetCanvas()->drawRect(boxes[i].rect, paint);
1138  }
1139  EXPECT_EQ(boxes.size(), 1ull);
1140  // Verify the box is in the right place
1141  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 162.5);
1142  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
1143  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 217.5);
1144  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
1145 
1146  paint.setColor(SK_ColorBLUE);
1147  boxes =
1148  paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
1149  for (size_t i = 0; i < boxes.size(); ++i) {
1150  GetCanvas()->drawRect(boxes[i].rect, paint);
1151  }
1152  EXPECT_EQ(boxes.size(), 1ull);
1153  // Verify the other text didn't just shift to accomodate it.
1154  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 135.5);
1155  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 4.7033391);
1156  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 162.5);
1157  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 42.065342);
1158 
1159  ASSERT_TRUE(Snapshot());
1160 }
1161 
1162 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBreakParagraph)) {
1163  const char* text = "012 34";
1164  auto icu_text = icu::UnicodeString::fromUTF8(text);
1165  std::u16string u16_text(icu_text.getBuffer(),
1166  icu_text.getBuffer() + icu_text.length());
1167 
1168  txt::ParagraphStyle paragraph_style;
1169  paragraph_style.max_lines = 14;
1170  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1171 
1172  txt::TextStyle text_style;
1173  text_style.font_families = std::vector<std::string>(1, "Roboto");
1174  text_style.font_size = 26;
1175  text_style.letter_spacing = 1;
1176  text_style.word_spacing = 5;
1177  text_style.color = SK_ColorBLACK;
1178  text_style.height = 1;
1180  text_style.decoration_color = SK_ColorBLACK;
1181  builder.PushStyle(text_style);
1182 
1183  builder.AddText(u16_text);
1184 
1185  txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
1187  txt::PlaceholderRun placeholder_run2(25, 25, PlaceholderAlignment::kBaseline,
1189  builder.AddPlaceholder(placeholder_run);
1190  builder.AddPlaceholder(placeholder_run);
1191  builder.AddPlaceholder(placeholder_run);
1192  builder.AddPlaceholder(placeholder_run2);
1193  builder.AddPlaceholder(placeholder_run);
1194  builder.AddText(u16_text);
1195  builder.AddPlaceholder(placeholder_run);
1196  builder.AddPlaceholder(placeholder_run);
1197  builder.AddPlaceholder(placeholder_run);
1198  builder.AddPlaceholder(placeholder_run);
1199  builder.AddPlaceholder(placeholder_run2);
1200  builder.AddPlaceholder(placeholder_run);
1201  builder.AddPlaceholder(placeholder_run);
1202  builder.AddPlaceholder(placeholder_run);
1203  builder.AddPlaceholder(placeholder_run);
1204  builder.AddPlaceholder(placeholder_run);
1205  builder.AddPlaceholder(placeholder_run);
1206  builder.AddPlaceholder(placeholder_run2);
1207  builder.AddPlaceholder(placeholder_run);
1208  builder.AddPlaceholder(placeholder_run);
1209  builder.AddPlaceholder(placeholder_run);
1210  builder.AddPlaceholder(placeholder_run);
1211  builder.AddPlaceholder(placeholder_run);
1212  builder.AddPlaceholder(placeholder_run);
1213  builder.AddPlaceholder(placeholder_run);
1214  builder.AddPlaceholder(placeholder_run2);
1215  builder.AddPlaceholder(placeholder_run);
1216 
1217  builder.AddText(u16_text);
1218 
1219  builder.AddPlaceholder(placeholder_run);
1220  builder.AddPlaceholder(placeholder_run2);
1221 
1222  builder.AddText(u16_text);
1223  builder.AddText(u16_text);
1224  builder.AddText(u16_text);
1225  builder.AddText(u16_text);
1226  builder.AddPlaceholder(placeholder_run2);
1227  builder.AddPlaceholder(placeholder_run);
1228  builder.AddText(u16_text);
1229  builder.AddPlaceholder(placeholder_run2);
1230  builder.AddText(u16_text);
1231  builder.AddText(u16_text);
1232  builder.AddText(u16_text);
1233  builder.AddText(u16_text);
1234  builder.AddText(u16_text);
1235  builder.AddText(u16_text);
1236  builder.AddText(u16_text);
1237  builder.AddText(u16_text);
1238  builder.AddText(u16_text);
1239  builder.AddText(u16_text);
1240  builder.AddText(u16_text);
1241  builder.AddText(u16_text);
1242  builder.AddText(u16_text);
1243  builder.AddText(u16_text);
1244  builder.AddText(u16_text);
1245  builder.AddText(u16_text);
1246  builder.AddText(u16_text);
1247  builder.AddText(u16_text);
1248  builder.AddText(u16_text);
1249 
1250  builder.Pop();
1251 
1252  auto paragraph = BuildParagraph(builder);
1253  paragraph->Layout(GetTestCanvasWidth() - 100);
1254 
1255  paragraph->Paint(GetCanvas(), 0, 0);
1256 
1257  SkPaint paint;
1258  paint.setStyle(SkPaint::kStroke_Style);
1259  paint.setAntiAlias(true);
1260  paint.setStrokeWidth(1);
1261 
1262  Paragraph::RectHeightStyle rect_height_style =
1264  Paragraph::RectWidthStyle rect_width_style =
1266  paint.setColor(SK_ColorRED);
1267  std::vector<txt::Paragraph::TextBox> boxes =
1268  paragraph->GetRectsForRange(0, 3, rect_height_style, rect_width_style);
1269  for (size_t i = 0; i < boxes.size(); ++i) {
1270  GetCanvas()->drawRect(boxes[i].rect, paint);
1271  }
1272  EXPECT_EQ(boxes.size(), 1ull);
1273 
1274  paint.setColor(SK_ColorGREEN);
1275  boxes = paragraph->GetRectsForRange(175, 176, rect_height_style,
1276  rect_width_style);
1277  for (size_t i = 0; i < boxes.size(); ++i) {
1278  GetCanvas()->drawRect(boxes[i].rect, paint);
1279  }
1280  EXPECT_EQ(boxes.size(), 1ull);
1281  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 31.703125);
1282  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 218.53125);
1283  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 47.304688);
1284  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 249);
1285 
1286  paint.setColor(SK_ColorRED);
1287  boxes = paragraph->GetRectsForPlaceholders();
1288  for (size_t i = 0; i < boxes.size(); ++i) {
1289  GetCanvas()->drawRect(boxes[i].rect, paint);
1290  }
1291 
1292  paint.setColor(SK_ColorBLUE);
1293  boxes =
1294  paragraph->GetRectsForRange(4, 45, rect_height_style, rect_width_style);
1295  for (size_t i = 0; i < boxes.size(); ++i) {
1296  GetCanvas()->drawRect(boxes[i].rect, paint);
1297  }
1298  EXPECT_EQ(boxes.size(), 30ull);
1299  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 59.742188);
1300  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 26.378906);
1301  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312);
1302  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 56.847656);
1303 
1304  EXPECT_FLOAT_EQ(boxes[11].rect.left(), 606.39062);
1305  EXPECT_FLOAT_EQ(boxes[11].rect.top(), 38);
1306  EXPECT_FLOAT_EQ(boxes[11].rect.right(), 631.39062);
1307  EXPECT_FLOAT_EQ(boxes[11].rect.bottom(), 63);
1308 
1309  EXPECT_FLOAT_EQ(boxes[17].rect.left(), 0.5);
1310  EXPECT_FLOAT_EQ(boxes[17].rect.top(), 63.5);
1311  EXPECT_FLOAT_EQ(boxes[17].rect.right(), 50.5);
1312  EXPECT_FLOAT_EQ(boxes[17].rect.bottom(), 113.5);
1313 
1314  ASSERT_TRUE(Snapshot());
1315 }
1316 
1317 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderGetRectsParagraph)) {
1318  const char* text = "012 34";
1319  auto icu_text = icu::UnicodeString::fromUTF8(text);
1320  std::u16string u16_text(icu_text.getBuffer(),
1321  icu_text.getBuffer() + icu_text.length());
1322 
1323  txt::ParagraphStyle paragraph_style;
1324  paragraph_style.max_lines = 14;
1325  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1326 
1327  txt::TextStyle text_style;
1328  text_style.font_families = std::vector<std::string>(1, "Roboto");
1329  text_style.font_size = 26;
1330  text_style.letter_spacing = 1;
1331  text_style.word_spacing = 5;
1332  text_style.color = SK_ColorBLACK;
1333  text_style.height = 1;
1335  text_style.decoration_color = SK_ColorBLACK;
1336  builder.PushStyle(text_style);
1337 
1338  builder.AddText(u16_text);
1339 
1340  txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
1342  txt::PlaceholderRun placeholder_run2(5, 20, PlaceholderAlignment::kBaseline,
1344  builder.AddPlaceholder(placeholder_run);
1345  builder.AddPlaceholder(placeholder_run);
1346  builder.AddPlaceholder(placeholder_run);
1347  builder.AddPlaceholder(placeholder_run);
1348  builder.AddPlaceholder(placeholder_run);
1349  builder.AddPlaceholder(placeholder_run);
1350  builder.AddPlaceholder(placeholder_run);
1351  builder.AddPlaceholder(placeholder_run);
1352  builder.AddPlaceholder(placeholder_run2);
1353  builder.AddPlaceholder(placeholder_run);
1354  builder.AddPlaceholder(placeholder_run);
1355  builder.AddPlaceholder(placeholder_run);
1356  builder.AddPlaceholder(placeholder_run);
1357  builder.AddPlaceholder(placeholder_run);
1358  builder.AddPlaceholder(placeholder_run2);
1359  builder.AddPlaceholder(placeholder_run);
1360  builder.AddPlaceholder(placeholder_run);
1361  builder.AddPlaceholder(placeholder_run);
1362  builder.AddPlaceholder(placeholder_run);
1363  builder.AddPlaceholder(placeholder_run);
1364  builder.AddPlaceholder(placeholder_run);
1365  builder.AddPlaceholder(placeholder_run);
1366  builder.AddPlaceholder(placeholder_run);
1367 
1368  builder.AddText(u16_text);
1369 
1370  builder.AddPlaceholder(placeholder_run);
1371  builder.AddPlaceholder(placeholder_run2);
1372  builder.AddPlaceholder(placeholder_run2);
1373  builder.AddPlaceholder(placeholder_run);
1374  builder.AddPlaceholder(placeholder_run2);
1375  builder.AddPlaceholder(placeholder_run2);
1376 
1377  builder.AddText(u16_text);
1378  builder.AddText(u16_text);
1379  builder.AddText(u16_text);
1380  builder.AddText(u16_text);
1381  builder.AddText(u16_text);
1382  builder.AddText(u16_text);
1383  builder.AddText(u16_text);
1384  builder.AddText(u16_text);
1385  builder.AddText(u16_text);
1386  builder.AddText(u16_text);
1387  builder.AddText(u16_text);
1388  builder.AddPlaceholder(placeholder_run2);
1389  builder.AddPlaceholder(placeholder_run);
1390  builder.AddPlaceholder(placeholder_run2);
1391  builder.AddPlaceholder(placeholder_run);
1392  builder.AddPlaceholder(placeholder_run2);
1393  builder.AddText(u16_text);
1394 
1395  builder.Pop();
1396 
1397  auto paragraph = BuildParagraph(builder);
1398  paragraph->Layout(GetTestCanvasWidth());
1399 
1400  paragraph->Paint(GetCanvas(), 0, 0);
1401 
1402  SkPaint paint;
1403  paint.setStyle(SkPaint::kStroke_Style);
1404  paint.setAntiAlias(true);
1405  paint.setStrokeWidth(1);
1406  paint.setColor(SK_ColorRED);
1407  std::vector<txt::Paragraph::TextBox> boxes =
1408  paragraph->GetRectsForPlaceholders();
1409  for (size_t i = 0; i < boxes.size(); ++i) {
1410  GetCanvas()->drawRect(boxes[i].rect, paint);
1411  }
1412  EXPECT_EQ(boxes.size(), 34ull);
1413  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.945312);
1414  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
1415  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 140.94531);
1416  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
1417 
1418  EXPECT_FLOAT_EQ(boxes[16].rect.left(), 800.94531);
1419  EXPECT_FLOAT_EQ(boxes[16].rect.top(), 0);
1420  EXPECT_FLOAT_EQ(boxes[16].rect.right(), 850.94531);
1421  EXPECT_FLOAT_EQ(boxes[16].rect.bottom(), 50);
1422 
1423  EXPECT_FLOAT_EQ(boxes[33].rect.left(), 503.48438);
1424  EXPECT_FLOAT_EQ(boxes[33].rect.top(), 160);
1425  EXPECT_FLOAT_EQ(boxes[33].rect.right(), 508.48438);
1426  EXPECT_FLOAT_EQ(boxes[33].rect.bottom(), 180);
1427 
1428  Paragraph::RectHeightStyle rect_height_style =
1430  Paragraph::RectWidthStyle rect_width_style =
1432  paint.setColor(SK_ColorBLUE);
1433  boxes =
1434  paragraph->GetRectsForRange(30, 50, rect_height_style, rect_width_style);
1435  for (size_t i = 0; i < boxes.size(); ++i) {
1436  GetCanvas()->drawRect(boxes[i].rect, paint);
1437  }
1438  EXPECT_EQ(boxes.size(), 8ull);
1439  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 216.10156);
1440  // Top should be taller than "tight"
1441  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 60);
1442  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 290.94531);
1443  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 120);
1444 
1445  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 290.94531);
1446  EXPECT_FLOAT_EQ(boxes[1].rect.top(), 60);
1447  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 340.94531);
1448  EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 120);
1449 
1450  EXPECT_FLOAT_EQ(boxes[2].rect.left(), 340.94531);
1451  EXPECT_FLOAT_EQ(boxes[2].rect.top(), 60);
1452  EXPECT_FLOAT_EQ(boxes[2].rect.right(), 345.94531);
1453  EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 120);
1454 
1455  ASSERT_TRUE(Snapshot());
1456 }
1457 
1458 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderLongestLine)) {
1459  txt::ParagraphStyle paragraph_style;
1460  paragraph_style.max_lines = 1;
1461  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1462 
1463  txt::TextStyle text_style;
1464  text_style.font_families = std::vector<std::string>(1, "Roboto");
1465  text_style.font_size = 26;
1466  text_style.letter_spacing = 1;
1467  text_style.word_spacing = 5;
1468  text_style.color = SK_ColorBLACK;
1469  text_style.height = 1;
1471  text_style.decoration_color = SK_ColorBLACK;
1472  builder.PushStyle(text_style);
1473 
1474  txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
1476  builder.AddPlaceholder(placeholder_run);
1477  builder.Pop();
1478 
1479  auto paragraph = BuildParagraph(builder);
1480  paragraph->Layout(GetTestCanvasWidth());
1481 
1482  ASSERT_DOUBLE_EQ(paragraph->width_, GetTestCanvasWidth());
1483  ASSERT_TRUE(paragraph->longest_line_ < GetTestCanvasWidth());
1484  ASSERT_TRUE(paragraph->longest_line_ >= 50);
1485 }
1486 
1487 #if OS_LINUX
1488 // Tests if manually inserted 0xFFFC characters are replaced to 0xFFFD in order
1489 // to not interfere with the placeholder box layout.
1490 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholder0xFFFCParagraph)) {
1491  const char* text = "ab\uFFFCcd";
1492  auto icu_text = icu::UnicodeString::fromUTF8(text);
1493  std::u16string u16_text(icu_text.getBuffer(),
1494  icu_text.getBuffer() + icu_text.length());
1495 
1496  // Used to generate the replaced version.
1497  const char* text2 = "ab\uFFFDcd";
1498  auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
1499  std::u16string u16_text2(icu_text2.getBuffer(),
1500  icu_text2.getBuffer() + icu_text2.length());
1501 
1502  txt::ParagraphStyle paragraph_style;
1503  paragraph_style.max_lines = 14;
1504  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1505 
1506  txt::TextStyle text_style;
1507  text_style.font_families = std::vector<std::string>(1, "Roboto");
1508  text_style.font_size = 26;
1509  text_style.letter_spacing = 1;
1510  text_style.word_spacing = 5;
1511  text_style.color = SK_ColorBLACK;
1512  text_style.height = 1;
1514  text_style.decoration_color = SK_ColorBLACK;
1515  builder.PushStyle(text_style);
1516 
1517  std::vector<uint16_t> truth_text;
1518 
1519  builder.AddText(u16_text);
1520  truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1521  builder.AddText(u16_text);
1522  truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1523 
1524  txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline,
1526  builder.AddPlaceholder(placeholder_run);
1527  truth_text.push_back(0xFFFC);
1528 
1529  builder.AddText(u16_text);
1530  truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1531  builder.AddText(u16_text);
1532  truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1533 
1534  builder.AddPlaceholder(placeholder_run);
1535  truth_text.push_back(0xFFFC);
1536  builder.AddPlaceholder(placeholder_run);
1537  truth_text.push_back(0xFFFC);
1538  builder.AddText(u16_text);
1539  truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1540  builder.AddText(u16_text);
1541  truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end());
1542  builder.AddPlaceholder(placeholder_run);
1543  truth_text.push_back(0xFFFC);
1544 
1545  builder.Pop();
1546 
1547  auto paragraph = BuildParagraph(builder);
1548  paragraph->Layout(GetTestCanvasWidth());
1549 
1550  paragraph->Paint(GetCanvas(), 0, 0);
1551 
1552  for (size_t i = 0; i < truth_text.size(); ++i) {
1553  EXPECT_EQ(paragraph->text_[i], truth_text[i]);
1554  }
1555 
1556  SkPaint paint;
1557  paint.setStyle(SkPaint::kStroke_Style);
1558  paint.setAntiAlias(true);
1559  paint.setStrokeWidth(1);
1560 
1561  paint.setColor(SK_ColorRED);
1562 
1563  paint.setColor(SK_ColorRED);
1564  std::vector<txt::Paragraph::TextBox> boxes =
1565  paragraph->GetRectsForPlaceholders();
1566  for (size_t i = 0; i < boxes.size(); ++i) {
1567  GetCanvas()->drawRect(boxes[i].rect, paint);
1568  }
1569  EXPECT_EQ(boxes.size(), 4ull);
1570 
1571  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177.83594);
1572  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
1573  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 227.83594);
1574  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50);
1575 
1576  EXPECT_FLOAT_EQ(boxes[3].rect.left(), 682.50781);
1577  EXPECT_FLOAT_EQ(boxes[3].rect.top(), 0);
1578  EXPECT_FLOAT_EQ(boxes[3].rect.right(), 732.50781);
1579  EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 50);
1580 
1581  ASSERT_TRUE(Snapshot());
1582 }
1583 #endif
1584 
1585 TEST_F(ParagraphTest, SimpleRedParagraph) {
1586  const char* text = "I am RED";
1587  auto icu_text = icu::UnicodeString::fromUTF8(text);
1588  std::u16string u16_text(icu_text.getBuffer(),
1589  icu_text.getBuffer() + icu_text.length());
1590 
1591  txt::ParagraphStyle paragraph_style;
1592  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1593 
1594  txt::TextStyle text_style;
1595  text_style.font_families = std::vector<std::string>(1, "Roboto");
1596  text_style.color = SK_ColorRED;
1597  builder.PushStyle(text_style);
1598 
1599  builder.AddText(u16_text);
1600 
1601  builder.Pop();
1602 
1603  auto paragraph = BuildParagraph(builder);
1604  paragraph->Layout(GetTestCanvasWidth());
1605 
1606  paragraph->Paint(GetCanvas(), 10.0, 15.0);
1607 
1608  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1609  for (size_t i = 0; i < u16_text.length(); i++) {
1610  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1611  }
1612  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1613  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1614  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1615  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
1616  ASSERT_TRUE(Snapshot());
1617 }
1618 
1619 TEST_F(ParagraphTest, RainbowParagraph) {
1620  const char* text1 = "Red Roboto";
1621  auto icu_text1 = icu::UnicodeString::fromUTF8(text1);
1622  std::u16string u16_text1(icu_text1.getBuffer(),
1623  icu_text1.getBuffer() + icu_text1.length());
1624  const char* text2 = "big Greeen Default";
1625  auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
1626  std::u16string u16_text2(icu_text2.getBuffer(),
1627  icu_text2.getBuffer() + icu_text2.length());
1628  const char* text3 = "Defcolor Homemade Apple";
1629  auto icu_text3 = icu::UnicodeString::fromUTF8(text3);
1630  std::u16string u16_text3(icu_text3.getBuffer(),
1631  icu_text3.getBuffer() + icu_text3.length());
1632  const char* text4 = "Small Blue Roboto";
1633  auto icu_text4 = icu::UnicodeString::fromUTF8(text4);
1634  std::u16string u16_text4(icu_text4.getBuffer(),
1635  icu_text4.getBuffer() + icu_text4.length());
1636  const char* text5 =
1637  "Continue Last Style With lots of words to check if it overlaps "
1638  "properly or not";
1639  auto icu_text5 = icu::UnicodeString::fromUTF8(text5);
1640  std::u16string u16_text5(icu_text5.getBuffer(),
1641  icu_text5.getBuffer() + icu_text5.length());
1642 
1643  txt::ParagraphStyle paragraph_style;
1644  paragraph_style.max_lines = 2;
1645  paragraph_style.text_align = TextAlign::left;
1646  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1647 
1648  txt::TextStyle text_style1;
1649  text_style1.font_families = std::vector<std::string>(1, "Roboto");
1650  text_style1.color = SK_ColorRED;
1651 
1652  builder.PushStyle(text_style1);
1653 
1654  builder.AddText(u16_text1);
1655 
1656  txt::TextStyle text_style2;
1657  text_style2.font_size = 50;
1658  text_style2.letter_spacing = 10;
1659  text_style2.word_spacing = 30;
1660  text_style2.font_weight = txt::FontWeight::w600;
1661  text_style2.color = SK_ColorGREEN;
1662  text_style2.font_families = std::vector<std::string>(1, "Roboto");
1663  text_style2.decoration = TextDecoration::kUnderline |
1666  text_style2.decoration_color = SK_ColorBLACK;
1667  builder.PushStyle(text_style2);
1668 
1669  builder.AddText(u16_text2);
1670 
1671  txt::TextStyle text_style3;
1672  text_style3.font_families = std::vector<std::string>(1, "Homemade Apple");
1673  builder.PushStyle(text_style3);
1674 
1675  builder.AddText(u16_text3);
1676 
1677  txt::TextStyle text_style4;
1678  text_style4.font_size = 14;
1679  text_style4.color = SK_ColorBLUE;
1680  text_style4.font_families = std::vector<std::string>(1, "Roboto");
1681  text_style4.decoration = TextDecoration::kUnderline |
1684  text_style4.decoration_color = SK_ColorBLACK;
1685  builder.PushStyle(text_style4);
1686 
1687  builder.AddText(u16_text4);
1688 
1689  // Extra text to see if it goes to default when there is more text chunks than
1690  // styles.
1691  builder.AddText(u16_text5);
1692 
1693  builder.Pop();
1694 
1695  auto paragraph = BuildParagraph(builder);
1696  paragraph->Layout(GetTestCanvasWidth());
1697  paragraph->Paint(GetCanvas(), 0, 0);
1698 
1699  u16_text1 += u16_text2 + u16_text3 + u16_text4;
1700  for (size_t i = 0; i < u16_text1.length(); i++) {
1701  ASSERT_EQ(paragraph->text_[i], u16_text1[i]);
1702  }
1703  ASSERT_TRUE(Snapshot());
1704  ASSERT_EQ(paragraph->runs_.runs_.size(), 4ull);
1705  ASSERT_EQ(paragraph->runs_.styles_.size(), 5ull);
1706  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style1));
1707  ASSERT_TRUE(paragraph->runs_.styles_[2].equals(text_style2));
1708  ASSERT_TRUE(paragraph->runs_.styles_[3].equals(text_style3));
1709  ASSERT_TRUE(paragraph->runs_.styles_[4].equals(text_style4));
1710  ASSERT_EQ(paragraph->records_[0].style().color, text_style1.color);
1711  ASSERT_EQ(paragraph->records_[1].style().color, text_style2.color);
1712  ASSERT_EQ(paragraph->records_[2].style().color, text_style3.color);
1713  ASSERT_EQ(paragraph->records_[3].style().color, text_style4.color);
1714 }
1715 
1716 // Currently, this should render nothing without a supplied TextStyle.
1717 TEST_F(ParagraphTest, DefaultStyleParagraph) {
1718  const char* text = "No TextStyle! Uh Oh!";
1719  auto icu_text = icu::UnicodeString::fromUTF8(text);
1720  std::u16string u16_text(icu_text.getBuffer(),
1721  icu_text.getBuffer() + icu_text.length());
1722 
1723  txt::ParagraphStyle paragraph_style;
1724  paragraph_style.font_family = "Roboto";
1725  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1726 
1727  builder.AddText(u16_text);
1728 
1729  builder.Pop();
1730 
1731  auto paragraph = BuildParagraph(builder);
1732  paragraph->Layout(GetTestCanvasWidth());
1733 
1734  paragraph->Paint(GetCanvas(), 10.0, 15.0);
1735 
1736  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1737  for (size_t i = 0; i < u16_text.length(); i++) {
1738  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1739  }
1740  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1741  ASSERT_EQ(paragraph->runs_.styles_.size(), 1ull);
1742  ASSERT_TRUE(Snapshot());
1743 }
1744 
1745 TEST_F(ParagraphTest, BoldParagraph) {
1746  const char* text = "This is Red max bold text!";
1747  auto icu_text = icu::UnicodeString::fromUTF8(text);
1748  std::u16string u16_text(icu_text.getBuffer(),
1749  icu_text.getBuffer() + icu_text.length());
1750 
1751  txt::ParagraphStyle paragraph_style;
1752  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1753 
1754  txt::TextStyle text_style;
1755  text_style.font_families = std::vector<std::string>(1, "Roboto");
1756  text_style.font_size = 60;
1757  text_style.letter_spacing = 0;
1758  text_style.font_weight = txt::FontWeight::w900;
1759  text_style.color = SK_ColorRED;
1760  builder.PushStyle(text_style);
1761 
1762  builder.AddText(u16_text);
1763 
1764  builder.Pop();
1765 
1766  auto paragraph = BuildParagraph(builder);
1767  paragraph->Layout(GetTestCanvasWidth());
1768 
1769  paragraph->Paint(GetCanvas(), 10.0, 60.0);
1770 
1771  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1772  for (size_t i = 0; i < u16_text.length(); i++) {
1773  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1774  }
1775  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1776  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1777  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1778  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
1779  ASSERT_TRUE(Snapshot());
1780 
1781  // width_ takes the full available space, but longest_line_ is only the width
1782  // of the text, which is less than one line.
1783  ASSERT_DOUBLE_EQ(paragraph->width_, GetTestCanvasWidth());
1784  ASSERT_TRUE(paragraph->longest_line_ < paragraph->width_);
1785  Paragraph::RectHeightStyle rect_height_style =
1787  Paragraph::RectWidthStyle rect_width_style =
1789  std::vector<txt::Paragraph::TextBox> boxes = paragraph->GetRectsForRange(
1790  0, strlen(text), rect_height_style, rect_width_style);
1791  ASSERT_DOUBLE_EQ(paragraph->longest_line_,
1792  boxes[boxes.size() - 1].rect.right() - boxes[0].rect.left());
1793 }
1794 
1795 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(HeightOverrideParagraph)) {
1796  const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
1797  auto icu_text = icu::UnicodeString::fromUTF8(text);
1798  std::u16string u16_text(icu_text.getBuffer(),
1799  icu_text.getBuffer() + icu_text.length());
1800 
1801  txt::ParagraphStyle paragraph_style;
1802  paragraph_style.max_lines = 10;
1803  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1804 
1805  txt::TextStyle text_style;
1806  text_style.font_families = std::vector<std::string>(1, "Roboto");
1807  text_style.font_size = 20;
1808  text_style.letter_spacing = 0;
1809  text_style.word_spacing = 0;
1810  text_style.color = SK_ColorBLACK;
1811  text_style.height = 3.6345;
1812  text_style.has_height_override = true;
1813  builder.PushStyle(text_style);
1814 
1815  builder.AddText(u16_text);
1816 
1817  builder.Pop();
1818 
1819  auto paragraph = BuildParagraph(builder);
1820  paragraph->Layout(550);
1821 
1822  paragraph->Paint(GetCanvas(), 0, 0);
1823 
1824  SkPaint paint;
1825  paint.setStyle(SkPaint::kStroke_Style);
1826  paint.setAntiAlias(true);
1827  paint.setStrokeWidth(1);
1828 
1829  // Tests for GetRectsForRange()
1830  Paragraph::RectHeightStyle rect_height_style =
1832  Paragraph::RectWidthStyle rect_width_style =
1834  paint.setColor(SK_ColorRED);
1835  std::vector<txt::Paragraph::TextBox> boxes =
1836  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
1837  for (size_t i = 0; i < boxes.size(); ++i) {
1838  GetCanvas()->drawRect(boxes[i].rect, paint);
1839  }
1840  EXPECT_EQ(boxes.size(), 0ull);
1841 
1842  boxes =
1843  paragraph->GetRectsForRange(0, 40, rect_height_style, rect_width_style);
1844  for (size_t i = 0; i < boxes.size(); ++i) {
1845  GetCanvas()->drawRect(boxes[i].rect, paint);
1846  }
1847  EXPECT_EQ(boxes.size(), 3ull);
1848  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
1849  EXPECT_NEAR(boxes[1].rect.top(), 92.805778503417969, 0.0001);
1850  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 43.851562);
1851  EXPECT_NEAR(boxes[1].rect.bottom(), 165.49578857421875, 0.0001);
1852 
1853  ASSERT_TRUE(Snapshot());
1854 }
1855 
1856 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(LeftAlignParagraph)) {
1857  const char* text =
1858  "This is a very long sentence to test if the text will properly wrap "
1859  "around and go to the next line. Sometimes, short sentence. Longer "
1860  "sentences are okay too because they are necessary. Very short. "
1861  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1862  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1863  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1864  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1865  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1866  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1867  "mollit anim id est laborum. "
1868  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1869  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1870  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1871  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1872  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1873  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1874  "mollit anim id est laborum.";
1875  auto icu_text = icu::UnicodeString::fromUTF8(text);
1876  std::u16string u16_text(icu_text.getBuffer(),
1877  icu_text.getBuffer() + icu_text.length());
1878 
1879  txt::ParagraphStyle paragraph_style;
1880  paragraph_style.max_lines = 14;
1881  paragraph_style.text_align = TextAlign::left;
1882  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1883 
1884  txt::TextStyle text_style;
1885  text_style.font_families = std::vector<std::string>(1, "Roboto");
1886  text_style.font_size = 26;
1887  text_style.letter_spacing = 1;
1888  text_style.word_spacing = 5;
1889  text_style.color = SK_ColorBLACK;
1890  text_style.height = 1;
1892  text_style.decoration_color = SK_ColorBLACK;
1893  builder.PushStyle(text_style);
1894 
1895  builder.AddText(u16_text);
1896 
1897  builder.Pop();
1898 
1899  auto paragraph = BuildParagraph(builder);
1900  paragraph->Layout(GetTestCanvasWidth() - 100);
1901 
1902  paragraph->Paint(GetCanvas(), 0, 0);
1903 
1904  ASSERT_TRUE(Snapshot());
1905 
1906  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1907  for (size_t i = 0; i < u16_text.length(); i++) {
1908  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1909  }
1910  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1911  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1912  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1913  ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines);
1914  double expected_y = 24;
1915 
1916  ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
1917  ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
1918  expected_y += 30;
1919  ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
1920 
1921  ASSERT_TRUE(paragraph->records_[1].style().equals(text_style));
1922  ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().y(), expected_y);
1923  expected_y += 30;
1924  ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
1925 
1926  ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
1927  ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
1928  expected_y += 30;
1929  ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
1930 
1931  ASSERT_TRUE(paragraph->records_[3].style().equals(text_style));
1932  ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().y(), expected_y);
1933  expected_y += 30 * 10;
1934  ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0);
1935 
1936  ASSERT_TRUE(paragraph->records_[13].style().equals(text_style));
1937  ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().y(), expected_y);
1938  ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().x(), 0);
1939 
1940  ASSERT_EQ(paragraph_style.text_align,
1941  paragraph->GetParagraphStyle().text_align);
1942 
1943  // Tests for GetGlyphPositionAtCoordinate()
1944  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0, 0).position, 0ull);
1945  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 1).position, 0ull);
1946  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 35).position, 68ull);
1947  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 70).position, 134ull);
1948  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(2000, 35).position, 134ull);
1949 
1950  ASSERT_TRUE(Snapshot());
1951 }
1952 
1953 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(RightAlignParagraph)) {
1954  const char* text =
1955  "This is a very long sentence to test if the text will properly wrap "
1956  "around and go to the next line. Sometimes, short sentence. Longer "
1957  "sentences are okay too because they are necessary. Very short. "
1958  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1959  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1960  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1961  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1962  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1963  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1964  "mollit anim id est laborum. "
1965  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1966  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1967  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1968  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1969  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1970  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1971  "mollit anim id est laborum.";
1972  auto icu_text = icu::UnicodeString::fromUTF8(text);
1973  std::u16string u16_text(icu_text.getBuffer(),
1974  icu_text.getBuffer() + icu_text.length());
1975 
1976  txt::ParagraphStyle paragraph_style;
1977  paragraph_style.max_lines = 14;
1978  paragraph_style.text_align = TextAlign::right;
1979  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
1980 
1981  txt::TextStyle text_style;
1982  text_style.font_families = std::vector<std::string>(1, "Roboto");
1983  text_style.font_size = 26;
1984  text_style.letter_spacing = 1;
1985  text_style.word_spacing = 5;
1986  text_style.color = SK_ColorBLACK;
1987  text_style.height = 1;
1989  text_style.decoration_color = SK_ColorBLACK;
1990  builder.PushStyle(text_style);
1991 
1992  builder.AddText(u16_text);
1993 
1994  builder.Pop();
1995 
1996  auto paragraph = BuildParagraph(builder);
1997  int available_width = GetTestCanvasWidth() - 100;
1998  paragraph->Layout(available_width);
1999 
2000  paragraph->Paint(GetCanvas(), 0, 0);
2001 
2002  ASSERT_TRUE(Snapshot());
2003  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
2004  for (size_t i = 0; i < u16_text.length(); i++) {
2005  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
2006  }
2007  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
2008  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
2009  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
2010  // Two records for each due to 'ghost' trailing whitespace run.
2011  ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines * 2);
2012  double expected_y = 24;
2013 
2014  ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
2015  ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
2016  expected_y += 30;
2017  ASSERT_NEAR(
2018  paragraph->records_[0].offset().x(),
2019  paragraph->width_ -
2020  paragraph->breaker_.getWidths()[paragraph->records_[0].line()],
2021  2.0);
2022 
2023  // width_ takes the full available space, while longest_line_ wraps the glyphs
2024  // as tightly as possible. Even though this text is more than one line long,
2025  // no line perfectly spans the width of the full line, so longest_line_ is
2026  // less than width_.
2027  ASSERT_DOUBLE_EQ(paragraph->width_, available_width);
2028  ASSERT_TRUE(paragraph->longest_line_ < available_width);
2029  ASSERT_DOUBLE_EQ(paragraph->longest_line_, 880.87109375);
2030 
2031  ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
2032  ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
2033  expected_y += 30;
2034  ASSERT_NEAR(
2035  paragraph->records_[2].offset().x(),
2036  paragraph->width_ -
2037  paragraph->breaker_.getWidths()[paragraph->records_[2].line()],
2038  2.0);
2039 
2040  ASSERT_TRUE(paragraph->records_[4].style().equals(text_style));
2041  ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y);
2042  expected_y += 30;
2043  ASSERT_NEAR(
2044  paragraph->records_[4].offset().x(),
2045  paragraph->width_ -
2046  paragraph->breaker_.getWidths()[paragraph->records_[4].line()],
2047  2.0);
2048 
2049  ASSERT_TRUE(paragraph->records_[6].style().equals(text_style));
2050  ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y);
2051  expected_y += 30 * 10;
2052  ASSERT_NEAR(
2053  paragraph->records_[6].offset().x(),
2054  paragraph->width_ -
2055  paragraph->breaker_.getWidths()[paragraph->records_[6].line()],
2056  2.0);
2057 
2058  ASSERT_TRUE(paragraph->records_[26].style().equals(text_style));
2059  ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y);
2060  ASSERT_NEAR(
2061  paragraph->records_[26].offset().x(),
2062  paragraph->width_ -
2063  paragraph->breaker_.getWidths()[paragraph->records_[26].line()],
2064  2.0);
2065 
2066  ASSERT_EQ(paragraph_style.text_align,
2067  paragraph->GetParagraphStyle().text_align);
2068 
2069  ASSERT_TRUE(Snapshot());
2070 }
2071 
2072 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(CenterAlignParagraph)) {
2073  const char* text =
2074  "This is a very long sentence to test if the text will properly wrap "
2075  "around and go to the next line. Sometimes, short sentence. Longer "
2076  "sentences are okay too because they are necessary. Very short. "
2077  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
2078  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
2079  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
2080  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
2081  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
2082  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
2083  "mollit anim id est laborum. "
2084  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
2085  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
2086  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
2087  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
2088  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
2089  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
2090  "mollit anim id est laborum.";
2091  auto icu_text = icu::UnicodeString::fromUTF8(text);
2092  std::u16string u16_text(icu_text.getBuffer(),
2093  icu_text.getBuffer() + icu_text.length());
2094 
2095  txt::ParagraphStyle paragraph_style;
2096  paragraph_style.max_lines = 14;
2097  paragraph_style.text_align = TextAlign::center;
2098  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2099 
2100  txt::TextStyle text_style;
2101  text_style.font_families = std::vector<std::string>(1, "Roboto");
2102  text_style.font_size = 26;
2103  text_style.letter_spacing = 1;
2104  text_style.word_spacing = 5;
2105  text_style.color = SK_ColorBLACK;
2106  text_style.height = 1;
2108  text_style.decoration_color = SK_ColorBLACK;
2109  builder.PushStyle(text_style);
2110 
2111  builder.AddText(u16_text);
2112 
2113  builder.Pop();
2114 
2115  auto paragraph = BuildParagraph(builder);
2116  paragraph->Layout(GetTestCanvasWidth() - 100);
2117 
2118  paragraph->Paint(GetCanvas(), 0, 0);
2119 
2120  ASSERT_TRUE(Snapshot());
2121  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
2122  for (size_t i = 0; i < u16_text.length(); i++) {
2123  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
2124  }
2125  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
2126  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
2127  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
2128  // Two records for each due to 'ghost' trailing whitespace run.
2129  ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines * 2);
2130  double expected_y = 24;
2131 
2132  ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
2133  ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
2134  expected_y += 30;
2135  ASSERT_NEAR(paragraph->records_[0].offset().x(),
2136  (paragraph->width_ -
2137  paragraph->breaker_.getWidths()[paragraph->records_[0].line()]) /
2138  2,
2139  2.0);
2140 
2141  ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
2142  ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
2143  expected_y += 30;
2144  ASSERT_NEAR(paragraph->records_[2].offset().x(),
2145  (paragraph->width_ -
2146  paragraph->breaker_.getWidths()[paragraph->records_[2].line()]) /
2147  2,
2148  2.0);
2149 
2150  ASSERT_TRUE(paragraph->records_[4].style().equals(text_style));
2151  ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y);
2152  expected_y += 30;
2153  ASSERT_NEAR(paragraph->records_[4].offset().x(),
2154  (paragraph->width_ -
2155  paragraph->breaker_.getWidths()[paragraph->records_[4].line()]) /
2156  2,
2157  2.0);
2158 
2159  ASSERT_TRUE(paragraph->records_[6].style().equals(text_style));
2160  ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y);
2161  expected_y += 30 * 10;
2162  ASSERT_NEAR(paragraph->records_[6].offset().x(),
2163  (paragraph->width_ -
2164  paragraph->breaker_.getWidths()[paragraph->records_[6].line()]) /
2165  2,
2166  2.0);
2167 
2168  ASSERT_TRUE(paragraph->records_[26].style().equals(text_style));
2169  ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y);
2170  ASSERT_NEAR(
2171  paragraph->records_[26].offset().x(),
2172  (paragraph->width_ -
2173  paragraph->breaker_.getWidths()[paragraph->records_[26].line()]) /
2174  2,
2175  2.0);
2176 
2177  ASSERT_EQ(paragraph_style.text_align,
2178  paragraph->GetParagraphStyle().text_align);
2179 
2180  ASSERT_TRUE(Snapshot());
2181 }
2182 
2183 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyAlignParagraph)) {
2184  const char* text =
2185  "This is a very long sentence to test if the text will properly wrap "
2186  "around and go to the next line. Sometimes, short sentence. Longer "
2187  "sentences are okay too because they are necessary. Very short. "
2188  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
2189  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
2190  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
2191  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
2192  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
2193  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
2194  "mollit anim id est laborum. "
2195  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
2196  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
2197  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
2198  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
2199  "velit esse cillum dolore eu fugiat.";
2200  auto icu_text = icu::UnicodeString::fromUTF8(text);
2201  std::u16string u16_text(icu_text.getBuffer(),
2202  icu_text.getBuffer() + icu_text.length());
2203 
2204  txt::ParagraphStyle paragraph_style;
2205  paragraph_style.max_lines = 14;
2206  paragraph_style.text_align = TextAlign::justify;
2207  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2208 
2209  txt::TextStyle text_style;
2210  text_style.font_families = std::vector<std::string>(1, "Roboto");
2211  text_style.font_size = 26;
2212  text_style.letter_spacing = 0;
2213  text_style.word_spacing = 5;
2214  text_style.color = SK_ColorBLACK;
2215  text_style.height = 1;
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_TRUE(Snapshot());
2230  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
2231  for (size_t i = 0; i < u16_text.length(); i++) {
2232  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
2233  }
2234  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
2235  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
2236  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
2237  ASSERT_EQ(paragraph->records_.size(), 27ull);
2238  double expected_y = 24;
2239 
2240  ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
2241  ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
2242  expected_y += 30;
2243  ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
2244 
2245  ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
2246  ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
2247  expected_y += 30;
2248  ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
2249 
2250  ASSERT_TRUE(paragraph->records_[4].style().equals(text_style));
2251  ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y);
2252  expected_y += 30;
2253  ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 0);
2254 
2255  ASSERT_TRUE(paragraph->records_[6].style().equals(text_style));
2256  ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y);
2257  expected_y += 30 * 10;
2258  ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().x(), 0);
2259 
2260  ASSERT_TRUE(paragraph->records_[26].style().equals(text_style));
2261  ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y);
2262  ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().x(), 0);
2263 
2264  ASSERT_EQ(paragraph_style.text_align,
2265  paragraph->GetParagraphStyle().text_align);
2266 
2267  ASSERT_TRUE(Snapshot());
2268 }
2269 
2271  const char* text =
2272  "אאא בּבּבּבּ אאאא בּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ "
2273  "אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ "
2274  "אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ";
2275 
2276  auto icu_text = icu::UnicodeString::fromUTF8(text);
2277  std::u16string u16_text(icu_text.getBuffer(),
2278  icu_text.getBuffer() + icu_text.length());
2279 
2280  txt::ParagraphStyle paragraph_style;
2281  paragraph_style.max_lines = 14;
2282  paragraph_style.text_align = TextAlign::justify;
2283  paragraph_style.text_direction = TextDirection::rtl;
2284  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2285 
2286  txt::TextStyle text_style;
2287  text_style.font_families = std::vector<std::string>(1, "Ahem");
2288  text_style.font_size = 26;
2289  text_style.color = SK_ColorBLACK;
2290  text_style.height = 1;
2291  builder.PushStyle(text_style);
2292 
2293  builder.AddText(u16_text);
2294 
2295  builder.Pop();
2296 
2297  auto paragraph = BuildParagraph(builder);
2298  size_t paragraph_width = GetTestCanvasWidth() - 100;
2299  paragraph->Layout(paragraph_width);
2300 
2301  paragraph->Paint(GetCanvas(), 0, 0);
2302 
2303  auto glyph_line_width = [&paragraph](int index) {
2304  size_t second_to_last_position_index =
2305  paragraph->glyph_lines_[index].positions.size() - 1;
2306  return paragraph->glyph_lines_[index]
2307  .positions[second_to_last_position_index]
2308  .x_pos.end;
2309  };
2310 
2311  SkPaint paint;
2312  paint.setStyle(SkPaint::kStroke_Style);
2313  paint.setAntiAlias(true);
2314  paint.setStrokeWidth(1);
2315 
2316  // Tests for GetRectsForRange()
2317  Paragraph::RectHeightStyle rect_height_style =
2319  Paragraph::RectWidthStyle rect_width_style =
2321  paint.setColor(SK_ColorRED);
2322  std::vector<txt::Paragraph::TextBox> boxes =
2323  paragraph->GetRectsForRange(0, 100, rect_height_style, rect_width_style);
2324  for (size_t i = 0; i < boxes.size(); ++i) {
2325  GetCanvas()->drawRect(boxes[i].rect, paint);
2326  }
2327  ASSERT_EQ(boxes.size(), 5ull);
2328 
2329  paint.setColor(SK_ColorBLUE);
2330  boxes = paragraph->GetRectsForRange(240, 250, rect_height_style,
2331  rect_width_style);
2332  for (size_t i = 0; i < boxes.size(); ++i) {
2333  GetCanvas()->drawRect(boxes[i].rect, paint);
2334  }
2335  ASSERT_EQ(boxes.size(), 1ull);
2336  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 588);
2337  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 130);
2338  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 640);
2339  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 156);
2340  ASSERT_TRUE(Snapshot());
2341 
2342  // All lines should be justified to the width of the
2343  // paragraph.
2344  for (size_t i = 0; i < paragraph->glyph_lines_.size(); ++i) {
2345  ASSERT_EQ(glyph_line_width(i), paragraph_width);
2346  }
2347 }
2348 
2349 TEST_F(ParagraphTest, LINUX_ONLY(JustifyRTLNewLine)) {
2350  const char* text =
2351  "אאא בּבּבּבּ אאאא\nבּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ "
2352  "אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ "
2353  "אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ";
2354 
2355  auto icu_text = icu::UnicodeString::fromUTF8(text);
2356  std::u16string u16_text(icu_text.getBuffer(),
2357  icu_text.getBuffer() + icu_text.length());
2358 
2359  txt::ParagraphStyle paragraph_style;
2360  paragraph_style.max_lines = 14;
2361  paragraph_style.text_align = TextAlign::justify;
2362  paragraph_style.text_direction = TextDirection::rtl;
2363  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2364 
2365  txt::TextStyle text_style;
2366  text_style.font_families = std::vector<std::string>(1, "Ahem");
2367  text_style.font_size = 26;
2368  text_style.color = SK_ColorBLACK;
2369  text_style.height = 1;
2370  builder.PushStyle(text_style);
2371 
2372  builder.AddText(u16_text);
2373 
2374  builder.Pop();
2375 
2376  auto paragraph = BuildParagraph(builder);
2377  size_t paragraph_width = GetTestCanvasWidth() - 100;
2378  paragraph->Layout(paragraph_width);
2379 
2380  paragraph->Paint(GetCanvas(), 0, 0);
2381 
2382  auto glyph_line_width = [&paragraph](int index) {
2383  size_t second_to_last_position_index =
2384  paragraph->glyph_lines_[index].positions.size() - 1;
2385  return paragraph->glyph_lines_[index]
2386  .positions[second_to_last_position_index]
2387  .x_pos.end;
2388  };
2389 
2390  SkPaint paint;
2391  paint.setStyle(SkPaint::kStroke_Style);
2392  paint.setAntiAlias(true);
2393  paint.setStrokeWidth(1);
2394 
2395  ASSERT_TRUE(Snapshot());
2396 
2397  // Tests for GetRectsForRange()
2398  Paragraph::RectHeightStyle rect_height_style =
2400  Paragraph::RectWidthStyle rect_width_style =
2402  paint.setColor(SK_ColorRED);
2403  std::vector<txt::Paragraph::TextBox> boxes =
2404  paragraph->GetRectsForRange(0, 30, rect_height_style, rect_width_style);
2405  for (size_t i = 0; i < boxes.size(); ++i) {
2406  GetCanvas()->drawRect(boxes[i].rect, paint);
2407  }
2408  ASSERT_EQ(boxes.size(), 2ull);
2409  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 562);
2410  EXPECT_FLOAT_EQ(boxes[0].rect.top(), -1.4305115e-06);
2411  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 900);
2412  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 26);
2413 
2414  paint.setColor(SK_ColorBLUE);
2415  boxes = paragraph->GetRectsForRange(240, 250, rect_height_style,
2416  rect_width_style);
2417  for (size_t i = 0; i < boxes.size(); ++i) {
2418  GetCanvas()->drawRect(boxes[i].rect, paint);
2419  }
2420  ASSERT_EQ(boxes.size(), 1ull);
2421  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 68);
2422  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 130);
2423  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 120);
2424  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 156);
2425  ASSERT_TRUE(Snapshot());
2426 
2427  // All lines should be justified to the width of the
2428  // paragraph.
2429  for (size_t i = 0; i < paragraph->glyph_lines_.size(); ++i) {
2430  ASSERT_EQ(glyph_line_width(i), paragraph_width);
2431  }
2432 }
2433 
2435  const char* text = " leading space";
2436 
2437  auto icu_text = icu::UnicodeString::fromUTF8(text);
2438  std::u16string u16_text(icu_text.getBuffer(),
2439  icu_text.getBuffer() + icu_text.length());
2440 
2441  txt::ParagraphStyle paragraph_style;
2442  paragraph_style.max_lines = 14;
2443  paragraph_style.text_align = TextAlign::justify;
2444  paragraph_style.text_direction = TextDirection::rtl;
2445  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2446 
2447  txt::TextStyle text_style;
2448  text_style.font_families = std::vector<std::string>(1, "Ahem");
2449  text_style.font_size = 26;
2450  text_style.color = SK_ColorBLACK;
2451  text_style.height = 1;
2452  builder.PushStyle(text_style);
2453 
2454  builder.AddText(u16_text);
2455 
2456  builder.Pop();
2457 
2458  auto paragraph = BuildParagraph(builder);
2459  size_t paragraph_width = GetTestCanvasWidth() - 100;
2460  paragraph->Layout(paragraph_width);
2461 
2462  paragraph->Paint(GetCanvas(), 0, 0);
2463 
2464  SkPaint paint;
2465  paint.setStyle(SkPaint::kStroke_Style);
2466  paint.setAntiAlias(true);
2467  paint.setStrokeWidth(1);
2468 
2469  // Tests for GetRectsForRange()
2470  Paragraph::RectHeightStyle rect_height_style =
2472  Paragraph::RectWidthStyle rect_width_style =
2474  paint.setColor(SK_ColorRED);
2475  std::vector<txt::Paragraph::TextBox> boxes =
2476  paragraph->GetRectsForRange(0, 100, rect_height_style, rect_width_style);
2477  for (size_t i = 0; i < boxes.size(); ++i) {
2478  GetCanvas()->drawRect(boxes[i].rect, paint);
2479  }
2480  ASSERT_EQ(boxes.size(), 2ull);
2481 
2482  // This test should crash if behavior regresses.
2483 }
2484 
2485 TEST_F(ParagraphTest, DecorationsParagraph) {
2486  txt::ParagraphStyle paragraph_style;
2487  paragraph_style.max_lines = 14;
2488  paragraph_style.text_align = TextAlign::left;
2489  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2490 
2491  txt::TextStyle text_style;
2492  text_style.font_families = std::vector<std::string>(1, "Roboto");
2493  text_style.font_size = 26;
2494  text_style.letter_spacing = 0;
2495  text_style.word_spacing = 5;
2496  text_style.color = SK_ColorBLACK;
2497  text_style.height = 2;
2498  text_style.decoration = TextDecoration::kUnderline |
2502  text_style.decoration_color = SK_ColorBLACK;
2503  text_style.decoration_thickness_multiplier = 2.0;
2504  builder.PushStyle(text_style);
2505  builder.AddText(u"This text should be");
2506 
2508  text_style.decoration_color = SK_ColorBLUE;
2509  text_style.decoration_thickness_multiplier = 1.0;
2510  builder.PushStyle(text_style);
2511  builder.AddText(u" decorated even when");
2512 
2514  text_style.decoration_color = SK_ColorBLACK;
2515  builder.PushStyle(text_style);
2516  builder.AddText(u" wrapped around to");
2517 
2519  text_style.decoration_color = SK_ColorBLACK;
2520  text_style.decoration_thickness_multiplier = 3.0;
2521  builder.PushStyle(text_style);
2522  builder.AddText(u" the next line.");
2523 
2525  text_style.decoration_color = SK_ColorRED;
2526  text_style.decoration_thickness_multiplier = 1.0;
2527  builder.PushStyle(text_style);
2528 
2529  builder.AddText(u" Otherwise, bad things happen.");
2530 
2531  builder.Pop();
2532 
2533  auto paragraph = BuildParagraph(builder);
2534  paragraph->Layout(GetTestCanvasWidth() - 100);
2535 
2536  paragraph->Paint(GetCanvas(), 0, 0);
2537 
2538  ASSERT_TRUE(Snapshot());
2539  ASSERT_EQ(paragraph->runs_.size(), 5ull);
2540  ASSERT_EQ(paragraph->records_.size(), 6ull);
2541 
2542  for (size_t i = 0; i < 6; ++i) {
2543  ASSERT_EQ(paragraph->records_[i].style().decoration,
2546  }
2547 
2548  ASSERT_EQ(paragraph->records_[0].style().decoration_style,
2550  ASSERT_EQ(paragraph->records_[1].style().decoration_style,
2552  ASSERT_EQ(paragraph->records_[2].style().decoration_style,
2554  ASSERT_EQ(paragraph->records_[3].style().decoration_style,
2556  ASSERT_EQ(paragraph->records_[4].style().decoration_style,
2558  ASSERT_EQ(paragraph->records_[5].style().decoration_style,
2560 
2561  ASSERT_EQ(paragraph->records_[0].style().decoration_color, SK_ColorBLACK);
2562  ASSERT_EQ(paragraph->records_[1].style().decoration_color, SK_ColorBLUE);
2563  ASSERT_EQ(paragraph->records_[2].style().decoration_color, SK_ColorBLACK);
2564  ASSERT_EQ(paragraph->records_[3].style().decoration_color, SK_ColorBLACK);
2565  ASSERT_EQ(paragraph->records_[4].style().decoration_color, SK_ColorBLACK);
2566  ASSERT_EQ(paragraph->records_[5].style().decoration_color, SK_ColorRED);
2567 
2568  ASSERT_EQ(paragraph->records_[0].style().decoration_thickness_multiplier,
2569  2.0);
2570  ASSERT_EQ(paragraph->records_[1].style().decoration_thickness_multiplier,
2571  1.0);
2572  ASSERT_EQ(paragraph->records_[2].style().decoration_thickness_multiplier,
2573  1.0);
2574  ASSERT_EQ(paragraph->records_[3].style().decoration_thickness_multiplier,
2575  3.0);
2576  ASSERT_EQ(paragraph->records_[4].style().decoration_thickness_multiplier,
2577  3.0);
2578  ASSERT_EQ(paragraph->records_[5].style().decoration_thickness_multiplier,
2579  1.0);
2580 }
2581 
2582 TEST_F(ParagraphTest, WavyDecorationParagraph) {
2583  txt::ParagraphStyle paragraph_style;
2584  paragraph_style.max_lines = 14;
2585  paragraph_style.text_align = TextAlign::left;
2586  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2587 
2588  txt::TextStyle text_style;
2589  text_style.font_families = std::vector<std::string>(1, "Roboto");
2590  text_style.font_size = 26;
2591  text_style.letter_spacing = 0;
2592  text_style.word_spacing = 5;
2593  text_style.color = SK_ColorBLACK;
2594  text_style.height = 2;
2595  text_style.decoration = TextDecoration::kUnderline |
2598 
2600  text_style.decoration_color = SK_ColorRED;
2601  text_style.decoration_thickness_multiplier = 1.0;
2602  builder.PushStyle(text_style);
2603 
2604  builder.AddText(u" Otherwise, bad things happen.");
2605 
2606  builder.Pop();
2607 
2608  auto paragraph = BuildParagraph(builder);
2609  paragraph->Layout(GetTestCanvasWidth() - 100);
2610 
2611  paragraph->Paint(GetCanvas(), 0, 0);
2612 
2613  ASSERT_TRUE(Snapshot());
2614  ASSERT_EQ(paragraph->runs_.size(), 1ull);
2615  ASSERT_EQ(paragraph->records_.size(), 1ull);
2616 
2617  for (size_t i = 0; i < 1; ++i) {
2618  ASSERT_EQ(paragraph->records_[i].style().decoration,
2621  }
2622 
2623  ASSERT_EQ(paragraph->records_[0].style().decoration_style,
2625 
2626  ASSERT_EQ(paragraph->records_[0].style().decoration_color, SK_ColorRED);
2627 
2628  ASSERT_EQ(paragraph->records_[0].style().decoration_thickness_multiplier,
2629  1.0);
2630 
2631  SkPath path0;
2632  SkPath canonical_path0;
2633  paragraph->ComputeWavyDecoration(path0, 1, 1, 9.56, 1);
2634 
2635  canonical_path0.moveTo(1, 1);
2636  canonical_path0.rQuadTo(1, -1, 2, 0);
2637  canonical_path0.rQuadTo(1, 1, 2, 0);
2638  canonical_path0.rQuadTo(1, -1, 2, 0);
2639  canonical_path0.rQuadTo(1, 1, 2, 0);
2640  canonical_path0.rQuadTo(0.78, -0.78, 1.56, -0.3432);
2641 
2642  ASSERT_EQ(path0.countPoints(), canonical_path0.countPoints());
2643  for (int i = 0; i < canonical_path0.countPoints(); ++i) {
2644  ASSERT_EQ(path0.getPoint(i).x(), canonical_path0.getPoint(i).x());
2645  ASSERT_EQ(path0.getPoint(i).y(), canonical_path0.getPoint(i).y());
2646  }
2647 
2648  SkPath path1;
2649  SkPath canonical_path1;
2650  paragraph->ComputeWavyDecoration(path1, 1, 1, 8.35, 1);
2651 
2652  canonical_path1.moveTo(1, 1);
2653  canonical_path1.rQuadTo(1, -1, 2, 0);
2654  canonical_path1.rQuadTo(1, 1, 2, 0);
2655  canonical_path1.rQuadTo(1, -1, 2, 0);
2656  canonical_path1.rQuadTo(1, 1, 2, 0);
2657  canonical_path1.rQuadTo(0.175, -0.175, 0.35, -0.28875);
2658 
2659  ASSERT_EQ(path1.countPoints(), canonical_path1.countPoints());
2660  for (int i = 0; i < canonical_path1.countPoints(); ++i) {
2661  ASSERT_EQ(path1.getPoint(i).x(), canonical_path1.getPoint(i).x());
2662  ASSERT_EQ(path1.getPoint(i).y(), canonical_path1.getPoint(i).y());
2663  }
2664 
2665  SkPath path2;
2666  SkPath canonical_path2;
2667  paragraph->ComputeWavyDecoration(path2, 1, 1, 10.59, 1);
2668 
2669  canonical_path2.moveTo(1, 1);
2670  canonical_path2.rQuadTo(1, -1, 2, 0);
2671  canonical_path2.rQuadTo(1, 1, 2, 0);
2672  canonical_path2.rQuadTo(1, -1, 2, 0);
2673  canonical_path2.rQuadTo(1, 1, 2, 0);
2674  canonical_path2.rQuadTo(1, -1, 2, 0);
2675  canonical_path2.rQuadTo(0.295, 0.295, 0.59, 0.41595);
2676 
2677  ASSERT_EQ(path2.countPoints(), canonical_path2.countPoints());
2678  for (int i = 0; i < canonical_path2.countPoints(); ++i) {
2679  ASSERT_EQ(path2.getPoint(i).x(), canonical_path2.getPoint(i).x());
2680  ASSERT_EQ(path2.getPoint(i).y(), canonical_path2.getPoint(i).y());
2681  }
2682 
2683  SkPath path3;
2684  SkPath canonical_path3;
2685  paragraph->ComputeWavyDecoration(path3, 1, 1, 11.2, 1);
2686 
2687  canonical_path3.moveTo(1, 1);
2688  canonical_path3.rQuadTo(1, -1, 2, 0);
2689  canonical_path3.rQuadTo(1, 1, 2, 0);
2690  canonical_path3.rQuadTo(1, -1, 2, 0);
2691  canonical_path3.rQuadTo(1, 1, 2, 0);
2692  canonical_path3.rQuadTo(1, -1, 2, 0);
2693  canonical_path3.rQuadTo(0.6, 0.6, 1.2, 0.48);
2694 
2695  ASSERT_EQ(path3.countPoints(), canonical_path3.countPoints());
2696  for (int i = 0; i < canonical_path3.countPoints(); ++i) {
2697  ASSERT_EQ(path3.getPoint(i).x(), canonical_path3.getPoint(i).x());
2698  ASSERT_EQ(path3.getPoint(i).y(), canonical_path3.getPoint(i).y());
2699  }
2700 
2701  SkPath path4;
2702  SkPath canonical_path4;
2703  paragraph->ComputeWavyDecoration(path4, 1, 1, 12, 1);
2704 
2705  canonical_path4.moveTo(1, 1);
2706  canonical_path4.rQuadTo(1, -1, 2, 0);
2707  canonical_path4.rQuadTo(1, 1, 2, 0);
2708  canonical_path4.rQuadTo(1, -1, 2, 0);
2709  canonical_path4.rQuadTo(1, 1, 2, 0);
2710  canonical_path4.rQuadTo(1, -1, 2, 0);
2711  canonical_path4.rQuadTo(1, 1, 2, 0);
2712 
2713  ASSERT_EQ(path4.countPoints(), canonical_path4.countPoints());
2714  for (int i = 0; i < canonical_path4.countPoints(); ++i) {
2715  ASSERT_EQ(path4.getPoint(i).x(), canonical_path4.getPoint(i).x());
2716  ASSERT_EQ(path4.getPoint(i).y(), canonical_path4.getPoint(i).y());
2717  }
2718 }
2719 
2720 TEST_F(ParagraphTest, ItalicsParagraph) {
2721  txt::ParagraphStyle paragraph_style;
2722  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2723 
2724  txt::TextStyle text_style;
2725  text_style.font_families = std::vector<std::string>(1, "Roboto");
2726  text_style.color = SK_ColorRED;
2727  text_style.font_size = 10;
2728  builder.PushStyle(text_style);
2729  builder.AddText(u"No italic ");
2730 
2731  text_style.font_style = txt::FontStyle::italic;
2732  builder.PushStyle(text_style);
2733  builder.AddText(u"Yes Italic ");
2734 
2735  builder.Pop();
2736  builder.AddText(u"No Italic again.");
2737 
2738  auto paragraph = BuildParagraph(builder);
2739  paragraph->Layout(GetTestCanvasWidth());
2740 
2741  paragraph->Paint(GetCanvas(), 0, 0);
2742 
2743  ASSERT_EQ(paragraph->runs_.runs_.size(), 3ull);
2744  ASSERT_EQ(paragraph->runs_.styles_.size(), 3ull);
2745  ASSERT_EQ(paragraph->records_[1].style().color, text_style.color);
2746  ASSERT_EQ(paragraph->records_[1].style().font_style, txt::FontStyle::italic);
2747  ASSERT_EQ(paragraph->records_[2].style().font_style, txt::FontStyle::normal);
2748  ASSERT_EQ(paragraph->records_[0].style().font_style, txt::FontStyle::normal);
2749  ASSERT_TRUE(Snapshot());
2750 }
2751 
2752 TEST_F(ParagraphTest, ChineseParagraph) {
2753  const char* text =
2754  "左線読設重説切後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
2755  "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得庭"
2756  "際輝求佐抗蒼提夜合逃表。注統天言件自謙雅載報紙喪。作画稿愛器灯女書利変探"
2757  "訃第金線朝開化建。子戦年帝励害表月幕株漠新期刊人秘。図的海力生禁挙保天戦"
2758  "聞条年所在口。";
2759  auto icu_text = icu::UnicodeString::fromUTF8(text);
2760  std::u16string u16_text(icu_text.getBuffer(),
2761  icu_text.getBuffer() + icu_text.length());
2762 
2763  txt::ParagraphStyle paragraph_style;
2764  paragraph_style.max_lines = 14;
2765  paragraph_style.text_align = TextAlign::justify;
2766  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2767 
2768  txt::TextStyle text_style;
2769  text_style.color = SK_ColorBLACK;
2770  text_style.font_size = 35;
2771  text_style.letter_spacing = 2;
2772  text_style.font_families = std::vector<std::string>(1, "Source Han Serif CN");
2773  text_style.decoration = TextDecoration::kUnderline |
2777  text_style.decoration_color = SK_ColorBLACK;
2778  builder.PushStyle(text_style);
2779 
2780  builder.AddText(u16_text);
2781 
2782  builder.Pop();
2783 
2784  auto paragraph = BuildParagraph(builder);
2785  paragraph->Layout(GetTestCanvasWidth() - 100);
2786 
2787  paragraph->Paint(GetCanvas(), 0, 0);
2788 
2789  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
2790  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
2791  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
2792  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
2793  ASSERT_EQ(paragraph->records_.size(), 7ull);
2794 
2795  ASSERT_TRUE(Snapshot());
2796 }
2797 
2798 // TODO(garyq): Support RTL languages.
2799 TEST_F(ParagraphTest, DISABLED_ArabicParagraph) {
2800  const char* text =
2801  "من أسر وإعلان الخاصّة وهولندا،, عل قائمة الضغوط بالمطالبة تلك. الصفحة "
2802  "بمباركة التقليدية قام عن. تصفح";
2803  auto icu_text = icu::UnicodeString::fromUTF8(text);
2804  std::u16string u16_text(icu_text.getBuffer(),
2805  icu_text.getBuffer() + icu_text.length());
2806 
2807  txt::ParagraphStyle paragraph_style;
2808  paragraph_style.max_lines = 14;
2809  paragraph_style.text_align = TextAlign::right;
2810  paragraph_style.text_direction = TextDirection::rtl;
2811  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2812 
2813  txt::TextStyle text_style;
2814  text_style.color = SK_ColorBLACK;
2815  text_style.font_size = 35;
2816  text_style.letter_spacing = 2;
2817  text_style.font_families = std::vector<std::string>(1, "Katibeh");
2818  text_style.decoration = TextDecoration::kUnderline |
2822  text_style.decoration_color = SK_ColorBLACK;
2823  builder.PushStyle(text_style);
2824 
2825  builder.AddText(u16_text);
2826 
2827  builder.Pop();
2828 
2829  auto paragraph = BuildParagraph(builder);
2830  paragraph->Layout(GetTestCanvasWidth() - 100);
2831 
2832  paragraph->Paint(GetCanvas(), 0, 0);
2833 
2834  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
2835 
2836  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
2837  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
2838  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
2839  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
2840  ASSERT_EQ(paragraph->records_.size(), 2ull);
2841  ASSERT_EQ(paragraph->paragraph_style_.text_direction, TextDirection::rtl);
2842 
2843  for (size_t i = 0; i < u16_text.length(); i++) {
2844  ASSERT_EQ(paragraph->text_[i], u16_text[u16_text.length() - i]);
2845  }
2846 
2847  ASSERT_TRUE(Snapshot());
2848 }
2849 
2850 // Checks if the rects are in the correct positions after typing spaces in
2851 // Arabic.
2852 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsParagraph)) {
2853  const char* text = "بمباركة التقليدية قام عن. تصفح يد ";
2854  auto icu_text = icu::UnicodeString::fromUTF8(text);
2855  std::u16string u16_text(icu_text.getBuffer(),
2856  icu_text.getBuffer() + icu_text.length());
2857 
2858  txt::ParagraphStyle paragraph_style;
2859  paragraph_style.max_lines = 14;
2860  paragraph_style.text_align = TextAlign::right;
2861  paragraph_style.text_direction = TextDirection::rtl;
2862  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2863 
2864  txt::TextStyle text_style;
2865  text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
2866  text_style.font_size = 26;
2867  text_style.letter_spacing = 1;
2868  text_style.word_spacing = 5;
2869  text_style.color = SK_ColorBLACK;
2870  text_style.height = 1;
2872  text_style.decoration_color = SK_ColorBLACK;
2873  builder.PushStyle(text_style);
2874 
2875  builder.AddText(u16_text);
2876 
2877  builder.Pop();
2878 
2879  auto paragraph = BuildParagraph(builder);
2880  paragraph->Layout(GetTestCanvasWidth() - 100);
2881 
2882  paragraph->Paint(GetCanvas(), 0, 0);
2883 
2884  SkPaint paint;
2885  paint.setStyle(SkPaint::kStroke_Style);
2886  paint.setAntiAlias(true);
2887  paint.setStrokeWidth(1);
2888 
2889  // Tests for GetRectsForRange()
2890  Paragraph::RectHeightStyle rect_height_style =
2892  Paragraph::RectWidthStyle rect_width_style =
2894  paint.setColor(SK_ColorRED);
2895  std::vector<txt::Paragraph::TextBox> boxes =
2896  paragraph->GetRectsForRange(0, 100, rect_height_style, rect_width_style);
2897  for (size_t i = 0; i < boxes.size(); ++i) {
2898  GetCanvas()->drawRect(boxes[i].rect, paint);
2899  }
2900  EXPECT_EQ(boxes.size(), 2ull);
2901 
2902  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 556.48438);
2903  EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
2904  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 900);
2905  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
2906 
2907  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 510.03125);
2908  EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469);
2909  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 556.98438);
2910  EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 44);
2911 
2912  ASSERT_EQ(paragraph_style.text_align,
2913  paragraph->GetParagraphStyle().text_align);
2914 
2915  ASSERT_TRUE(Snapshot());
2916 }
2917 
2918 // Trailing space at the end of the arabic rtl run should be at the left end of
2919 // the arabic run.
2920 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRLeftAlignParagraph)) {
2921  const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
2922  auto icu_text = icu::UnicodeString::fromUTF8(text);
2923  std::u16string u16_text(icu_text.getBuffer(),
2924  icu_text.getBuffer() + icu_text.length());
2925 
2926  txt::ParagraphStyle paragraph_style;
2927  paragraph_style.max_lines = 14;
2928  paragraph_style.text_align = TextAlign::left;
2929  paragraph_style.text_direction = TextDirection::ltr;
2930  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2931 
2932  txt::TextStyle text_style;
2933  text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
2934  text_style.font_size = 26;
2935  text_style.letter_spacing = 1;
2936  text_style.word_spacing = 5;
2937  text_style.color = SK_ColorBLACK;
2938  text_style.height = 1;
2940  text_style.decoration_color = SK_ColorBLACK;
2941  builder.PushStyle(text_style);
2942 
2943  builder.AddText(u16_text);
2944 
2945  builder.Pop();
2946 
2947  auto paragraph = BuildParagraph(builder);
2948  paragraph->Layout(GetTestCanvasWidth() - 100);
2949 
2950  paragraph->Paint(GetCanvas(), 0, 0);
2951 
2952  SkPaint paint;
2953  paint.setStyle(SkPaint::kStroke_Style);
2954  paint.setAntiAlias(true);
2955  paint.setStrokeWidth(1);
2956 
2957  // Tests for GetRectsForRange()
2958  Paragraph::RectHeightStyle rect_height_style =
2960  Paragraph::RectWidthStyle rect_width_style =
2962  paint.setColor(SK_ColorRED);
2963  std::vector<txt::Paragraph::TextBox> boxes =
2964  paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style);
2965  for (size_t i = 0; i < boxes.size(); ++i) {
2966  GetCanvas()->drawRect(boxes[i].rect, paint);
2967  }
2968  EXPECT_EQ(boxes.size(), 1ull);
2969 
2970  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 89.425781);
2971  EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
2972  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 121.90625);
2973  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
2974 
2975  ASSERT_EQ(paragraph_style.text_align,
2976  paragraph->GetParagraphStyle().text_align);
2977 
2978  ASSERT_TRUE(Snapshot());
2979 }
2980 
2981 // Trailing space at the end of the arabic rtl run should be at the left end of
2982 // the arabic run and be a ghost space.
2983 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRRightAlignParagraph)) {
2984  const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
2985  auto icu_text = icu::UnicodeString::fromUTF8(text);
2986  std::u16string u16_text(icu_text.getBuffer(),
2987  icu_text.getBuffer() + icu_text.length());
2988 
2989  txt::ParagraphStyle paragraph_style;
2990  paragraph_style.max_lines = 14;
2991  paragraph_style.text_align = TextAlign::right;
2992  paragraph_style.text_direction = TextDirection::ltr;
2993  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
2994 
2995  txt::TextStyle text_style;
2996  text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
2997  text_style.font_size = 26;
2998  text_style.letter_spacing = 1;
2999  text_style.word_spacing = 5;
3000  text_style.color = SK_ColorBLACK;
3001  text_style.height = 1;
3003  text_style.decoration_color = SK_ColorBLACK;
3004  builder.PushStyle(text_style);
3005 
3006  builder.AddText(u16_text);
3007 
3008  builder.Pop();
3009 
3010  auto paragraph = BuildParagraph(builder);
3011  paragraph->Layout(GetTestCanvasWidth() - 100);
3012 
3013  paragraph->Paint(GetCanvas(), 0, 0);
3014 
3015  SkPaint paint;
3016  paint.setStyle(SkPaint::kStroke_Style);
3017  paint.setAntiAlias(true);
3018  paint.setStrokeWidth(1);
3019 
3020  // Tests for GetRectsForRange()
3021  Paragraph::RectHeightStyle rect_height_style =
3023  Paragraph::RectWidthStyle rect_width_style =
3025  paint.setColor(SK_ColorRED);
3026  std::vector<txt::Paragraph::TextBox> boxes =
3027  paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style);
3028  for (size_t i = 0; i < boxes.size(); ++i) {
3029  GetCanvas()->drawRect(boxes[i].rect, paint);
3030  }
3031  EXPECT_EQ(boxes.size(), 2ull);
3032 
3033  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 556.48438);
3034  EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
3035  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 577.72656);
3036  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
3037 
3038  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 545.24609);
3039  EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469);
3040  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 556.98438);
3041  EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 44);
3042 
3043  ASSERT_EQ(paragraph_style.text_align,
3044  paragraph->GetParagraphStyle().text_align);
3045 
3046  ASSERT_TRUE(Snapshot());
3047 }
3048 
3049 TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateParagraph) {
3050  const char* text =
3051  "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
3052  "67890 12345";
3053  auto icu_text = icu::UnicodeString::fromUTF8(text);
3054  std::u16string u16_text(icu_text.getBuffer(),
3055  icu_text.getBuffer() + icu_text.length());
3056 
3057  txt::ParagraphStyle paragraph_style;
3058  paragraph_style.max_lines = 10;
3059  paragraph_style.text_align = TextAlign::left;
3060  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3061 
3062  txt::TextStyle text_style;
3063  text_style.font_families = std::vector<std::string>(1, "Roboto");
3064  text_style.font_size = 50;
3065  text_style.letter_spacing = 1;
3066  text_style.word_spacing = 5;
3067  text_style.color = SK_ColorBLACK;
3068  text_style.height = 1;
3069  builder.PushStyle(text_style);
3070 
3071  builder.AddText(u16_text);
3072 
3073  builder.Pop();
3074 
3075  auto paragraph = BuildParagraph(builder);
3076  paragraph->Layout(550);
3077 
3078  paragraph->Paint(GetCanvas(), 0, 0);
3079 
3080  ASSERT_TRUE(Snapshot());
3081 
3082  // Tests for GetGlyphPositionAtCoordinate()
3083  // NOTE: resulting values can be a few off from their respective positions in
3084  // the original text because the final trailing whitespaces are sometimes not
3085  // drawn (namely, when using "justify" alignment) and therefore are not active
3086  // glyphs.
3087  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-10000, -10000).position,
3088  0ull);
3089  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-1, -1).position, 0ull);
3090  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0, 0).position, 0ull);
3091  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(3, 3).position, 0ull);
3092  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(35, 1).position, 1ull);
3093  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(300, 2).position, 11ull);
3094  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(301, 2.2).position, 11ull);
3095  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(302, 2.6).position, 11ull);
3096  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(301, 2.1).position, 11ull);
3097  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(100000, 20).position,
3098  18ull);
3099  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(450, 20).position, 16ull);
3100  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(100000, 90).position,
3101  36ull);
3102  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-100000, 90).position,
3103  18ull);
3104  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20, -80).position, 1ull);
3105  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 90).position, 18ull);
3106  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 170).position, 36ull);
3107  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 180).position,
3108  72ull);
3109  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(70, 180).position, 56ull);
3110  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 270).position, 72ull);
3111  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(35, 90).position, 19ull);
3112  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 10000).position,
3113  77ull);
3114  ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(85, 10000).position, 75ull);
3115 }
3116 
3117 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
3118  const char* text =
3119  "12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
3120  "67890 12345";
3121  auto icu_text = icu::UnicodeString::fromUTF8(text);
3122  std::u16string u16_text(icu_text.getBuffer(),
3123  icu_text.getBuffer() + icu_text.length());
3124 
3125  txt::ParagraphStyle paragraph_style;
3126  paragraph_style.max_lines = 10;
3127  paragraph_style.text_align = TextAlign::left;
3128  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3129 
3130  txt::TextStyle text_style;
3131  text_style.font_families = std::vector<std::string>(1, "Roboto");
3132  text_style.font_size = 50;
3133  text_style.letter_spacing = 0;
3134  text_style.font_weight = FontWeight::w500;
3135  text_style.word_spacing = 0;
3136  text_style.color = SK_ColorBLACK;
3137  text_style.height = 1;
3138  builder.PushStyle(text_style);
3139 
3140  builder.AddText(u16_text);
3141 
3142  builder.Pop();
3143 
3144  auto paragraph = BuildParagraph(builder);
3145  paragraph->Layout(550);
3146 
3147  paragraph->Paint(GetCanvas(), 0, 0);
3148 
3149  SkPaint paint;
3150  paint.setStyle(SkPaint::kStroke_Style);
3151  paint.setAntiAlias(true);
3152  paint.setStrokeWidth(1);
3153 
3154  // Tests for GetRectsForRange()
3155  // NOTE: The base truth values may still need adjustment as the specifics
3156  // are adjusted.
3157  Paragraph::RectHeightStyle rect_height_style =
3159  Paragraph::RectWidthStyle rect_width_style =
3161  paint.setColor(SK_ColorRED);
3162  std::vector<txt::Paragraph::TextBox> boxes =
3163  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3164  for (size_t i = 0; i < boxes.size(); ++i) {
3165  GetCanvas()->drawRect(boxes[i].rect, paint);
3166  }
3167  EXPECT_EQ(boxes.size(), 0ull);
3168 
3169  boxes =
3170  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3171  for (size_t i = 0; i < boxes.size(); ++i) {
3172  GetCanvas()->drawRect(boxes[i].rect, paint);
3173  }
3174  EXPECT_EQ(boxes.size(), 1ull);
3175  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
3176  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3177  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 28.417969);
3178  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3179 
3180  paint.setColor(SK_ColorBLUE);
3181  boxes =
3182  paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
3183  for (size_t i = 0; i < boxes.size(); ++i) {
3184  GetCanvas()->drawRect(boxes[i].rect, paint);
3185  }
3186  EXPECT_EQ(boxes.size(), 1ull);
3187  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 56.835938);
3188  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3189  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 177.98438);
3190  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3191 
3192  paint.setColor(SK_ColorGREEN);
3193  boxes =
3194  paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
3195  for (size_t i = 0; i < boxes.size(); ++i) {
3196  GetCanvas()->drawRect(boxes[i].rect, paint);
3197  }
3198  EXPECT_EQ(boxes.size(), 1ull);
3199  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177.98438);
3200  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3201  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 507.03906);
3202  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3203 
3204  paint.setColor(SK_ColorRED);
3205  boxes =
3206  paragraph->GetRectsForRange(30, 100, rect_height_style, rect_width_style);
3207  for (size_t i = 0; i < boxes.size(); ++i) {
3208  GetCanvas()->drawRect(boxes[i].rect, paint);
3209  }
3210  EXPECT_EQ(boxes.size(), 4ull);
3211  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 211.37891);
3212  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
3213  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 463.62891);
3214  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
3215 
3216  // TODO(garyq): The following set of vals are definitely wrong and
3217  // end of paragraph handling needs to be fixed in a later patch.
3218  EXPECT_FLOAT_EQ(boxes[3].rect.left(), 0);
3219  EXPECT_FLOAT_EQ(boxes[3].rect.top(), 236.40625);
3220  EXPECT_FLOAT_EQ(boxes[3].rect.right(), 142.08984);
3221  EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 295);
3222 
3223  paint.setColor(SK_ColorBLUE);
3224  boxes =
3225  paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
3226  for (size_t i = 0; i < boxes.size(); ++i) {
3227  GetCanvas()->drawRect(boxes[i].rect, paint);
3228  }
3229  EXPECT_EQ(boxes.size(), 1ull);
3230  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 450.20312);
3231  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3232  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519.49219);
3233  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3234 
3235  paint.setColor(SK_ColorRED);
3236  boxes =
3237  paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3238  for (size_t i = 0; i < boxes.size(); ++i) {
3239  GetCanvas()->drawRect(boxes[i].rect, paint);
3240  }
3241  EXPECT_EQ(boxes.size(), 0ull);
3242 
3243  ASSERT_TRUE(Snapshot());
3244 }
3245 
3246 TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeTight)) {
3247  const char* text =
3248  "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3249  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3250  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
3251  auto icu_text = icu::UnicodeString::fromUTF8(text);
3252  std::u16string u16_text(icu_text.getBuffer(),
3253  icu_text.getBuffer() + icu_text.length());
3254 
3255  txt::ParagraphStyle paragraph_style;
3256  paragraph_style.max_lines = 10;
3257  paragraph_style.text_align = TextAlign::left;
3258  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3259 
3260  txt::TextStyle text_style;
3261  text_style.font_families = std::vector<std::string>(1, "Noto Sans CJK JP");
3262  text_style.font_size = 50;
3263  text_style.letter_spacing = 0;
3264  text_style.font_weight = FontWeight::w500;
3265  text_style.word_spacing = 0;
3266  text_style.color = SK_ColorBLACK;
3267  text_style.height = 1;
3268  builder.PushStyle(text_style);
3269 
3270  builder.AddText(u16_text);
3271 
3272  builder.Pop();
3273 
3274  auto paragraph = BuildParagraph(builder);
3275  paragraph->Layout(550);
3276 
3277  paragraph->Paint(GetCanvas(), 0, 0);
3278 
3279  SkPaint paint;
3280  paint.setStyle(SkPaint::kStroke_Style);
3281  paint.setAntiAlias(true);
3282  paint.setStrokeWidth(1);
3283 
3284  // Tests for GetRectsForRange()
3285  // NOTE: The base truth values may still need adjustment as the specifics
3286  // are adjusted.
3287  Paragraph::RectHeightStyle rect_height_style =
3289  Paragraph::RectWidthStyle rect_width_style =
3291  paint.setColor(SK_ColorRED);
3292  std::vector<txt::Paragraph::TextBox> boxes =
3293  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3294  for (size_t i = 0; i < boxes.size(); ++i) {
3295  GetCanvas()->drawRect(boxes[i].rect, paint);
3296  }
3297  EXPECT_EQ(boxes.size(), 0ull);
3298 
3299  boxes =
3300  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3301  for (size_t i = 0; i < boxes.size(); ++i) {
3302  GetCanvas()->drawRect(boxes[i].rect, paint);
3303  }
3304  EXPECT_EQ(boxes.size(), 1ull);
3305  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
3306  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
3307  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.898438);
3308  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
3309 
3310  paint.setColor(SK_ColorBLUE);
3311  boxes =
3312  paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
3313  for (size_t i = 0; i < boxes.size(); ++i) {
3314  GetCanvas()->drawRect(boxes[i].rect, paint);
3315  }
3316  EXPECT_EQ(boxes.size(), 1ull);
3317  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
3318  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 264.09766);
3319  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
3320 
3321  paint.setColor(SK_ColorGREEN);
3322  boxes =
3323  paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
3324  for (size_t i = 0; i < boxes.size(); ++i) {
3325  GetCanvas()->drawRect(boxes[i].rect, paint);
3326  }
3327  EXPECT_EQ(boxes.size(), 2ull);
3328  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 264.09766);
3329  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
3330  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 595.09375);
3331  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
3332 
3333  ASSERT_TRUE(Snapshot());
3334 }
3335 
3337  DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingMiddle)) {
3338  const char* text =
3339  "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3340  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3341  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
3342  auto icu_text = icu::UnicodeString::fromUTF8(text);
3343  std::u16string u16_text(icu_text.getBuffer(),
3344  icu_text.getBuffer() + icu_text.length());
3345 
3346  txt::ParagraphStyle paragraph_style;
3347  paragraph_style.max_lines = 10;
3348  paragraph_style.text_align = TextAlign::left;
3349  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3350 
3351  txt::TextStyle text_style;
3352  text_style.font_families = std::vector<std::string>(1, "Roboto");
3353  text_style.font_size = 50;
3354  text_style.letter_spacing = 0;
3355  text_style.font_weight = FontWeight::w500;
3356  text_style.word_spacing = 0;
3357  text_style.color = SK_ColorBLACK;
3358  text_style.height = 1.6;
3359  text_style.has_height_override = true;
3360  builder.PushStyle(text_style);
3361 
3362  builder.AddText(u16_text);
3363 
3364  builder.Pop();
3365 
3366  auto paragraph = BuildParagraph(builder);
3367  paragraph->Layout(550);
3368 
3369  paragraph->Paint(GetCanvas(), 0, 0);
3370 
3371  SkPaint paint;
3372  paint.setStyle(SkPaint::kStroke_Style);
3373  paint.setAntiAlias(true);
3374  paint.setStrokeWidth(1);
3375 
3376  // Tests for GetRectsForRange()
3377  // NOTE: The base truth values may still need adjustment as the specifics
3378  // are adjusted.
3379  Paragraph::RectHeightStyle rect_height_style =
3382  paint.setColor(SK_ColorRED);
3383  std::vector<txt::Paragraph::TextBox> boxes =
3384  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3385  for (size_t i = 0; i < boxes.size(); ++i) {
3386  GetCanvas()->drawRect(boxes[i].rect, paint);
3387  }
3388  EXPECT_EQ(boxes.size(), 0ull);
3389 
3390  boxes =
3391  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3392  for (size_t i = 0; i < boxes.size(); ++i) {
3393  GetCanvas()->drawRect(boxes[i].rect, paint);
3394  }
3395  EXPECT_EQ(boxes.size(), 1ull);
3396  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
3397  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3398  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.433594);
3399  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305);
3400 
3401  paint.setColor(SK_ColorBLUE);
3402  boxes =
3403  paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
3404  for (size_t i = 0; i < boxes.size(); ++i) {
3405  GetCanvas()->drawRect(boxes[i].rect, paint);
3406  }
3407  EXPECT_EQ(boxes.size(), 1ull);
3408  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.433594);
3409  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3410  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.01953);
3411  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305);
3412 
3413  paint.setColor(SK_ColorGREEN);
3414  boxes =
3415  paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
3416  for (size_t i = 0; i < boxes.size(); ++i) {
3417  GetCanvas()->drawRect(boxes[i].rect, paint);
3418  }
3419  EXPECT_EQ(boxes.size(), 1ull);
3420  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.01953);
3421  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3422  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.09375);
3423  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473312);
3424 
3425  paint.setColor(SK_ColorRED);
3426  boxes =
3427  paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style);
3428  for (size_t i = 0; i < boxes.size(); ++i) {
3429  GetCanvas()->drawRect(boxes[i].rect, paint);
3430  }
3431  EXPECT_EQ(boxes.size(), 8ull);
3432  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.01953);
3433  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 88.473312);
3434  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.72266);
3435  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 168.47331);
3436 
3437  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.72266);
3438  EXPECT_FLOAT_EQ(boxes[1].rect.top(), 88.473312);
3439  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.05859);
3440  EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 168.4733);
3441 
3442  EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0);
3443  EXPECT_FLOAT_EQ(boxes[2].rect.top(), 168.4733);
3444  EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.60547);
3445  EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 248.47331);
3446 
3447  EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.60547);
3448  EXPECT_FLOAT_EQ(boxes[3].rect.top(), 168.4733);
3449  EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.05859);
3450  EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 248.47331);
3451 
3452  EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0);
3453  EXPECT_FLOAT_EQ(boxes[4].rect.top(), 248.47331);
3454  EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.05859);
3455  EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 328.4733);
3456 
3457  EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0);
3458  EXPECT_FLOAT_EQ(boxes[5].rect.top(), 328.47333);
3459  EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.05859);
3460  EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 408.4733);
3461 
3462  paint.setColor(SK_ColorBLUE);
3463  boxes =
3464  paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
3465  for (size_t i = 0; i < boxes.size(); ++i) {
3466  GetCanvas()->drawRect(boxes[i].rect, paint);
3467  }
3468  EXPECT_EQ(boxes.size(), 1ull);
3469  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.75781);
3470  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3471  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.26172);
3472  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305);
3473 
3474  paint.setColor(SK_ColorRED);
3475  boxes =
3476  paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3477  for (size_t i = 0; i < boxes.size(); ++i) {
3478  GetCanvas()->drawRect(boxes[i].rect, paint);
3479  }
3480  EXPECT_EQ(boxes.size(), 0ull);
3481 
3482  ASSERT_TRUE(Snapshot());
3483 }
3484 
3486  DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingTop)) {
3487  const char* text =
3488  "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3489  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3490  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
3491  auto icu_text = icu::UnicodeString::fromUTF8(text);
3492  std::u16string u16_text(icu_text.getBuffer(),
3493  icu_text.getBuffer() + icu_text.length());
3494 
3495  txt::ParagraphStyle paragraph_style;
3496  paragraph_style.max_lines = 10;
3497  paragraph_style.text_align = TextAlign::left;
3498  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3499 
3500  txt::TextStyle text_style;
3501  text_style.font_families = std::vector<std::string>(1, "Roboto");
3502  text_style.font_size = 50;
3503  text_style.letter_spacing = 0;
3504  text_style.font_weight = FontWeight::w500;
3505  text_style.word_spacing = 0;
3506  text_style.color = SK_ColorBLACK;
3507  text_style.height = 1.6;
3508  text_style.has_height_override = true;
3509  builder.PushStyle(text_style);
3510 
3511  builder.AddText(u16_text);
3512 
3513  builder.Pop();
3514 
3515  auto paragraph = BuildParagraph(builder);
3516  paragraph->Layout(550);
3517 
3518  paragraph->Paint(GetCanvas(), 0, 0);
3519 
3520  SkPaint paint;
3521  paint.setStyle(SkPaint::kStroke_Style);
3522  paint.setAntiAlias(true);
3523  paint.setStrokeWidth(1);
3524 
3525  // Tests for GetRectsForRange()
3526  // NOTE: The base truth values may still need adjustment as the specifics
3527  // are adjusted.
3528  Paragraph::RectHeightStyle rect_height_style =
3531  paint.setColor(SK_ColorRED);
3532  std::vector<txt::Paragraph::TextBox> boxes =
3533  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3534  for (size_t i = 0; i < boxes.size(); ++i) {
3535  GetCanvas()->drawRect(boxes[i].rect, paint);
3536  }
3537  EXPECT_EQ(boxes.size(), 0ull);
3538 
3539  boxes =
3540  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3541  for (size_t i = 0; i < boxes.size(); ++i) {
3542  GetCanvas()->drawRect(boxes[i].rect, paint);
3543  }
3544  EXPECT_EQ(boxes.size(), 1ull);
3545  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
3546  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3547  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.433594);
3548  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
3549 
3550  paint.setColor(SK_ColorBLUE);
3551  boxes =
3552  paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
3553  for (size_t i = 0; i < boxes.size(); ++i) {
3554  GetCanvas()->drawRect(boxes[i].rect, paint);
3555  }
3556  EXPECT_EQ(boxes.size(), 1ull);
3557  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.433594);
3558  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3559  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.01953);
3560  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
3561 
3562  paint.setColor(SK_ColorGREEN);
3563  boxes =
3564  paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
3565  for (size_t i = 0; i < boxes.size(); ++i) {
3566  GetCanvas()->drawRect(boxes[i].rect, paint);
3567  }
3568  EXPECT_EQ(boxes.size(), 1ull);
3569  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.01953);
3570  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3571  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.09375);
3572  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
3573 
3574  paint.setColor(SK_ColorRED);
3575  boxes =
3576  paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style);
3577  for (size_t i = 0; i < boxes.size(); ++i) {
3578  GetCanvas()->drawRect(boxes[i].rect, paint);
3579  }
3580  EXPECT_EQ(boxes.size(), 8ull);
3581  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.01953);
3582  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 80);
3583  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.72266);
3584  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
3585 
3586  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.72266);
3587  EXPECT_FLOAT_EQ(boxes[1].rect.top(), 80);
3588  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.05859);
3589  EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 160);
3590 
3591  EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0);
3592  EXPECT_FLOAT_EQ(boxes[2].rect.top(), 160);
3593  EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.60547);
3594  EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 240);
3595 
3596  EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.60547);
3597  EXPECT_FLOAT_EQ(boxes[3].rect.top(), 160);
3598  EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.05859);
3599  EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 240);
3600 
3601  EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0);
3602  EXPECT_FLOAT_EQ(boxes[4].rect.top(), 240);
3603  EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.05859);
3604  EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 320);
3605 
3606  EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0);
3607  EXPECT_FLOAT_EQ(boxes[5].rect.top(), 320);
3608  EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.05859);
3609  EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 400);
3610 
3611  paint.setColor(SK_ColorBLUE);
3612  boxes =
3613  paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
3614  for (size_t i = 0; i < boxes.size(); ++i) {
3615  GetCanvas()->drawRect(boxes[i].rect, paint);
3616  }
3617  EXPECT_EQ(boxes.size(), 1ull);
3618  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.75781);
3619  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3620  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.26172);
3621  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
3622 
3623  paint.setColor(SK_ColorRED);
3624  boxes =
3625  paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3626  for (size_t i = 0; i < boxes.size(); ++i) {
3627  GetCanvas()->drawRect(boxes[i].rect, paint);
3628  }
3629  EXPECT_EQ(boxes.size(), 0ull);
3630 
3631  ASSERT_TRUE(Snapshot());
3632 }
3633 
3635  DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingBottom)) {
3636  const char* text =
3637  "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3638  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
3639  " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
3640  auto icu_text = icu::UnicodeString::fromUTF8(text);
3641  std::u16string u16_text(icu_text.getBuffer(),
3642  icu_text.getBuffer() + icu_text.length());
3643 
3644  txt::ParagraphStyle paragraph_style;
3645  paragraph_style.max_lines = 10;
3646  paragraph_style.text_align = TextAlign::left;
3647  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3648 
3649  txt::TextStyle text_style;
3650  text_style.font_families = std::vector<std::string>(1, "Roboto");
3651  text_style.font_size = 50;
3652  text_style.letter_spacing = 0;
3653  text_style.font_weight = FontWeight::w500;
3654  text_style.word_spacing = 0;
3655  text_style.color = SK_ColorBLACK;
3656  text_style.height = 1.6;
3657  text_style.has_height_override = true;
3658  builder.PushStyle(text_style);
3659 
3660  builder.AddText(u16_text);
3661 
3662  builder.Pop();
3663 
3664  auto paragraph = BuildParagraph(builder);
3665  paragraph->Layout(550);
3666 
3667  paragraph->Paint(GetCanvas(), 0, 0);
3668 
3669  SkPaint paint;
3670  paint.setStyle(SkPaint::kStroke_Style);
3671  paint.setAntiAlias(true);
3672  paint.setStrokeWidth(1);
3673 
3674  // Tests for GetRectsForRange()
3675  // NOTE: The base truth values may still need adjustment as the specifics
3676  // are adjusted.
3677  Paragraph::RectHeightStyle rect_height_style =
3680  paint.setColor(SK_ColorRED);
3681  std::vector<txt::Paragraph::TextBox> boxes =
3682  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3683  for (size_t i = 0; i < boxes.size(); ++i) {
3684  GetCanvas()->drawRect(boxes[i].rect, paint);
3685  }
3686  EXPECT_EQ(boxes.size(), 0ull);
3687 
3688  boxes =
3689  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3690  for (size_t i = 0; i < boxes.size(); ++i) {
3691  GetCanvas()->drawRect(boxes[i].rect, paint);
3692  }
3693  EXPECT_EQ(boxes.size(), 1ull);
3694  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
3695  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3696  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.433594);
3697  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3698 
3699  paint.setColor(SK_ColorBLUE);
3700  boxes =
3701  paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style);
3702  for (size_t i = 0; i < boxes.size(); ++i) {
3703  GetCanvas()->drawRect(boxes[i].rect, paint);
3704  }
3705  EXPECT_EQ(boxes.size(), 1ull);
3706  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.433594);
3707  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3708  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.01953);
3709  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3710 
3711  paint.setColor(SK_ColorGREEN);
3712  boxes =
3713  paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style);
3714  for (size_t i = 0; i < boxes.size(); ++i) {
3715  GetCanvas()->drawRect(boxes[i].rect, paint);
3716  }
3717  EXPECT_EQ(boxes.size(), 1ull);
3718  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.01953);
3719  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3720  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.09375);
3721  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3722 
3723  paint.setColor(SK_ColorRED);
3724  boxes =
3725  paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style);
3726  for (size_t i = 0; i < boxes.size(); ++i) {
3727  GetCanvas()->drawRect(boxes[i].rect, paint);
3728  }
3729  EXPECT_EQ(boxes.size(), 8ull);
3730  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.01953);
3731  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 96.946617);
3732  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.72266);
3733  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 176.94661);
3734 
3735  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.72266);
3736  EXPECT_FLOAT_EQ(boxes[1].rect.top(), 96.946617);
3737  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.05859);
3738  EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 176.94661);
3739 
3740  EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0);
3741  EXPECT_FLOAT_EQ(boxes[2].rect.top(), 176.94661);
3742  EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.60547);
3743  EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 256.94662);
3744 
3745  EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.60547);
3746  EXPECT_FLOAT_EQ(boxes[3].rect.top(), 176.94661);
3747  EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.05859);
3748  EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 256.94662);
3749 
3750  EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0);
3751  EXPECT_FLOAT_EQ(boxes[4].rect.top(), 256.94662);
3752  EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.05859);
3753  EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 336.94662);
3754 
3755  EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0);
3756  EXPECT_FLOAT_EQ(boxes[5].rect.top(), 336.94662);
3757  EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.05859);
3758  EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 416.94662);
3759 
3760  paint.setColor(SK_ColorBLUE);
3761  boxes =
3762  paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style);
3763  for (size_t i = 0; i < boxes.size(); ++i) {
3764  GetCanvas()->drawRect(boxes[i].rect, paint);
3765  }
3766  EXPECT_EQ(boxes.size(), 1ull);
3767  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.75781);
3768  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615);
3769  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.26172);
3770  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609);
3771 
3772  paint.setColor(SK_ColorRED);
3773  boxes =
3774  paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3775  for (size_t i = 0; i < boxes.size(); ++i) {
3776  GetCanvas()->drawRect(boxes[i].rect, paint);
3777  }
3778  EXPECT_EQ(boxes.size(), 0ull);
3779 
3780  ASSERT_TRUE(Snapshot());
3781 }
3782 
3783 TEST_F(ParagraphTest, GetRectsForRangeIncludeCombiningCharacter) {
3784  const char* text = "ดีสวัสดีชาวโลกที่น่ารัก";
3785  auto icu_text = icu::UnicodeString::fromUTF8(text);
3786  std::u16string u16_text(icu_text.getBuffer(),
3787  icu_text.getBuffer() + icu_text.length());
3788 
3789  txt::ParagraphStyle paragraph_style;
3790  paragraph_style.max_lines = 10;
3791  paragraph_style.text_align = TextAlign::left;
3792  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3793 
3794  txt::TextStyle text_style;
3795  text_style.font_families = std::vector<std::string>(1, "Roboto");
3796  text_style.font_size = 50;
3797  text_style.letter_spacing = 1;
3798  text_style.word_spacing = 5;
3799  text_style.color = SK_ColorBLACK;
3800  text_style.height = 1;
3801  builder.PushStyle(text_style);
3802 
3803  builder.AddText(u16_text);
3804 
3805  builder.Pop();
3806 
3807  auto paragraph = BuildParagraph(builder);
3808  paragraph->Layout(GetTestCanvasWidth() - 100);
3809 
3810  paragraph->Paint(GetCanvas(), 0, 0);
3811 
3812  Paragraph::RectHeightStyle rect_height_style =
3814  Paragraph::RectWidthStyle rect_width_style =
3816 
3817  std::vector<txt::Paragraph::TextBox> boxes =
3818  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3819  EXPECT_EQ(boxes.size(), 0ull);
3820 
3821  // Case when the sentence starts with a combining character
3822  // We should get 0 box for ด because it's already been combined to ดี
3823  boxes =
3824  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3825  EXPECT_EQ(boxes.size(), 0ull);
3826 
3827  boxes =
3828  paragraph->GetRectsForRange(1, 2, rect_height_style, rect_width_style);
3829  EXPECT_EQ(boxes.size(), 1ull);
3830 
3831  boxes =
3832  paragraph->GetRectsForRange(0, 2, rect_height_style, rect_width_style);
3833  EXPECT_EQ(boxes.size(), 1ull);
3834 
3835  // Case when the sentence contains a combining character
3836  // We should get 0 box for ว because it's already been combined to วั
3837  boxes =
3838  paragraph->GetRectsForRange(3, 4, rect_height_style, rect_width_style);
3839  EXPECT_EQ(boxes.size(), 0ull);
3840 
3841  boxes =
3842  paragraph->GetRectsForRange(4, 5, rect_height_style, rect_width_style);
3843  EXPECT_EQ(boxes.size(), 1ull);
3844 
3845  boxes =
3846  paragraph->GetRectsForRange(3, 5, rect_height_style, rect_width_style);
3847  EXPECT_EQ(boxes.size(), 1ull);
3848 
3849  // Case when the sentence contains a combining character that contain 3
3850  // characters We should get 0 box for ท and ที because it's already been
3851  // combined to ที่
3852  boxes =
3853  paragraph->GetRectsForRange(14, 15, rect_height_style, rect_width_style);
3854  EXPECT_EQ(boxes.size(), 0ull);
3855 
3856  boxes =
3857  paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
3858  EXPECT_EQ(boxes.size(), 0ull);
3859 
3860  boxes =
3861  paragraph->GetRectsForRange(16, 17, rect_height_style, rect_width_style);
3862  EXPECT_EQ(boxes.size(), 1ull);
3863 
3864  boxes =
3865  paragraph->GetRectsForRange(14, 17, rect_height_style, rect_width_style);
3866  EXPECT_EQ(boxes.size(), 1ull);
3867 }
3868 
3869 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraph)) {
3870  const char* text = "01234   "; // includes ideographic space
3871  // and english space.
3872  auto icu_text = icu::UnicodeString::fromUTF8(text);
3873  std::u16string u16_text(icu_text.getBuffer(),
3874  icu_text.getBuffer() + icu_text.length());
3875 
3876  txt::ParagraphStyle paragraph_style;
3877  paragraph_style.max_lines = 10;
3878  paragraph_style.text_align = TextAlign::center;
3879  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3880 
3881  txt::TextStyle text_style;
3882  text_style.font_families = std::vector<std::string>(1, "Roboto");
3883  text_style.font_size = 50;
3884  text_style.letter_spacing = 0;
3885  text_style.font_weight = FontWeight::w500;
3886  text_style.word_spacing = 0;
3887  text_style.color = SK_ColorBLACK;
3888  text_style.height = 1;
3889  builder.PushStyle(text_style);
3890 
3891  builder.AddText(u16_text);
3892 
3893  builder.Pop();
3894 
3895  auto paragraph = BuildParagraph(builder);
3896  paragraph->Layout(550);
3897 
3898  paragraph->Paint(GetCanvas(), 0, 0);
3899 
3900  SkPaint paint;
3901  paint.setStyle(SkPaint::kStroke_Style);
3902  paint.setAntiAlias(true);
3903  paint.setStrokeWidth(1);
3904 
3905  // Tests for GetRectsForRange()
3906  Paragraph::RectHeightStyle rect_height_style =
3908  Paragraph::RectWidthStyle rect_width_style =
3910  paint.setColor(SK_ColorRED);
3911  std::vector<txt::Paragraph::TextBox> boxes =
3912  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
3913  for (size_t i = 0; i < boxes.size(); ++i) {
3914  GetCanvas()->drawRect(boxes[i].rect, paint);
3915  }
3916  EXPECT_EQ(boxes.size(), 0ull);
3917 
3918  boxes =
3919  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
3920  for (size_t i = 0; i < boxes.size(); ++i) {
3921  GetCanvas()->drawRect(boxes[i].rect, paint);
3922  }
3923  EXPECT_EQ(boxes.size(), 1ull);
3924  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
3925  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3926  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
3927  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3928 
3929  paint.setColor(SK_ColorBLUE);
3930  boxes =
3931  paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style);
3932  for (size_t i = 0; i < boxes.size(); ++i) {
3933  GetCanvas()->drawRect(boxes[i].rect, paint);
3934  }
3935  EXPECT_EQ(boxes.size(), 1ull);
3936  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102);
3937  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3938  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695);
3939  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3940 
3941  paint.setColor(SK_ColorGREEN);
3942  boxes =
3943  paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style);
3944  for (size_t i = 0; i < boxes.size(); ++i) {
3945  GetCanvas()->drawRect(boxes[i].rect, paint);
3946  }
3947  EXPECT_EQ(boxes.size(), 2ull);
3948  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695);
3949  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3950  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
3951  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3952 
3953  paint.setColor(SK_ColorBLACK);
3954  boxes =
3955  paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
3956  for (size_t i = 0; i < boxes.size(); ++i) {
3957  GetCanvas()->drawRect(boxes[i].rect, paint);
3958  }
3959  EXPECT_EQ(boxes.size(), 1ull);
3960  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492);
3961  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
3962  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 358.49805);
3963  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
3964 
3965  paint.setColor(SK_ColorRED);
3966  boxes =
3967  paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
3968  for (size_t i = 0; i < boxes.size(); ++i) {
3969  GetCanvas()->drawRect(boxes[i].rect, paint);
3970  }
3971  EXPECT_EQ(boxes.size(), 0ull);
3972 
3973  ASSERT_TRUE(Snapshot());
3974 }
3975 
3976 TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineLeftAlign)) {
3977  const char* text = "01234\n\nعab\naعلی\n";
3978  auto icu_text = icu::UnicodeString::fromUTF8(text);
3979  std::u16string u16_text(icu_text.getBuffer(),
3980  icu_text.getBuffer() + icu_text.length());
3981 
3982  txt::ParagraphStyle paragraph_style;
3983  paragraph_style.font_family = "Roboto";
3984  paragraph_style.max_lines = 10;
3985  paragraph_style.text_direction = TextDirection::ltr;
3986  paragraph_style.text_align = TextAlign::left;
3987  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
3988 
3989  txt::TextStyle text_style;
3990  text_style.font_families = {"Roboto", "Noto Naskh Arabic"};
3991  text_style.font_size = 50;
3992  text_style.letter_spacing = 0;
3993  text_style.font_weight = FontWeight::w500;
3994  text_style.word_spacing = 0;
3995  text_style.color = SK_ColorBLACK;
3996  text_style.height = 1;
3997  builder.PushStyle(text_style);
3998 
3999  builder.AddText(u16_text);
4000 
4001  builder.Pop();
4002 
4003  auto paragraph = BuildParagraph(builder);
4004  paragraph->Layout(550);
4005 
4006  paragraph->Paint(GetCanvas(), 0, 0);
4007 
4008  SkPaint paint;
4009  paint.setStyle(SkPaint::kStroke_Style);
4010  paint.setAntiAlias(true);
4011  paint.setStrokeWidth(1);
4012 
4013  // Tests for GetRectsForRange()
4014  Paragraph::RectHeightStyle rect_height_style =
4016  Paragraph::RectWidthStyle rect_width_style =
4018  paint.setColor(SK_ColorRED);
4019  std::vector<txt::Paragraph::TextBox> boxes =
4020  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4021  for (size_t i = 0; i < boxes.size(); ++i) {
4022  GetCanvas()->drawRect(boxes[i].rect, paint);
4023  }
4024  EXPECT_EQ(boxes.size(), 0ull);
4025 
4026  boxes =
4027  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4028  for (size_t i = 0; i < boxes.size(); ++i) {
4029  GetCanvas()->drawRect(boxes[i].rect, paint);
4030  }
4031  EXPECT_EQ(boxes.size(), 1ull);
4032  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4033  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4034  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 28.417969);
4035  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4036 
4037  paint.setColor(SK_ColorGREEN);
4038  boxes =
4039  paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style);
4040  for (size_t i = 0; i < boxes.size(); ++i) {
4041  GetCanvas()->drawRect(boxes[i].rect, paint);
4042  }
4043  EXPECT_EQ(boxes.size(), 1ull);
4044  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4045  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 0);
4046  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(),
4047  75); // TODO(garyq): This value can be improved... Should be
4048  // taller, but we need a good way to obtain a height
4049  // without any glyphs on the line.
4050 
4051  boxes =
4052  paragraph->GetRectsForRange(10, 11, rect_height_style, rect_width_style);
4053  for (size_t i = 0; i < boxes.size(); ++i) {
4054  GetCanvas()->drawRect(boxes[i].rect, paint);
4055  }
4056  EXPECT_EQ(boxes.size(), 1ull);
4057  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 85);
4058  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 85);
4059  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
4060 
4061  boxes =
4062  paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
4063  for (size_t i = 0; i < boxes.size(); ++i) {
4064  GetCanvas()->drawRect(boxes[i].rect, paint);
4065  }
4066  EXPECT_EQ(boxes.size(), 1ull);
4067  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 27);
4068  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 27);
4069  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245);
4070 
4071  ASSERT_TRUE(Snapshot());
4072 }
4073 
4074 TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineRightAlign)) {
4075  const char* text = "01234\n\nعab\naعلی\n";
4076  auto icu_text = icu::UnicodeString::fromUTF8(text);
4077  std::u16string u16_text(icu_text.getBuffer(),
4078  icu_text.getBuffer() + icu_text.length());
4079 
4080  txt::ParagraphStyle paragraph_style;
4081  paragraph_style.font_family = "Roboto";
4082  paragraph_style.max_lines = 10;
4083  paragraph_style.text_direction = TextDirection::ltr;
4084  paragraph_style.text_align = TextAlign::right;
4085  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4086 
4087  txt::TextStyle text_style;
4088  text_style.font_families = {"Roboto", "Noto Naskh Arabic"};
4089  text_style.font_size = 50;
4090  text_style.letter_spacing = 0;
4091  text_style.font_weight = FontWeight::w500;
4092  text_style.word_spacing = 0;
4093  text_style.color = SK_ColorBLACK;
4094  text_style.height = 1;
4095  builder.PushStyle(text_style);
4096 
4097  builder.AddText(u16_text);
4098 
4099  builder.Pop();
4100 
4101  auto paragraph = BuildParagraph(builder);
4102  paragraph->Layout(550);
4103 
4104  paragraph->Paint(GetCanvas(), 0, 0);
4105 
4106  SkPaint paint;
4107  paint.setStyle(SkPaint::kStroke_Style);
4108  paint.setAntiAlias(true);
4109  paint.setStrokeWidth(1);
4110 
4111  // Tests for GetRectsForRange()
4112  Paragraph::RectHeightStyle rect_height_style =
4114  Paragraph::RectWidthStyle rect_width_style =
4116  paint.setColor(SK_ColorRED);
4117  std::vector<txt::Paragraph::TextBox> boxes =
4118  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4119  for (size_t i = 0; i < boxes.size(); ++i) {
4120  GetCanvas()->drawRect(boxes[i].rect, paint);
4121  }
4122  EXPECT_EQ(boxes.size(), 0ull);
4123 
4124  boxes =
4125  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4126  for (size_t i = 0; i < boxes.size(); ++i) {
4127  GetCanvas()->drawRect(boxes[i].rect, paint);
4128  }
4129  EXPECT_EQ(boxes.size(), 1ull);
4130  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 407.91016);
4131  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4132  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 436.32812);
4133  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4134 
4135  paint.setColor(SK_ColorGREEN);
4136  boxes =
4137  paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style);
4138  for (size_t i = 0; i < boxes.size(); ++i) {
4139  GetCanvas()->drawRect(boxes[i].rect, paint);
4140  }
4141  EXPECT_EQ(boxes.size(), 1ull);
4142  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 550);
4143  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550);
4144  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(),
4145  75); // TODO(garyq): This value can be improved... Should be
4146  // taller, but we need a good way to obtain a height
4147  // without any glyphs on the line.
4148 
4149  boxes =
4150  paragraph->GetRectsForRange(10, 11, rect_height_style, rect_width_style);
4151  for (size_t i = 0; i < boxes.size(); ++i) {
4152  GetCanvas()->drawRect(boxes[i].rect, paint);
4153  }
4154  EXPECT_EQ(boxes.size(), 1ull);
4155  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 550);
4156  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550);
4157  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
4158 
4159  boxes =
4160  paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
4161  for (size_t i = 0; i < boxes.size(); ++i) {
4162  GetCanvas()->drawRect(boxes[i].rect, paint);
4163  }
4164  EXPECT_EQ(boxes.size(), 1ull);
4165  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 478);
4166  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 478);
4167  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245);
4168 
4169  ASSERT_TRUE(Snapshot());
4170 }
4171 
4173  LINUX_ONLY(GetRectsForRangeCenterParagraphNewlineCentered)) {
4174  const char* text = "01234\n\nعab\naعلی\n";
4175  auto icu_text = icu::UnicodeString::fromUTF8(text);
4176  std::u16string u16_text(icu_text.getBuffer(),
4177  icu_text.getBuffer() + icu_text.length());
4178 
4179  txt::ParagraphStyle paragraph_style;
4180  paragraph_style.font_family = "Roboto";
4181  paragraph_style.max_lines = 10;
4182  paragraph_style.text_direction = TextDirection::ltr;
4183  paragraph_style.text_align = TextAlign::center;
4184  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4185 
4186  txt::TextStyle text_style;
4187  text_style.font_families = {"Roboto", "Noto Naskh Arabic"};
4188  text_style.font_size = 50;
4189  text_style.letter_spacing = 0;
4190  text_style.font_weight = FontWeight::w500;
4191  text_style.word_spacing = 0;
4192  text_style.color = SK_ColorBLACK;
4193  text_style.height = 1;
4194  builder.PushStyle(text_style);
4195 
4196  builder.AddText(u16_text);
4197 
4198  builder.Pop();
4199 
4200  auto paragraph = BuildParagraph(builder);
4201  paragraph->Layout(550);
4202 
4203  paragraph->Paint(GetCanvas(), 0, 0);
4204 
4205  SkPaint paint;
4206  paint.setStyle(SkPaint::kStroke_Style);
4207  paint.setAntiAlias(true);
4208  paint.setStrokeWidth(1);
4209 
4210  // Tests for GetRectsForRange()
4211  Paragraph::RectHeightStyle rect_height_style =
4213  Paragraph::RectWidthStyle rect_width_style =
4215  paint.setColor(SK_ColorRED);
4216  std::vector<txt::Paragraph::TextBox> boxes =
4217  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4218  for (size_t i = 0; i < boxes.size(); ++i) {
4219  GetCanvas()->drawRect(boxes[i].rect, paint);
4220  }
4221  EXPECT_EQ(boxes.size(), 0ull);
4222 
4223  boxes =
4224  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4225  for (size_t i = 0; i < boxes.size(); ++i) {
4226  GetCanvas()->drawRect(boxes[i].rect, paint);
4227  }
4228  EXPECT_EQ(boxes.size(), 1ull);
4229  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
4230  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4231  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
4232  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4233 
4234  paint.setColor(SK_ColorGREEN);
4235  boxes =
4236  paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style);
4237  for (size_t i = 0; i < boxes.size(); ++i) {
4238  GetCanvas()->drawRect(boxes[i].rect, paint);
4239  }
4240  EXPECT_EQ(boxes.size(), 1ull);
4241  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 275);
4242  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275);
4243  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(),
4244  75); // TODO(garyq): This value can be improved... Should be
4245  // taller, but we need a good way to obtain a height
4246  // without any glyphs on the line.
4247 
4248  boxes =
4249  paragraph->GetRectsForRange(10, 11, rect_height_style, rect_width_style);
4250  for (size_t i = 0; i < boxes.size(); ++i) {
4251  GetCanvas()->drawRect(boxes[i].rect, paint);
4252  }
4253  EXPECT_EQ(boxes.size(), 1ull);
4254  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317);
4255  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317);
4256  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
4257 
4258  boxes =
4259  paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
4260  for (size_t i = 0; i < boxes.size(); ++i) {
4261  GetCanvas()->drawRect(boxes[i].rect, paint);
4262  }
4263  EXPECT_EQ(boxes.size(), 1ull);
4264  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 252);
4265  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 252);
4266  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245);
4267 
4268  ASSERT_TRUE(Snapshot());
4269 }
4270 
4272  LINUX_ONLY(GetRectsForRangeParagraphNewlineRTLLeftAlign)) {
4273  const char* text = "01234\n\nعab\naعلی\n";
4274  auto icu_text = icu::UnicodeString::fromUTF8(text);
4275  std::u16string u16_text(icu_text.getBuffer(),
4276  icu_text.getBuffer() + icu_text.length());
4277 
4278  txt::ParagraphStyle paragraph_style;
4279  paragraph_style.font_family = "Roboto";
4280  paragraph_style.max_lines = 10;
4281  paragraph_style.text_direction = TextDirection::rtl;
4282  paragraph_style.text_align = TextAlign::left;
4283  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4284 
4285  txt::TextStyle text_style;
4286  text_style.font_families = {"Roboto", "Noto Naskh Arabic"};
4287  text_style.font_size = 50;
4288  text_style.letter_spacing = 0;
4289  text_style.font_weight = FontWeight::w500;
4290  text_style.word_spacing = 0;
4291  text_style.color = SK_ColorBLACK;
4292  text_style.height = 1;
4293  builder.PushStyle(text_style);
4294 
4295  builder.AddText(u16_text);
4296 
4297  builder.Pop();
4298 
4299  auto paragraph = BuildParagraph(builder);
4300  paragraph->Layout(550);
4301 
4302  paragraph->Paint(GetCanvas(), 0, 0);
4303 
4304  SkPaint paint;
4305  paint.setStyle(SkPaint::kStroke_Style);
4306  paint.setAntiAlias(true);
4307  paint.setStrokeWidth(1);
4308 
4309  // Tests for GetRectsForRange()
4310  Paragraph::RectHeightStyle rect_height_style =
4312  Paragraph::RectWidthStyle rect_width_style =
4314  paint.setColor(SK_ColorRED);
4315  std::vector<txt::Paragraph::TextBox> boxes =
4316  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4317  for (size_t i = 0; i < boxes.size(); ++i) {
4318  GetCanvas()->drawRect(boxes[i].rect, paint);
4319  }
4320  EXPECT_EQ(boxes.size(), 0ull);
4321 
4322  boxes =
4323  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4324  for (size_t i = 0; i < boxes.size(); ++i) {
4325  GetCanvas()->drawRect(boxes[i].rect, paint);
4326  }
4327  EXPECT_EQ(boxes.size(), 1ull);
4328  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4329  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4330  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 28.417969);
4331  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4332 
4333  paint.setColor(SK_ColorGREEN);
4334  boxes =
4335  paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style);
4336  for (size_t i = 0; i < boxes.size(); ++i) {
4337  GetCanvas()->drawRect(boxes[i].rect, paint);
4338  }
4339  EXPECT_EQ(boxes.size(), 1ull);
4340  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4341  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 0);
4342  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(),
4343  75); // TODO(garyq): This value can be improved... Should be
4344  // taller, but we need a good way to obtain a height
4345  // without any glyphs on the line.
4346 
4347  boxes =
4348  paragraph->GetRectsForRange(10, 11, rect_height_style, rect_width_style);
4349  for (size_t i = 0; i < boxes.size(); ++i) {
4350  GetCanvas()->drawRect(boxes[i].rect, paint);
4351  }
4352  EXPECT_EQ(boxes.size(), 1ull);
4353  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 55);
4354  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 55);
4355  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
4356 
4357  boxes =
4358  paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
4359  for (size_t i = 0; i < boxes.size(); ++i) {
4360  GetCanvas()->drawRect(boxes[i].rect, paint);
4361  }
4362  EXPECT_EQ(boxes.size(), 1ull);
4363  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
4364  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 0);
4365  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245);
4366 
4367  ASSERT_TRUE(Snapshot());
4368 }
4369 
4371  LINUX_ONLY(GetRectsForRangeParagraphNewlineRTLRightAlign)) {
4372  const char* text = "01234\n\nعab\naعلی\n";
4373  auto icu_text = icu::UnicodeString::fromUTF8(text);
4374  std::u16string u16_text(icu_text.getBuffer(),
4375  icu_text.getBuffer() + icu_text.length());
4376 
4377  txt::ParagraphStyle paragraph_style;
4378  paragraph_style.font_family = "Roboto";
4379  paragraph_style.max_lines = 10;
4380  paragraph_style.text_direction = TextDirection::rtl;
4381  paragraph_style.text_align = TextAlign::right;
4382  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4383 
4384  txt::TextStyle text_style;
4385  text_style.font_families = {"Roboto", "Noto Naskh Arabic"};
4386  text_style.font_size = 50;
4387  text_style.letter_spacing = 0;
4388  text_style.font_weight = FontWeight::w500;
4389  text_style.word_spacing = 0;
4390  text_style.color = SK_ColorBLACK;
4391  text_style.height = 1;
4392  builder.PushStyle(text_style);
4393 
4394  builder.AddText(u16_text);
4395 
4396  builder.Pop();
4397 
4398  auto paragraph = BuildParagraph(builder);
4399  paragraph->Layout(550);
4400 
4401  paragraph->Paint(GetCanvas(), 0, 0);
4402 
4403  SkPaint paint;
4404  paint.setStyle(SkPaint::kStroke_Style);
4405  paint.setAntiAlias(true);
4406  paint.setStrokeWidth(1);
4407 
4408  // Tests for GetRectsForRange()
4409  Paragraph::RectHeightStyle rect_height_style =
4411  Paragraph::RectWidthStyle rect_width_style =
4413  paint.setColor(SK_ColorRED);
4414  std::vector<txt::Paragraph::TextBox> boxes =
4415  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4416  for (size_t i = 0; i < boxes.size(); ++i) {
4417  GetCanvas()->drawRect(boxes[i].rect, paint);
4418  }
4419  EXPECT_EQ(boxes.size(), 0ull);
4420 
4421  boxes =
4422  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4423  for (size_t i = 0; i < boxes.size(); ++i) {
4424  GetCanvas()->drawRect(boxes[i].rect, paint);
4425  }
4426  EXPECT_EQ(boxes.size(), 1ull);
4427  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 407.91016);
4428  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4429  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 436.32812);
4430  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4431 
4432  paint.setColor(SK_ColorGREEN);
4433  boxes =
4434  paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style);
4435  for (size_t i = 0; i < boxes.size(); ++i) {
4436  GetCanvas()->drawRect(boxes[i].rect, paint);
4437  }
4438  EXPECT_EQ(boxes.size(), 1ull);
4439  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 550);
4440  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550);
4441  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(),
4442  75); // TODO(garyq): This value can be improved... Should be
4443  // taller, but we need a good way to obtain a height
4444  // without any glyphs on the line.
4445 
4446  boxes =
4447  paragraph->GetRectsForRange(10, 11, rect_height_style, rect_width_style);
4448  for (size_t i = 0; i < boxes.size(); ++i) {
4449  GetCanvas()->drawRect(boxes[i].rect, paint);
4450  }
4451  EXPECT_EQ(boxes.size(), 1ull);
4452  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 519);
4453  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519);
4454  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
4455 
4456  boxes =
4457  paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
4458  for (size_t i = 0; i < boxes.size(); ++i) {
4459  GetCanvas()->drawRect(boxes[i].rect, paint);
4460  }
4461  EXPECT_EQ(boxes.size(), 1ull);
4462  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 451);
4463  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 451);
4464  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245);
4465 
4466  ASSERT_TRUE(Snapshot());
4467 }
4468 
4470  LINUX_ONLY(GetRectsForRangeCenterParagraphNewlineRTLCentered)) {
4471  const char* text = "01234\n\nعab\naعلی\n";
4472  auto icu_text = icu::UnicodeString::fromUTF8(text);
4473  std::u16string u16_text(icu_text.getBuffer(),
4474  icu_text.getBuffer() + icu_text.length());
4475 
4476  txt::ParagraphStyle paragraph_style;
4477  paragraph_style.font_family = "Roboto";
4478  paragraph_style.max_lines = 10;
4479  paragraph_style.text_direction = TextDirection::rtl;
4480  paragraph_style.text_align = TextAlign::center;
4481  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4482 
4483  txt::TextStyle text_style;
4484  text_style.font_families = {"Roboto", "Noto Naskh Arabic"};
4485  text_style.font_size = 50;
4486  text_style.letter_spacing = 0;
4487  text_style.font_weight = FontWeight::w500;
4488  text_style.word_spacing = 0;
4489  text_style.color = SK_ColorBLACK;
4490  text_style.height = 1;
4491  builder.PushStyle(text_style);
4492 
4493  builder.AddText(u16_text);
4494 
4495  builder.Pop();
4496 
4497  auto paragraph = BuildParagraph(builder);
4498  paragraph->Layout(550);
4499 
4500  paragraph->Paint(GetCanvas(), 0, 0);
4501 
4502  SkPaint paint;
4503  paint.setStyle(SkPaint::kStroke_Style);
4504  paint.setAntiAlias(true);
4505  paint.setStrokeWidth(1);
4506 
4507  // Tests for GetRectsForRange()
4508  Paragraph::RectHeightStyle rect_height_style =
4510  Paragraph::RectWidthStyle rect_width_style =
4512  paint.setColor(SK_ColorRED);
4513  std::vector<txt::Paragraph::TextBox> boxes =
4514  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4515  for (size_t i = 0; i < boxes.size(); ++i) {
4516  GetCanvas()->drawRect(boxes[i].rect, paint);
4517  }
4518  EXPECT_EQ(boxes.size(), 0ull);
4519 
4520  boxes =
4521  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4522  for (size_t i = 0; i < boxes.size(); ++i) {
4523  GetCanvas()->drawRect(boxes[i].rect, paint);
4524  }
4525  EXPECT_EQ(boxes.size(), 1ull);
4526  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
4527  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4528  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
4529  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4530 
4531  paint.setColor(SK_ColorGREEN);
4532  boxes =
4533  paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style);
4534  for (size_t i = 0; i < boxes.size(); ++i) {
4535  GetCanvas()->drawRect(boxes[i].rect, paint);
4536  }
4537  EXPECT_EQ(boxes.size(), 1ull);
4538  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 275);
4539  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275);
4540  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(),
4541  75); // TODO(garyq): This value can be improved... Should be
4542  // taller, but we need a good way to obtain a height
4543  // without any glyphs on the line.
4544 
4545  boxes =
4546  paragraph->GetRectsForRange(10, 11, rect_height_style, rect_width_style);
4547  for (size_t i = 0; i < boxes.size(); ++i) {
4548  GetCanvas()->drawRect(boxes[i].rect, paint);
4549  }
4550  EXPECT_EQ(boxes.size(), 1ull);
4551  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 287);
4552  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 287);
4553  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160);
4554 
4555  boxes =
4556  paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
4557  for (size_t i = 0; i < boxes.size(); ++i) {
4558  GetCanvas()->drawRect(boxes[i].rect, paint);
4559  }
4560  EXPECT_EQ(boxes.size(), 1ull);
4561  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 225);
4562  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 225);
4563  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245);
4564 
4565  ASSERT_TRUE(Snapshot());
4566 }
4567 
4569  DISABLE_ON_WINDOWS(GetRectsForRangeCenterMultiLineParagraph)) {
4570  const char* text = "01234   \n0123  "; // includes ideographic
4571  // space and english space.
4572  auto icu_text = icu::UnicodeString::fromUTF8(text);
4573  std::u16string u16_text(icu_text.getBuffer(),
4574  icu_text.getBuffer() + icu_text.length());
4575 
4576  txt::ParagraphStyle paragraph_style;
4577  paragraph_style.max_lines = 10;
4578  paragraph_style.text_align = TextAlign::center;
4579  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4580 
4581  txt::TextStyle text_style;
4582  text_style.font_families = std::vector<std::string>(1, "Roboto");
4583  text_style.font_size = 50;
4584  text_style.letter_spacing = 0;
4585  text_style.font_weight = FontWeight::w500;
4586  text_style.word_spacing = 0;
4587  text_style.color = SK_ColorBLACK;
4588  text_style.height = 1;
4589  builder.PushStyle(text_style);
4590 
4591  builder.AddText(u16_text);
4592 
4593  builder.Pop();
4594 
4595  auto paragraph = BuildParagraph(builder);
4596  paragraph->Layout(550);
4597 
4598  paragraph->Paint(GetCanvas(), 0, 0);
4599 
4600  SkPaint paint;
4601  paint.setStyle(SkPaint::kStroke_Style);
4602  paint.setAntiAlias(true);
4603  paint.setStrokeWidth(1);
4604 
4605  // Tests for GetRectsForRange()
4606  Paragraph::RectHeightStyle rect_height_style =
4608  Paragraph::RectWidthStyle rect_width_style =
4610  paint.setColor(SK_ColorRED);
4611  std::vector<txt::Paragraph::TextBox> boxes =
4612  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
4613  for (size_t i = 0; i < boxes.size(); ++i) {
4614  GetCanvas()->drawRect(boxes[i].rect, paint);
4615  }
4616  EXPECT_EQ(boxes.size(), 0ull);
4617 
4618  boxes =
4619  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
4620  for (size_t i = 0; i < boxes.size(); ++i) {
4621  GetCanvas()->drawRect(boxes[i].rect, paint);
4622  }
4623  EXPECT_EQ(boxes.size(), 1ull);
4624  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
4625  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4626  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
4627  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4628 
4629  paint.setColor(SK_ColorBLUE);
4630  boxes =
4631  paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style);
4632  for (size_t i = 0; i < boxes.size(); ++i) {
4633  GetCanvas()->drawRect(boxes[i].rect, paint);
4634  }
4635  EXPECT_EQ(boxes.size(), 1ull);
4636  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102);
4637  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4638  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695);
4639  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4640 
4641  paint.setColor(SK_ColorGREEN);
4642  boxes =
4643  paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style);
4644  for (size_t i = 0; i < boxes.size(); ++i) {
4645  GetCanvas()->drawRect(boxes[i].rect, paint);
4646  }
4647  EXPECT_EQ(boxes.size(), 2ull);
4648  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695);
4649  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4650  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
4651  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4652 
4653  paint.setColor(SK_ColorBLACK);
4654  boxes =
4655  paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
4656  for (size_t i = 0; i < boxes.size(); ++i) {
4657  GetCanvas()->drawRect(boxes[i].rect, paint);
4658  }
4659  EXPECT_EQ(boxes.size(), 1ull);
4660  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492);
4661  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
4662  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 358.49805);
4663  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
4664 
4665  paint.setColor(SK_ColorBLACK);
4666  boxes =
4667  paragraph->GetRectsForRange(10, 12, rect_height_style, rect_width_style);
4668  for (size_t i = 0; i < boxes.size(); ++i) {
4669  GetCanvas()->drawRect(boxes[i].rect, paint);
4670  }
4671  EXPECT_EQ(boxes.size(), 1ull);
4672  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 218.16406);
4673  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
4674  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275);
4675  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
4676 
4677  paint.setColor(SK_ColorBLACK);
4678  boxes =
4679  paragraph->GetRectsForRange(14, 18, rect_height_style, rect_width_style);
4680  for (size_t i = 0; i < boxes.size(); ++i) {
4681  GetCanvas()->drawRect(boxes[i].rect, paint);
4682  }
4683  EXPECT_EQ(boxes.size(), 1ull);
4684  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 331.83594);
4685  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
4686  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 419.19531);
4687  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
4688 
4689  paint.setColor(SK_ColorRED);
4690  boxes =
4691  paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
4692  for (size_t i = 0; i < boxes.size(); ++i) {
4693  GetCanvas()->drawRect(boxes[i].rect, paint);
4694  }
4695  EXPECT_EQ(boxes.size(), 0ull);
4696 
4697  ASSERT_TRUE(Snapshot());
4698 }
4699 
4700 TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeStrut)) {
4701  const char* text = "Chinese 字典";
4702 
4703  auto icu_text = icu::UnicodeString::fromUTF8(text);
4704  std::u16string u16_text(icu_text.getBuffer(),
4705  icu_text.getBuffer() + icu_text.length());
4706 
4707  txt::ParagraphStyle paragraph_style;
4708  paragraph_style.strut_enabled = true;
4709  paragraph_style.strut_font_families.push_back("Roboto");
4710  paragraph_style.strut_font_size = 14;
4711  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4712 
4713  txt::TextStyle text_style;
4714  text_style.font_families.push_back("Noto Sans CJK JP");
4715  text_style.font_size = 20;
4716  text_style.color = SK_ColorBLACK;
4717  builder.PushStyle(text_style);
4718 
4719  builder.AddText(u16_text);
4720 
4721  builder.Pop();
4722 
4723  auto paragraph = BuildParagraph(builder);
4724  paragraph->Layout(550);
4725 
4726  paragraph->Paint(GetCanvas(), 0, 0);
4727 
4728  SkPaint paint;
4729  paint.setStyle(SkPaint::kStroke_Style);
4730  paint.setAntiAlias(true);
4731  paint.setStrokeWidth(1);
4732 
4733  std::vector<txt::Paragraph::TextBox> strut_boxes =
4734  paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kStrut,
4736  ASSERT_EQ(strut_boxes.size(), 1ull);
4737  const SkRect& strut_rect = strut_boxes.front().rect;
4738  paint.setColor(SK_ColorRED);
4739  GetCanvas()->drawRect(strut_rect, paint);
4740 
4741  std::vector<txt::Paragraph::TextBox> tight_boxes =
4742  paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kTight,
4744  ASSERT_EQ(tight_boxes.size(), 1ull);
4745  const SkRect& tight_rect = tight_boxes.front().rect;
4746  paint.setColor(SK_ColorGREEN);
4747  GetCanvas()->drawRect(tight_rect, paint);
4748 
4749  EXPECT_FLOAT_EQ(strut_rect.left(), 0);
4750  EXPECT_FLOAT_EQ(strut_rect.top(), 10.611719);
4751  EXPECT_FLOAT_EQ(strut_rect.right(), 118.61719);
4752  EXPECT_FLOAT_EQ(strut_rect.bottom(), 27.017969);
4753 
4754  ASSERT_TRUE(tight_rect.contains(strut_rect));
4755 
4756  ASSERT_TRUE(Snapshot());
4757 }
4758 
4759 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeStrutFallback)) {
4760  const char* text = "Chinese 字典";
4761 
4762  auto icu_text = icu::UnicodeString::fromUTF8(text);
4763  std::u16string u16_text(icu_text.getBuffer(),
4764  icu_text.getBuffer() + icu_text.length());
4765 
4766  txt::ParagraphStyle paragraph_style;
4767  paragraph_style.strut_enabled = false;
4768  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4769 
4770  txt::TextStyle text_style;
4771  text_style.font_families.push_back("Noto Sans CJK JP");
4772  text_style.font_size = 20;
4773  builder.PushStyle(text_style);
4774 
4775  builder.AddText(u16_text);
4776 
4777  builder.Pop();
4778 
4779  auto paragraph = BuildParagraph(builder);
4780  paragraph->Layout(550);
4781 
4782  std::vector<txt::Paragraph::TextBox> strut_boxes =
4783  paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kStrut,
4785  std::vector<txt::Paragraph::TextBox> tight_boxes =
4786  paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kTight,
4788 
4789  ASSERT_EQ(strut_boxes.size(), 1ull);
4790  ASSERT_EQ(tight_boxes.size(), 1ull);
4791  ASSERT_EQ(strut_boxes.front().rect, tight_boxes.front().rect);
4792 }
4793 
4794 SkRect GetCoordinatesForGlyphPosition(txt::Paragraph& paragraph, size_t pos) {
4795  std::vector<txt::Paragraph::TextBox> boxes =
4796  paragraph.GetRectsForRange(pos, pos + 1, Paragraph::RectHeightStyle::kMax,
4798  return !boxes.empty() ? boxes.front().rect : SkRect::MakeEmpty();
4799 }
4800 
4801 TEST_F(ParagraphTest, GetWordBoundaryParagraph) {
4802  const char* text =
4803  "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
4804  "67890 12345";
4805  auto icu_text = icu::UnicodeString::fromUTF8(text);
4806  std::u16string u16_text(icu_text.getBuffer(),
4807  icu_text.getBuffer() + icu_text.length());
4808 
4809  txt::ParagraphStyle paragraph_style;
4810  paragraph_style.max_lines = 10;
4811  paragraph_style.text_align = TextAlign::left;
4812  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4813 
4814  txt::TextStyle text_style;
4815  text_style.font_families = std::vector<std::string>(1, "Roboto");
4816  text_style.font_size = 52;
4817  text_style.letter_spacing = 1.19039;
4818  text_style.word_spacing = 5;
4819  text_style.color = SK_ColorBLACK;
4820  text_style.height = 1.5;
4821  text_style.has_height_override = true;
4822  builder.PushStyle(text_style);
4823 
4824  builder.AddText(u16_text);
4825 
4826  builder.Pop();
4827 
4828  auto paragraph = BuildParagraph(builder);
4829  paragraph->Layout(550);
4830 
4831  paragraph->Paint(GetCanvas(), 0, 0);
4832 
4833  SkPaint paint;
4834  paint.setStyle(SkPaint::kStroke_Style);
4835  paint.setAntiAlias(true);
4836  paint.setStrokeWidth(1);
4837  paint.setColor(SK_ColorRED);
4838 
4839  SkRect rect = GetCoordinatesForGlyphPosition(*paragraph, 0);
4840  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4841 
4842  EXPECT_EQ(paragraph->GetWordBoundary(0), txt::Paragraph::Range<size_t>(0, 5));
4843  EXPECT_EQ(paragraph->GetWordBoundary(1), txt::Paragraph::Range<size_t>(0, 5));
4844  EXPECT_EQ(paragraph->GetWordBoundary(2), txt::Paragraph::Range<size_t>(0, 5));
4845  EXPECT_EQ(paragraph->GetWordBoundary(3), txt::Paragraph::Range<size_t>(0, 5));
4846  EXPECT_EQ(paragraph->GetWordBoundary(4), txt::Paragraph::Range<size_t>(0, 5));
4847  rect = GetCoordinatesForGlyphPosition(*paragraph, 5);
4848  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4849 
4850  EXPECT_EQ(paragraph->GetWordBoundary(5), txt::Paragraph::Range<size_t>(5, 7));
4851  rect = GetCoordinatesForGlyphPosition(*paragraph, 6);
4852  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4853 
4854  EXPECT_EQ(paragraph->GetWordBoundary(6), txt::Paragraph::Range<size_t>(5, 7));
4855  rect = GetCoordinatesForGlyphPosition(*paragraph, 7);
4856  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4857 
4858  EXPECT_EQ(paragraph->GetWordBoundary(7),
4860  EXPECT_EQ(paragraph->GetWordBoundary(8),
4862  EXPECT_EQ(paragraph->GetWordBoundary(9),
4864  EXPECT_EQ(paragraph->GetWordBoundary(10),
4866  EXPECT_EQ(paragraph->GetWordBoundary(11),
4868  rect = GetCoordinatesForGlyphPosition(*paragraph, 12);
4869  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4870 
4871  EXPECT_EQ(paragraph->GetWordBoundary(12),
4873  rect = GetCoordinatesForGlyphPosition(*paragraph, 13);
4874  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4875 
4876  EXPECT_EQ(paragraph->GetWordBoundary(13),
4878  rect = GetCoordinatesForGlyphPosition(*paragraph, 18);
4879  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4880 
4881  rect = GetCoordinatesForGlyphPosition(*paragraph, 19);
4882  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4883 
4884  rect = GetCoordinatesForGlyphPosition(*paragraph, 24);
4885  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4886 
4887  rect = GetCoordinatesForGlyphPosition(*paragraph, 25);
4888  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4889 
4890  rect = GetCoordinatesForGlyphPosition(*paragraph, 30);
4891  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4892 
4893  EXPECT_EQ(paragraph->GetWordBoundary(30),
4895  rect = GetCoordinatesForGlyphPosition(*paragraph, 31);
4896  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4897 
4898  rect = GetCoordinatesForGlyphPosition(*paragraph, icu_text.length() - 5);
4899  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4900 
4901  EXPECT_EQ(
4902  paragraph->GetWordBoundary(icu_text.length() - 1),
4903  txt::Paragraph::Range<size_t>(icu_text.length() - 5, icu_text.length()));
4904  rect = GetCoordinatesForGlyphPosition(*paragraph, icu_text.length());
4905  GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
4906 
4907  ASSERT_TRUE(Snapshot());
4908 }
4909 
4910 TEST_F(ParagraphTest, SpacingParagraph) {
4911  const char* text = "H";
4912  auto icu_text = icu::UnicodeString::fromUTF8(text);
4913  std::u16string u16_text(icu_text.getBuffer(),
4914  icu_text.getBuffer() + icu_text.length());
4915 
4916  txt::ParagraphStyle paragraph_style;
4917  paragraph_style.max_lines = 10;
4918  paragraph_style.text_align = TextAlign::left;
4919  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
4920 
4921  txt::TextStyle text_style;
4922  text_style.font_families = std::vector<std::string>(1, "Roboto");
4923  text_style.font_size = 50;
4924  text_style.letter_spacing = 20;
4925  text_style.word_spacing = 0;
4926  text_style.color = SK_ColorBLACK;
4927  text_style.height = 1;
4928  builder.PushStyle(text_style);
4929  builder.AddText(u16_text);
4930  builder.Pop();
4931 
4932  text_style.font_size = 50;
4933  text_style.letter_spacing = 10;
4934  text_style.word_spacing = 0;
4935  builder.PushStyle(text_style);
4936  builder.AddText(u16_text);
4937  builder.Pop();
4938 
4939  text_style.font_size = 50;
4940  text_style.letter_spacing = 20;
4941  text_style.word_spacing = 0;
4942  builder.PushStyle(text_style);
4943  builder.AddText(u16_text);
4944  builder.Pop();
4945 
4946  text_style.font_size = 50;
4947  text_style.letter_spacing = 0;
4948  text_style.word_spacing = 0;
4949  builder.PushStyle(text_style);
4950  builder.AddText(u"|");
4951  builder.Pop();
4952 
4953  text_style.font_size = 50;
4954  text_style.letter_spacing = 0;
4955  text_style.word_spacing = 20;
4956  builder.PushStyle(text_style);
4957  builder.AddText(u"H ");
4958  builder.Pop();
4959 
4960  text_style.font_size = 50;
4961  text_style.letter_spacing = 0;
4962  text_style.word_spacing = 0;
4963  builder.PushStyle(text_style);
4964  builder.AddText(u"H ");
4965  builder.Pop();
4966 
4967  text_style.font_size = 50;
4968  text_style.letter_spacing = 0;
4969  text_style.word_spacing = 20;
4970  builder.PushStyle(text_style);
4971  builder.AddText(u"H ");
4972  builder.Pop();
4973 
4974  auto paragraph = BuildParagraph(builder);
4975  paragraph->Layout(550);
4976 
4977  paragraph->Paint(GetCanvas(), 0, 0);
4978 
4979  SkPaint paint;
4980  paint.setStyle(SkPaint::kStroke_Style);
4981  paint.setAntiAlias(true);
4982  paint.setStrokeWidth(1);
4983  paint.setColor(SK_ColorRED);
4984 
4985  ASSERT_TRUE(Snapshot());
4986 
4987  ASSERT_EQ(paragraph->records_.size(), 7ull);
4988  ASSERT_EQ(paragraph->records_[0].style().letter_spacing, 20);
4989  ASSERT_EQ(paragraph->records_[1].style().letter_spacing, 10);
4990  ASSERT_EQ(paragraph->records_[2].style().letter_spacing, 20);
4991 
4992  ASSERT_EQ(paragraph->records_[4].style().word_spacing, 20);
4993  ASSERT_EQ(paragraph->records_[5].style().word_spacing, 0);
4994  ASSERT_EQ(paragraph->records_[6].style().word_spacing, 20);
4995 }
4996 
4997 TEST_F(ParagraphTest, LongWordParagraph) {
4998  const char* text =
4999  "A "
5000  "veryverylongwordtoseewherethiswillwraporifitwillatallandifitdoesthenthat"
5001  "wouldbeagoodthingbecausethebreakingisworking.";
5002  auto icu_text = icu::UnicodeString::fromUTF8(text);
5003  std::u16string u16_text(icu_text.getBuffer(),
5004  icu_text.getBuffer() + icu_text.length());
5005 
5006  txt::ParagraphStyle paragraph_style;
5008  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5009 
5010  txt::TextStyle text_style;
5011  text_style.font_families = std::vector<std::string>(1, "Roboto");
5012  text_style.font_size = 31;
5013  text_style.letter_spacing = 0;
5014  text_style.word_spacing = 0;
5015  text_style.color = SK_ColorBLACK;
5016  text_style.height = 1;
5017  builder.PushStyle(text_style);
5018  builder.AddText(u16_text);
5019 
5020  builder.Pop();
5021 
5022  auto paragraph = BuildParagraph(builder);
5023  paragraph->Layout(GetTestCanvasWidth() / 2);
5024 
5025  paragraph->Paint(GetCanvas(), 0, 0);
5026 
5027  ASSERT_TRUE(Snapshot());
5028  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
5029  for (size_t i = 0; i < u16_text.length(); i++) {
5030  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5031  }
5032  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
5033  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
5034  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
5035  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
5036  ASSERT_EQ(paragraph->GetLineCount(), 4ull);
5037  ASSERT_TRUE(Snapshot());
5038 }
5039 
5040 TEST_F(ParagraphTest, LINUX_ONLY(KernScaleParagraph)) {
5041  float scale = 3.0f;
5042 
5043  txt::ParagraphStyle paragraph_style;
5045  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5046 
5047  txt::TextStyle text_style;
5048  text_style.font_families = std::vector<std::string>(1, "Droid Serif");
5049  text_style.font_size = 100 / scale;
5050  text_style.letter_spacing = 0;
5051  text_style.word_spacing = 0;
5052  text_style.color = SK_ColorBLACK;
5053  text_style.height = 1;
5054  builder.PushStyle(text_style);
5055  builder.AddText(u"AVAVAWAH A0 V0 VA To The Lo");
5056  builder.PushStyle(text_style);
5057  builder.AddText(u"A");
5058  builder.PushStyle(text_style);
5059  builder.AddText(u"V");
5060  text_style.font_size = 14 / scale;
5061  builder.PushStyle(text_style);
5062  builder.AddText(
5063  u" Dialog Text List lots of words to see if kerning works on a bigger "
5064  u"set of characters AVAVAW");
5065 
5066  builder.Pop();
5067 
5068  auto paragraph = BuildParagraph(builder);
5069  paragraph->Layout(GetTestCanvasWidth() / scale);
5070  GetCanvas()->scale(scale, scale);
5071  paragraph->Paint(GetCanvas(), 0, 0);
5072  GetCanvas()->scale(1.0, 1.0);
5073  ASSERT_TRUE(Snapshot());
5074 
5075  EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
5076  EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
5077  EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 207.359375f);
5078  EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 230.859375f);
5079  EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 253.34765625f);
5080 }
5081 
5083  txt::ParagraphStyle paragraph_style;
5084  paragraph_style.font_family = "Roboto";
5086 
5087  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5088 
5089  txt::TextStyle text_style;
5090  text_style.font_families = std::vector<std::string>(1, "Roboto");
5091  text_style.font_size = 60;
5092  text_style.letter_spacing = 0;
5093  text_style.word_spacing = 0;
5094  text_style.color = SK_ColorBLACK;
5095  text_style.height = 1;
5096  builder.PushStyle(text_style);
5097  builder.AddText(
5098  u"line1\nline2 test1 test2 test3 test4 test5 test6 test7\nline3\n\nline4 "
5099  "test1 test2 test3 test4");
5100 
5101  builder.Pop();
5102 
5103  auto paragraph = BuildParagraph(builder);
5104  paragraph->Layout(GetTestCanvasWidth() - 300);
5105 
5106  paragraph->Paint(GetCanvas(), 0, 0);
5107 
5108  ASSERT_TRUE(Snapshot());
5109 
5110  ASSERT_EQ(paragraph->records_.size(), 6ull);
5111  EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
5112  EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
5113  EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().y(), 126);
5114  EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
5115  EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0);
5116  EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 0);
5117  EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().y(), 266);
5118  EXPECT_DOUBLE_EQ(paragraph->records_[5].offset().x(), 0);
5119 }
5120 
5121 TEST_F(ParagraphTest, LINUX_ONLY(EmojiParagraph)) {
5122  const char* text =
5123  "😀😃😄😁😆😅😂🤣☺😇🙂😍😡😟😢😻👽💩👍👎🙏👌👋👄👁👦👼👨‍🚀👨‍🚒🙋‍♂️👳👨‍👨‍👧‍👧\
5124  💼👡👠☂🐶🐰🐻🐼🐷🐒🐵🐔🐧🐦🐋🐟🐡🕸🐌🐴🐊🐄🐪🐘🌸🌏🔥🌟🌚🌝💦💧\
5125  ❄🍕🍔🍟🥝🍱🕶🎩🏈⚽🚴‍♀️🎻🎼🎹🚨🚎🚐⚓🛳🚀🚁🏪🏢🖱⏰📱💾💉📉🛏🔑🔓\
5126  📁🗓📊❤💯🚫🔻♠♣🕓❗🏳🏁🏳️‍🌈🇮🇹🇱🇷🇺🇸🇬🇧🇨🇳🇧🇴";
5127  auto icu_text = icu::UnicodeString::fromUTF8(text);
5128  std::u16string u16_text(icu_text.getBuffer(),
5129  icu_text.getBuffer() + icu_text.length());
5130 
5131  txt::ParagraphStyle paragraph_style;
5132 
5133  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5134 
5135  txt::TextStyle text_style;
5136  text_style.color = SK_ColorBLACK;
5137  text_style.font_families = std::vector<std::string>(1, "Noto Color Emoji");
5138  text_style.font_size = 50;
5140  builder.PushStyle(text_style);
5141  builder.AddText(u16_text);
5142 
5143  builder.Pop();
5144 
5145  auto paragraph = BuildParagraph(builder);
5146  paragraph->Layout(GetTestCanvasWidth());
5147 
5148  paragraph->Paint(GetCanvas(), 0, 0);
5149 
5150  ASSERT_TRUE(Snapshot());
5151 
5152  for (size_t i = 0; i < u16_text.length(); i++) {
5153  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5154  }
5155 
5156  ASSERT_EQ(paragraph->records_.size(), 8ull);
5157 
5158  EXPECT_EQ(paragraph->records_[0].line(), 0ull);
5159  EXPECT_EQ(paragraph->records_[1].line(), 1ull);
5160  EXPECT_EQ(paragraph->records_[2].line(), 2ull);
5161  EXPECT_EQ(paragraph->records_[3].line(), 3ull);
5162  EXPECT_EQ(paragraph->records_[7].line(), 7ull);
5163 }
5164 
5165 TEST_F(ParagraphTest, LINUX_ONLY(EmojiMultiLineRectsParagraph)) {
5166  // clang-format off
5167  const char* text =
5168  "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧i🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸"
5169  "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸"
5170  "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸"
5171  "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸"
5172  "❄🍕🍔🍟🥝🍱🕶🎩🏈⚽🚴‍♀️🎻🎼🎹🚨🚎🚐⚓🛳🚀🚁🏪🏢🖱⏰📱💾💉📉🛏🔑🔓"
5173  "📁🗓📊❤💯🚫🔻♠♣🕓❗🏳🏁🏳️‍🌈🇮🇹🇱🇷🇺🇸🇬🇧🇨🇳🇧🇴";
5174  // clang-format on
5175  auto icu_text = icu::UnicodeString::fromUTF8(text);
5176  std::u16string u16_text(icu_text.getBuffer(),
5177  icu_text.getBuffer() + icu_text.length());
5178 
5179  txt::ParagraphStyle paragraph_style;
5180 
5181  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5182 
5183  txt::TextStyle text_style;
5184  text_style.color = SK_ColorBLACK;
5185  text_style.font_families = std::vector<std::string>(1, "Noto Color Emoji");
5186  text_style.font_size = 50;
5187  builder.PushStyle(text_style);
5188  builder.AddText(u16_text);
5189 
5190  builder.Pop();
5191 
5192  auto paragraph = BuildParagraph(builder);
5193  paragraph->Layout(GetTestCanvasWidth() - 300);
5194 
5195  paragraph->Paint(GetCanvas(), 0, 0);
5196 
5197  for (size_t i = 0; i < u16_text.length(); i++) {
5198  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5199  }
5200 
5201  ASSERT_EQ(paragraph->records_.size(), 10ull);
5202 
5203  SkPaint paint;
5204  paint.setStyle(SkPaint::kStroke_Style);
5205  paint.setAntiAlias(true);
5206  paint.setStrokeWidth(1);
5207 
5208  // Tests for GetRectsForRange()
5209  Paragraph::RectHeightStyle rect_height_style =
5211  Paragraph::RectWidthStyle rect_width_style =
5213  paint.setColor(SK_ColorRED);
5214  std::vector<txt::Paragraph::TextBox> boxes =
5215  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
5216  for (size_t i = 0; i < boxes.size(); ++i) {
5217  GetCanvas()->drawRect(boxes[i].rect, paint);
5218  }
5219  EXPECT_EQ(boxes.size(), 0ull);
5220 
5221  // GetPositionForCoordinates should not return inter-emoji positions.
5222  boxes = paragraph->GetRectsForRange(
5223  0, paragraph->GetGlyphPositionAtCoordinate(610, 100).position,
5224  rect_height_style, rect_width_style);
5225  paint.setColor(SK_ColorGREEN);
5226  for (size_t i = 0; i < boxes.size(); ++i) {
5227  GetCanvas()->drawRect(boxes[i].rect, paint);
5228  }
5229  EXPECT_EQ(boxes.size(), 2ull);
5230  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
5231  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 622.53906);
5232 
5233  boxes = paragraph->GetRectsForRange(
5234  0, paragraph->GetGlyphPositionAtCoordinate(580, 100).position,
5235  rect_height_style, rect_width_style);
5236  paint.setColor(SK_ColorGREEN);
5237  for (size_t i = 0; i < boxes.size(); ++i) {
5238  GetCanvas()->drawRect(boxes[i].rect, paint);
5239  }
5240  EXPECT_EQ(boxes.size(), 2ull);
5241  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
5242  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 560.28516);
5243 
5244  boxes = paragraph->GetRectsForRange(
5245  0, paragraph->GetGlyphPositionAtCoordinate(560, 100).position,
5246  rect_height_style, rect_width_style);
5247  paint.setColor(SK_ColorGREEN);
5248  for (size_t i = 0; i < boxes.size(); ++i) {
5249  GetCanvas()->drawRect(boxes[i].rect, paint);
5250  }
5251  EXPECT_EQ(boxes.size(), 2ull);
5252  EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0);
5253  EXPECT_FLOAT_EQ(boxes[1].rect.right(), 560.28516);
5254 
5255  ASSERT_TRUE(Snapshot());
5256 }
5257 
5258 TEST_F(ParagraphTest, LINUX_ONLY(LigatureCharacters)) {
5259  const char* text = "Office";
5260  auto icu_text = icu::UnicodeString::fromUTF8(text);
5261  std::u16string u16_text(icu_text.getBuffer(),
5262  icu_text.getBuffer() + icu_text.length());
5263 
5264  txt::ParagraphStyle paragraph_style;
5265  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5266 
5267  txt::TextStyle text_style;
5268  text_style.font_families = std::vector<std::string>(1, "Roboto");
5269  text_style.color = SK_ColorBLACK;
5270  builder.PushStyle(text_style);
5271  builder.AddText(u16_text);
5272 
5273  builder.Pop();
5274 
5275  auto paragraph = BuildParagraph(builder);
5276  paragraph->Layout(GetTestCanvasWidth());
5277 
5278  // The "ffi" characters will be combined into one glyph in the Roboto font.
5279  // Verify that the graphemes within the glyph have distinct boxes.
5280  std::vector<txt::Paragraph::TextBox> boxes =
5281  paragraph->GetRectsForRange(1, 2, Paragraph::RectHeightStyle::kTight,
5283  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 9.625);
5284  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 13.608073);
5285 
5286  boxes = paragraph->GetRectsForRange(2, 4, Paragraph::RectHeightStyle::kTight,
5288  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 13.608073);
5289  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 21.574219);
5290 }
5291 
5292 TEST_F(ParagraphTest, HyphenBreakParagraph) {
5293  const char* text =
5294  "A "
5295  "very-very-long-Hyphen-word-to-see-where-this-will-wrap-or-if-it-will-at-"
5296  "all-and-if-it-does-thent-hat-"
5297  "would-be-a-good-thing-because-the-breaking.";
5298  auto icu_text = icu::UnicodeString::fromUTF8(text);
5299  std::u16string u16_text(icu_text.getBuffer(),
5300  icu_text.getBuffer() + icu_text.length());
5301 
5302  txt::ParagraphStyle paragraph_style;
5304 
5305  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5306 
5307  txt::TextStyle text_style;
5308  text_style.font_families = std::vector<std::string>(1, "Roboto");
5309  text_style.font_size = 31;
5310  text_style.letter_spacing = 0;
5311  text_style.word_spacing = 0;
5312  text_style.color = SK_ColorBLACK;
5313  text_style.height = 1;
5314  builder.PushStyle(text_style);
5315  builder.AddText(u16_text);
5316 
5317  builder.Pop();
5318 
5319  auto paragraph = BuildParagraph(builder);
5320  paragraph->Layout(GetTestCanvasWidth() / 2);
5321 
5322  paragraph->Paint(GetCanvas(), 0, 0);
5323 
5324  ASSERT_TRUE(Snapshot());
5325  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
5326  for (size_t i = 0; i < u16_text.length(); i++) {
5327  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5328  }
5329  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
5330  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
5331  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
5332  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
5333  ASSERT_EQ(paragraph->GetLineCount(), 5ull);
5334  ASSERT_TRUE(Snapshot());
5335 }
5336 
5337 TEST_F(ParagraphTest, RepeatLayoutParagraph) {
5338  const char* text =
5339  "Sentence to layout at diff widths to get diff line counts. short words "
5340  "short words short words short words short words short words short words "
5341  "short words short words short words short words short words short words "
5342  "end";
5343  auto icu_text = icu::UnicodeString::fromUTF8(text);
5344  std::u16string u16_text(icu_text.getBuffer(),
5345  icu_text.getBuffer() + icu_text.length());
5346 
5347  txt::ParagraphStyle paragraph_style;
5349  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5350 
5351  txt::TextStyle text_style;
5352  text_style.font_families = std::vector<std::string>(1, "Roboto");
5353  text_style.font_size = 31;
5354  text_style.letter_spacing = 0;
5355  text_style.word_spacing = 0;
5356  text_style.color = SK_ColorBLACK;
5357  text_style.height = 1;
5358  builder.PushStyle(text_style);
5359  builder.AddText(u16_text);
5360 
5361  builder.Pop();
5362 
5363  // First Layout.
5364  auto paragraph = BuildParagraph(builder);
5365  paragraph->Layout(300);
5366 
5367  paragraph->Paint(GetCanvas(), 0, 0);
5368 
5369  ASSERT_TRUE(Snapshot());
5370  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
5371  for (size_t i = 0; i < u16_text.length(); i++) {
5372  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5373  }
5374  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
5375  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
5376  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
5377  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
5378  ASSERT_EQ(paragraph->GetLineCount(), 12ull);
5379 
5380  // Second Layout.
5381  SetUp();
5382  paragraph->Layout(600);
5383  paragraph->Paint(GetCanvas(), 0, 0);
5384 
5385  ASSERT_TRUE(Snapshot());
5386  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
5387  for (size_t i = 0; i < u16_text.length(); i++) {
5388  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5389  }
5390  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
5391  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
5392  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
5393  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
5394  ASSERT_EQ(paragraph->GetLineCount(), 6ull);
5395  ASSERT_TRUE(Snapshot());
5396 }
5397 
5398 TEST_F(ParagraphTest, Ellipsize) {
5399  const char* text =
5400  "This is a very long sentence to test if the text will properly wrap "
5401  "around and go to the next line. Sometimes, short sentence. Longer "
5402  "sentences are okay too because they are necessary. Very short. ";
5403  auto icu_text = icu::UnicodeString::fromUTF8(text);
5404  std::u16string u16_text(icu_text.getBuffer(),
5405  icu_text.getBuffer() + icu_text.length());
5406 
5407  txt::ParagraphStyle paragraph_style;
5408  paragraph_style.ellipsis = u"\u2026";
5409  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5410 
5411  txt::TextStyle text_style;
5412  text_style.font_families = std::vector<std::string>(1, "Roboto");
5413  text_style.color = SK_ColorBLACK;
5414  builder.PushStyle(text_style);
5415  builder.AddText(u16_text);
5416 
5417  builder.Pop();
5418 
5419  auto paragraph = BuildParagraph(builder);
5420  paragraph->Layout(GetTestCanvasWidth());
5421 
5422  paragraph->Paint(GetCanvas(), 0, 0);
5423 
5424  ASSERT_TRUE(Snapshot());
5425 
5426  // Check that the ellipsizer limited the text to one line and did not wrap
5427  // to a second line.
5428  ASSERT_EQ(paragraph->records_.size(), 1ull);
5429 }
5430 
5431 // Test for shifting when identical runs of text are built as multiple runs.
5432 TEST_F(ParagraphTest, UnderlineShiftParagraph) {
5433  const char* text1 = "fluttser ";
5434  auto icu_text1 = icu::UnicodeString::fromUTF8(text1);
5435  std::u16string u16_text1(icu_text1.getBuffer(),
5436  icu_text1.getBuffer() + icu_text1.length());
5437  const char* text2 = "mdje";
5438  auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
5439  std::u16string u16_text2(icu_text2.getBuffer(),
5440  icu_text2.getBuffer() + icu_text2.length());
5441  const char* text3 = "fluttser mdje";
5442  auto icu_text3 = icu::UnicodeString::fromUTF8(text3);
5443  std::u16string u16_text3(icu_text3.getBuffer(),
5444  icu_text3.getBuffer() + icu_text3.length());
5445 
5446  // Construct multi-run paragraph.
5447  txt::ParagraphStyle paragraph_style;
5448  paragraph_style.max_lines = 2;
5449  paragraph_style.text_align = TextAlign::left;
5450  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5451 
5452  txt::TextStyle text_style1;
5453  text_style1.color = SK_ColorBLACK;
5454  text_style1.font_families = std::vector<std::string>(1, "Roboto");
5455  builder.PushStyle(text_style1);
5456 
5457  builder.AddText(u16_text1);
5458 
5459  txt::TextStyle text_style2;
5460  text_style2.color = SK_ColorBLACK;
5461  text_style2.font_families = std::vector<std::string>(1, "Roboto");
5462  text_style2.decoration = TextDecoration::kUnderline;
5463  text_style2.decoration_color = SK_ColorBLACK;
5464  builder.PushStyle(text_style2);
5465 
5466  builder.AddText(u16_text2);
5467 
5468  builder.Pop();
5469 
5470  // Construct single run paragraph.
5471  txt::ParagraphBuilderTxt builder2(paragraph_style, GetTestFontCollection());
5472 
5473  builder2.PushStyle(text_style1);
5474 
5475  builder2.AddText(u16_text3);
5476 
5477  builder2.Pop();
5478 
5479  // Build multi-run paragraph
5480  auto paragraph = BuildParagraph(builder);
5481  paragraph->Layout(GetTestCanvasWidth());
5482 
5483  paragraph->Paint(GetCanvas(), 0, 0);
5484 
5485  // Build single-run paragraph
5486  auto paragraph2 = BuildParagraph(builder2);
5487  paragraph2->Layout(GetTestCanvasWidth());
5488 
5489  paragraph2->Paint(GetCanvas(), 0, 25);
5490 
5491  ASSERT_TRUE(Snapshot());
5492 
5493  ASSERT_EQ(paragraph->records_[0].GetRunWidth() +
5494  paragraph->records_[1].GetRunWidth(),
5495  paragraph2->records_[0].GetRunWidth());
5496 
5497  auto rects1 =
5498  paragraph->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax,
5500  auto rects2 =
5501  paragraph2->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax,
5503 
5504  for (size_t i = 0; i < 12; ++i) {
5505  auto r1 = GetCoordinatesForGlyphPosition(*paragraph, i);
5506  auto r2 = GetCoordinatesForGlyphPosition(*paragraph2, i);
5507 
5508  ASSERT_EQ(r1.fLeft, r2.fLeft);
5509  ASSERT_EQ(r1.fRight, r2.fRight);
5510  }
5511 }
5512 
5513 TEST_F(ParagraphTest, SimpleShadow) {
5514  const char* text = "Hello World Text Dialog";
5515  auto icu_text = icu::UnicodeString::fromUTF8(text);
5516  std::u16string u16_text(icu_text.getBuffer(),
5517  icu_text.getBuffer() + icu_text.length());
5518 
5519  txt::ParagraphStyle paragraph_style;
5520  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5521 
5522  txt::TextStyle text_style;
5523  text_style.font_families = std::vector<std::string>(1, "Roboto");
5524  text_style.color = SK_ColorBLACK;
5525  text_style.text_shadows.emplace_back(SK_ColorBLACK, SkPoint::Make(2.0, 2.0),
5526  1.0);
5527  builder.PushStyle(text_style);
5528  builder.AddText(u16_text);
5529 
5530  builder.Pop();
5531 
5532  auto paragraph = BuildParagraph(builder);
5533  paragraph->Layout(GetTestCanvasWidth());
5534  paragraph->Paint(GetCanvas(), 10.0, 15.0);
5535 
5536  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
5537  for (size_t i = 0; i < u16_text.length(); i++) {
5538  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5539  }
5540  ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
5541  ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
5542  ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
5543  ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
5544 
5545  ASSERT_EQ(paragraph->records_[0].style().text_shadows.size(), 1ull);
5546  ASSERT_EQ(paragraph->records_[0].style().text_shadows[0],
5547  text_style.text_shadows[0]);
5548 
5549  ASSERT_TRUE(Snapshot());
5550 }
5551 
5552 TEST_F(ParagraphTest, ComplexShadow) {
5553  const char* text = "Text Chunk ";
5554  auto icu_text = icu::UnicodeString::fromUTF8(text);
5555  std::u16string u16_text(icu_text.getBuffer(),
5556  icu_text.getBuffer() + icu_text.length());
5557 
5558  txt::ParagraphStyle paragraph_style;
5559  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5560 
5561  txt::TextStyle text_style;
5562  text_style.font_families = std::vector<std::string>(1, "Roboto");
5563  text_style.color = SK_ColorBLACK;
5564  text_style.text_shadows.emplace_back(SK_ColorBLACK, SkPoint::Make(2.0, 2.0),
5565  1.0);
5566  builder.PushStyle(text_style);
5567  builder.AddText(u16_text);
5568 
5569  text_style.text_shadows.emplace_back(SK_ColorRED, SkPoint::Make(2.0, 2.0),
5570  5.0);
5571  text_style.text_shadows.emplace_back(SK_ColorGREEN, SkPoint::Make(10.0, -5.0),
5572  3.0);
5573  builder.PushStyle(text_style);
5574  builder.AddText(u16_text);
5575 
5576  builder.Pop();
5577  builder.AddText(u16_text);
5578 
5579  text_style.text_shadows.emplace_back(SK_ColorGREEN, SkPoint::Make(0.0, -1.0),
5580  0.0);
5581  builder.PushStyle(text_style);
5582  builder.AddText(u16_text);
5583 
5584  builder.Pop();
5585  builder.AddText(u16_text);
5586 
5587  builder.Pop();
5588 
5589  auto paragraph = BuildParagraph(builder);
5590  paragraph->Layout(GetTestCanvasWidth());
5591  paragraph->Paint(GetCanvas(), 10.0, 15.0);
5592 
5593  ASSERT_EQ(paragraph->text_.size(), std::string{text}.length() * 5);
5594  for (size_t i = 0; i < u16_text.length(); i++) {
5595  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
5596  }
5597 
5598  ASSERT_EQ(paragraph->records_[0].style().text_shadows.size(), 1ull);
5599  ASSERT_EQ(paragraph->records_[1].style().text_shadows.size(), 3ull);
5600  ASSERT_EQ(paragraph->records_[2].style().text_shadows.size(), 1ull);
5601  ASSERT_EQ(paragraph->records_[3].style().text_shadows.size(), 4ull);
5602  ASSERT_EQ(paragraph->records_[4].style().text_shadows.size(), 1ull);
5603  for (size_t i = 0; i < 1; ++i)
5604  ASSERT_EQ(paragraph->records_[0].style().text_shadows[i],
5605  text_style.text_shadows[i]);
5606  for (size_t i = 0; i < 3; ++i)
5607  ASSERT_EQ(paragraph->records_[1].style().text_shadows[i],
5608  text_style.text_shadows[i]);
5609  for (size_t i = 0; i < 1; ++i)
5610  ASSERT_EQ(paragraph->records_[2].style().text_shadows[i],
5611  text_style.text_shadows[i]);
5612  for (size_t i = 0; i < 4; ++i)
5613  ASSERT_EQ(paragraph->records_[3].style().text_shadows[i],
5614  text_style.text_shadows[i]);
5615  for (size_t i = 0; i < 1; ++i)
5616  ASSERT_EQ(paragraph->records_[4].style().text_shadows[i],
5617  text_style.text_shadows[i]);
5618 
5619  ASSERT_TRUE(Snapshot());
5620 }
5621 
5622 TEST_F(ParagraphTest, DISABLE_ON_MAC(BaselineParagraph)) {
5623  const char* text =
5624  "左線読設Byg後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
5625  "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得";
5626  auto icu_text = icu::UnicodeString::fromUTF8(text);
5627  std::u16string u16_text(icu_text.getBuffer(),
5628  icu_text.getBuffer() + icu_text.length());
5629 
5630  txt::ParagraphStyle paragraph_style;
5631  paragraph_style.max_lines = 14;
5632  paragraph_style.text_align = TextAlign::justify;
5633  paragraph_style.height = 1.5;
5634  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5635 
5636  txt::TextStyle text_style;
5637  text_style.color = SK_ColorBLACK;
5638  text_style.font_size = 55;
5639  text_style.letter_spacing = 2;
5640  text_style.font_families = std::vector<std::string>(1, "Source Han Serif CN");
5642  text_style.decoration_color = SK_ColorBLACK;
5643  builder.PushStyle(text_style);
5644 
5645  builder.AddText(u16_text);
5646 
5647  builder.Pop();
5648 
5649  auto paragraph = BuildParagraph(builder);
5650  paragraph->Layout(GetTestCanvasWidth() - 100);
5651 
5652  paragraph->Paint(GetCanvas(), 0, 0);
5653 
5654  SkPaint paint;
5655  paint.setStyle(SkPaint::kStroke_Style);
5656  paint.setAntiAlias(true);
5657  paint.setStrokeWidth(1);
5658  paint.setColor(SK_ColorRED);
5659  GetCanvas()->drawLine(0, paragraph->GetIdeographicBaseline(),
5660  paragraph->GetMaxWidth(),
5661  paragraph->GetIdeographicBaseline(), paint);
5662 
5663  paint.setColor(SK_ColorGREEN);
5664 
5665  GetCanvas()->drawLine(0, paragraph->GetAlphabeticBaseline(),
5666  paragraph->GetMaxWidth(),
5667  paragraph->GetAlphabeticBaseline(), paint);
5668  ASSERT_DOUBLE_EQ(paragraph->GetIdeographicBaseline(), 79.035000801086426);
5669  ASSERT_DOUBLE_EQ(paragraph->GetAlphabeticBaseline(), 63.305000305175781);
5670 
5671  ASSERT_TRUE(Snapshot());
5672 }
5673 
5674 TEST_F(ParagraphTest, FontFallbackParagraph) {
5675  const char* text = "Roboto 字典 ";
5676  auto icu_text = icu::UnicodeString::fromUTF8(text);
5677  std::u16string u16_text(icu_text.getBuffer(),
5678  icu_text.getBuffer() + icu_text.length());
5679  const char* text2 = "Homemade Apple 字典";
5680  icu_text = icu::UnicodeString::fromUTF8(text2);
5681  std::u16string u16_text2(icu_text.getBuffer(),
5682  icu_text.getBuffer() + icu_text.length());
5683  const char* text3 = "Chinese 字典";
5684  icu_text = icu::UnicodeString::fromUTF8(text3);
5685  std::u16string u16_text3(icu_text.getBuffer(),
5686  icu_text.getBuffer() + icu_text.length());
5687 
5688  txt::ParagraphStyle paragraph_style;
5689  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5690 
5691  txt::TextStyle text_style;
5692  // No chinese fallback provided, should not be able to render the chinese.
5693  text_style.font_families = std::vector<std::string>(1, "Not a real font");
5694  text_style.font_families.push_back("Also a fake font");
5695  text_style.font_families.push_back("So fake it is obvious");
5696  text_style.font_families.push_back("Next one should be a real font...");
5697  text_style.font_families.push_back("Roboto");
5698  text_style.font_families.push_back("another fake one in between");
5699  text_style.font_families.push_back("Homemade Apple");
5700  text_style.color = SK_ColorBLACK;
5701  builder.PushStyle(text_style);
5702  builder.AddText(u16_text);
5703 
5704  // Japanese version of the chinese should be rendered.
5705  text_style.font_families = std::vector<std::string>(1, "Not a real font");
5706  text_style.font_families.push_back("Also a fake font");
5707  text_style.font_families.push_back("So fake it is obvious");
5708  text_style.font_families.push_back("Homemade Apple");
5709  text_style.font_families.push_back("Next one should be a real font...");
5710  text_style.font_families.push_back("Roboto");
5711  text_style.font_families.push_back("another fake one in between");
5712  text_style.font_families.push_back("Noto Sans CJK JP");
5713  text_style.font_families.push_back("Source Han Serif CN");
5714  text_style.color = SK_ColorBLACK;
5715  builder.PushStyle(text_style);
5716  builder.AddText(u16_text2);
5717 
5718  // Chinese font defiend first
5719  text_style.font_families = std::vector<std::string>(1, "Not a real font");
5720  text_style.font_families.push_back("Also a fake font");
5721  text_style.font_families.push_back("So fake it is obvious");
5722  text_style.font_families.push_back("Homemade Apple");
5723  text_style.font_families.push_back("Next one should be a real font...");
5724  text_style.font_families.push_back("Roboto");
5725  text_style.font_families.push_back("another fake one in between");
5726  text_style.font_families.push_back("Source Han Serif CN");
5727  text_style.font_families.push_back("Noto Sans CJK JP");
5728  text_style.color = SK_ColorBLACK;
5729  builder.PushStyle(text_style);
5730  builder.AddText(u16_text3);
5731 
5732  builder.Pop();
5733 
5734  auto paragraph = BuildParagraph(builder);
5735  paragraph->Layout(GetTestCanvasWidth());
5736 
5737  paragraph->Paint(GetCanvas(), 10.0, 15.0);
5738 
5739  ASSERT_TRUE(Snapshot());
5740 
5741  ASSERT_EQ(paragraph->records_.size(), 5ull);
5742  ASSERT_DOUBLE_EQ(paragraph->records_[0].GetRunWidth(), 64.2109375);
5743  ASSERT_DOUBLE_EQ(paragraph->records_[1].GetRunWidth(), 139.1328125);
5744  ASSERT_DOUBLE_EQ(paragraph->records_[2].GetRunWidth(), 28);
5745  ASSERT_DOUBLE_EQ(paragraph->records_[3].GetRunWidth(), 62.25);
5746  ASSERT_DOUBLE_EQ(paragraph->records_[4].GetRunWidth(), 28);
5747  // When a different font is resolved, then the metrics are different.
5748  ASSERT_TRUE(paragraph->records_[2].metrics().fTop -
5749  paragraph->records_[4].metrics().fTop !=
5750  0);
5751  ASSERT_TRUE(paragraph->records_[2].metrics().fAscent -
5752  paragraph->records_[4].metrics().fAscent !=
5753  0);
5754  ASSERT_TRUE(paragraph->records_[2].metrics().fDescent -
5755  paragraph->records_[4].metrics().fDescent !=
5756  0);
5757  ASSERT_TRUE(paragraph->records_[2].metrics().fBottom -
5758  paragraph->records_[4].metrics().fBottom !=
5759  0);
5760  ASSERT_TRUE(paragraph->records_[2].metrics().fAvgCharWidth -
5761  paragraph->records_[4].metrics().fAvgCharWidth !=
5762  0);
5763 }
5764 
5765 TEST_F(ParagraphTest, LINUX_ONLY(StrutParagraph1)) {
5766  // The chinese extra height should be absorbed by the strut.
5767  const char* text = "01234満毎冠p来É本可\nabcd\n満毎É行p昼本可";
5768  auto icu_text = icu::UnicodeString::fromUTF8(text);
5769  std::u16string u16_text(icu_text.getBuffer(),
5770  icu_text.getBuffer() + icu_text.length());
5771 
5772  txt::ParagraphStyle paragraph_style;
5773  paragraph_style.max_lines = 10;
5774  paragraph_style.strut_font_families = std::vector<std::string>(1, "BlahFake");
5775  paragraph_style.strut_font_families.push_back("ahem");
5776  paragraph_style.strut_font_size = 50;
5777  paragraph_style.strut_height = 1.8;
5778  paragraph_style.strut_has_height_override = true;
5779  paragraph_style.strut_leading = 0.1;
5780  paragraph_style.strut_enabled = true;
5781 
5782  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5783 
5784  txt::TextStyle text_style;
5785  text_style.font_families = std::vector<std::string>(1, "ahem");
5786  text_style.font_families.push_back("ahem");
5787  text_style.font_size = 50;
5788  text_style.letter_spacing = 0;
5789  text_style.font_weight = FontWeight::w500;
5790  text_style.word_spacing = 0;
5791  text_style.color = SK_ColorBLACK;
5792  text_style.height = .5;
5793  builder.PushStyle(text_style);
5794 
5795  builder.AddText(u16_text);
5796 
5797  builder.Pop();
5798 
5799  auto paragraph = BuildParagraph(builder);
5800  paragraph->Layout(550);
5801 
5802  paragraph->Paint(GetCanvas(), 0, 0);
5803 
5804  SkPaint paint;
5805  paint.setStyle(SkPaint::kStroke_Style);
5806  paint.setAntiAlias(true);
5807  paint.setStrokeWidth(1);
5808 
5809  // Tests for GetRectsForRange()
5810  Paragraph::RectHeightStyle rect_height_style =
5812  Paragraph::RectHeightStyle rect_height_max_style =
5814  Paragraph::RectWidthStyle rect_width_style =
5816  paint.setColor(SK_ColorRED);
5817  std::vector<txt::Paragraph::TextBox> boxes =
5818  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
5819  for (size_t i = 0; i < boxes.size(); ++i) {
5820  GetCanvas()->drawRect(boxes[i].rect, paint);
5821  }
5822  EXPECT_EQ(boxes.size(), 0ull);
5823 
5824  boxes =
5825  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
5826  for (size_t i = 0; i < boxes.size(); ++i) {
5827  GetCanvas()->drawRect(boxes[i].rect, paint);
5828  }
5829  EXPECT_EQ(boxes.size(), 1ull);
5830  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5831  EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001);
5832  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
5833  EXPECT_NEAR(boxes[0].rect.bottom(), 84.5, 0.0001);
5834 
5835  boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
5836  rect_width_style);
5837  for (size_t i = 0; i < boxes.size(); ++i) {
5838  GetCanvas()->drawRect(boxes[i].rect, paint);
5839  }
5840  EXPECT_EQ(boxes.size(), 1ull);
5841  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5842  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
5843  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
5844  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 95);
5845 
5846  boxes =
5847  paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
5848  for (size_t i = 0; i < boxes.size(); ++i) {
5849  GetCanvas()->drawRect(boxes[i].rect, paint);
5850  }
5851  EXPECT_EQ(boxes.size(), 1ull);
5852  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
5853  EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001);
5854  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
5855  EXPECT_NEAR(boxes[0].rect.bottom(), 84.5, 0.0001);
5856  ;
5857 
5858  boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
5859  rect_width_style);
5860  for (size_t i = 0; i < boxes.size(); ++i) {
5861  GetCanvas()->drawRect(boxes[i].rect, paint);
5862  }
5863  EXPECT_EQ(boxes.size(), 1ull);
5864  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
5865  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
5866  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
5867  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 95);
5868 
5869  boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
5870  rect_width_style);
5871  for (size_t i = 0; i < boxes.size(); ++i) {
5872  GetCanvas()->drawRect(boxes[i].rect, paint);
5873  }
5874  EXPECT_EQ(boxes.size(), 1ull);
5875  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5876  EXPECT_NEAR(boxes[0].rect.top(), 190, 0.0001);
5877  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
5878  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 285);
5879 
5880  boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
5881  rect_width_style);
5882  for (size_t i = 0; i < boxes.size(); ++i) {
5883  GetCanvas()->drawRect(boxes[i].rect, paint);
5884  }
5885  EXPECT_EQ(boxes.size(), 1ull);
5886  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
5887  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 285);
5888  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
5889  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 380);
5890 
5891  ASSERT_TRUE(Snapshot());
5892 }
5893 
5895  // This string is all one size and smaller than the strut metrics.
5896  const char* text = "01234ABCDEFGH\nabcd\nABCDEFGH";
5897  auto icu_text = icu::UnicodeString::fromUTF8(text);
5898  std::u16string u16_text(icu_text.getBuffer(),
5899  icu_text.getBuffer() + icu_text.length());
5900 
5901  txt::ParagraphStyle paragraph_style;
5902  paragraph_style.max_lines = 10;
5903  paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
5904  paragraph_style.strut_font_size = 50;
5905  paragraph_style.strut_height = 1.6;
5906  paragraph_style.strut_has_height_override = true;
5907  paragraph_style.strut_enabled = true;
5908  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
5909 
5910  txt::TextStyle text_style;
5911  text_style.font_families = std::vector<std::string>(1, "ahem");
5912  text_style.font_families.push_back("ahem");
5913  text_style.font_size = 50;
5914  text_style.letter_spacing = 0;
5915  text_style.font_weight = FontWeight::w500;
5916  text_style.word_spacing = 0;
5917  text_style.color = SK_ColorBLACK;
5918  text_style.height = 1;
5919  builder.PushStyle(text_style);
5920 
5921  builder.AddText(u16_text);
5922 
5923  builder.Pop();
5924 
5925  auto paragraph = BuildParagraph(builder);
5926  paragraph->Layout(550);
5927 
5928  paragraph->Paint(GetCanvas(), 0, 0);
5929 
5930  SkPaint paint;
5931  paint.setStyle(SkPaint::kStroke_Style);
5932  paint.setAntiAlias(true);
5933  paint.setStrokeWidth(1);
5934 
5935  // Tests for GetRectsForRange()
5936  Paragraph::RectHeightStyle rect_height_style =
5938  Paragraph::RectHeightStyle rect_height_max_style =
5940  Paragraph::RectWidthStyle rect_width_style =
5942  paint.setColor(SK_ColorRED);
5943  std::vector<txt::Paragraph::TextBox> boxes =
5944  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
5945  for (size_t i = 0; i < boxes.size(); ++i) {
5946  GetCanvas()->drawRect(boxes[i].rect, paint);
5947  }
5948  EXPECT_EQ(boxes.size(), 0ull);
5949 
5950  boxes =
5951  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
5952  for (size_t i = 0; i < boxes.size(); ++i) {
5953  GetCanvas()->drawRect(boxes[i].rect, paint);
5954  }
5955  EXPECT_EQ(boxes.size(), 1ull);
5956  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5957  EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001);
5958  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
5959  EXPECT_NEAR(boxes[0].rect.bottom(), 74, 0.0001);
5960 
5961  boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
5962  rect_width_style);
5963  for (size_t i = 0; i < boxes.size(); ++i) {
5964  GetCanvas()->drawRect(boxes[i].rect, paint);
5965  }
5966  EXPECT_EQ(boxes.size(), 1ull);
5967  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
5968  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
5969  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
5970  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
5971 
5972  boxes =
5973  paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
5974  for (size_t i = 0; i < boxes.size(); ++i) {
5975  GetCanvas()->drawRect(boxes[i].rect, paint);
5976  }
5977  EXPECT_EQ(boxes.size(), 1ull);
5978  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
5979  EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001);
5980  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
5981  EXPECT_NEAR(boxes[0].rect.bottom(), 74, 0.0001);
5982 
5983  boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
5984  rect_width_style);
5985  for (size_t i = 0; i < boxes.size(); ++i) {
5986  GetCanvas()->drawRect(boxes[i].rect, paint);
5987  }
5988  EXPECT_EQ(boxes.size(), 1ull);
5989  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
5990  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
5991  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
5992  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
5993 
5994  boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
5995  rect_width_style);
5996  for (size_t i = 0; i < boxes.size(); ++i) {
5997  GetCanvas()->drawRect(boxes[i].rect, paint);
5998  }
5999  EXPECT_EQ(boxes.size(), 1ull);
6000  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6001  EXPECT_NEAR(boxes[0].rect.top(), 160, 0.0001);
6002  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
6003  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240);
6004 
6005  boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
6006  rect_width_style);
6007  for (size_t i = 0; i < boxes.size(); ++i) {
6008  GetCanvas()->drawRect(boxes[i].rect, paint);
6009  }
6010  EXPECT_EQ(boxes.size(), 1ull);
6011  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
6012  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 240);
6013  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
6014  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 320);
6015 
6016  ASSERT_TRUE(Snapshot());
6017 }
6018 
6020  // The strut is too small to absorb the extra chinese height, but the english
6021  // second line height is increased due to strut.
6022  const char* text = "01234満毎p行来昼本可\nabcd\n満毎冠行来昼本可";
6023  auto icu_text = icu::UnicodeString::fromUTF8(text);
6024  std::u16string u16_text(icu_text.getBuffer(),
6025  icu_text.getBuffer() + icu_text.length());
6026 
6027  txt::ParagraphStyle paragraph_style;
6028  paragraph_style.max_lines = 10;
6029  paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
6030  paragraph_style.strut_font_size = 50;
6031  paragraph_style.strut_height = 1.2;
6032  paragraph_style.strut_has_height_override = true;
6033  paragraph_style.strut_enabled = true;
6034  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
6035 
6036  txt::TextStyle text_style;
6037  text_style.font_families = std::vector<std::string>(1, "ahem");
6038  text_style.font_families.push_back("ahem");
6039  text_style.font_size = 50;
6040  text_style.letter_spacing = 0;
6041  text_style.font_weight = FontWeight::w500;
6042  text_style.word_spacing = 0;
6043  text_style.color = SK_ColorBLACK;
6044  text_style.height = 1;
6045  builder.PushStyle(text_style);
6046 
6047  builder.AddText(u16_text);
6048 
6049  builder.Pop();
6050 
6051  auto paragraph = BuildParagraph(builder);
6052  paragraph->Layout(550);
6053 
6054  paragraph->Paint(GetCanvas(), 0, 0);
6055 
6056  SkPaint paint;
6057  paint.setStyle(SkPaint::kStroke_Style);
6058  paint.setAntiAlias(true);
6059  paint.setStrokeWidth(1);
6060 
6061  // Tests for GetRectsForRange()
6062  Paragraph::RectHeightStyle rect_height_style =
6064  Paragraph::RectHeightStyle rect_height_max_style =
6066  Paragraph::RectWidthStyle rect_width_style =
6068  paint.setColor(SK_ColorRED);
6069  std::vector<txt::Paragraph::TextBox> boxes =
6070  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
6071  for (size_t i = 0; i < boxes.size(); ++i) {
6072  GetCanvas()->drawRect(boxes[i].rect, paint);
6073  }
6074  EXPECT_EQ(boxes.size(), 0ull);
6075 
6076  boxes =
6077  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
6078  for (size_t i = 0; i < boxes.size(); ++i) {
6079  GetCanvas()->drawRect(boxes[i].rect, paint);
6080  }
6081  EXPECT_EQ(boxes.size(), 1ull);
6082  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6083  EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001);
6084  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
6085  EXPECT_NEAR(boxes[0].rect.bottom(), 58, 0.0001);
6086 
6087  boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
6088  rect_width_style);
6089  for (size_t i = 0; i < boxes.size(); ++i) {
6090  GetCanvas()->drawRect(boxes[i].rect, paint);
6091  }
6092  EXPECT_EQ(boxes.size(), 1ull);
6093  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6094  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
6095  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
6096  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 60);
6097 
6098  boxes =
6099  paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
6100  for (size_t i = 0; i < boxes.size(); ++i) {
6101  GetCanvas()->drawRect(boxes[i].rect, paint);
6102  }
6103  EXPECT_EQ(boxes.size(), 1ull);
6104  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
6105  EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001);
6106  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
6107  EXPECT_NEAR(boxes[0].rect.bottom(), 58, 0.0001);
6108 
6109  boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
6110  rect_width_style);
6111  for (size_t i = 0; i < boxes.size(); ++i) {
6112  GetCanvas()->drawRect(boxes[i].rect, paint);
6113  }
6114  EXPECT_EQ(boxes.size(), 1ull);
6115  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
6116  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
6117  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
6118  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 60);
6119 
6120  boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
6121  rect_width_style);
6122  for (size_t i = 0; i < boxes.size(); ++i) {
6123  GetCanvas()->drawRect(boxes[i].rect, paint);
6124  }
6125  EXPECT_EQ(boxes.size(), 1ull);
6126  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6127  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 120);
6128  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
6129  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 180);
6130 
6131  boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
6132  rect_width_style);
6133  for (size_t i = 0; i < boxes.size(); ++i) {
6134  GetCanvas()->drawRect(boxes[i].rect, paint);
6135  }
6136  EXPECT_EQ(boxes.size(), 1ull);
6137  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
6138  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 180);
6139  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
6140  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240);
6141 
6142  ASSERT_TRUE(Snapshot());
6143 }
6144 
6145 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutForceParagraph)) {
6146  // The strut is too small to absorb the extra chinese height, but the english
6147  // second line height is increased due to strut.
6148  const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
6149  auto icu_text = icu::UnicodeString::fromUTF8(text);
6150  std::u16string u16_text(icu_text.getBuffer(),
6151  icu_text.getBuffer() + icu_text.length());
6152 
6153  txt::ParagraphStyle paragraph_style;
6154  paragraph_style.max_lines = 10;
6155  paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
6156  paragraph_style.strut_font_size = 50;
6157  paragraph_style.strut_height = 1.5;
6158  paragraph_style.strut_has_height_override = true;
6159  paragraph_style.strut_leading = 0.1;
6160  paragraph_style.force_strut_height = true;
6161  paragraph_style.strut_enabled = true;
6162  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
6163 
6164  txt::TextStyle text_style;
6165  text_style.font_families = std::vector<std::string>(1, "ahem");
6166  text_style.font_families.push_back("ahem");
6167  text_style.font_size = 50;
6168  text_style.letter_spacing = 0;
6169  text_style.word_spacing = 0;
6170  text_style.color = SK_ColorBLACK;
6171  text_style.height = 1;
6172  builder.PushStyle(text_style);
6173 
6174  builder.AddText(u16_text);
6175 
6176  builder.Pop();
6177 
6178  auto paragraph = BuildParagraph(builder);
6179  paragraph->Layout(550);
6180 
6181  paragraph->Paint(GetCanvas(), 0, 0);
6182 
6183  SkPaint paint;
6184  paint.setStyle(SkPaint::kStroke_Style);
6185  paint.setAntiAlias(true);
6186  paint.setStrokeWidth(1);
6187 
6188  // Tests for GetRectsForRange()
6189  Paragraph::RectHeightStyle rect_height_style =
6191  Paragraph::RectHeightStyle rect_height_max_style =
6193  Paragraph::RectWidthStyle rect_width_style =
6195  paint.setColor(SK_ColorRED);
6196  std::vector<txt::Paragraph::TextBox> boxes =
6197  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
6198  for (size_t i = 0; i < boxes.size(); ++i) {
6199  GetCanvas()->drawRect(boxes[i].rect, paint);
6200  }
6201  EXPECT_EQ(boxes.size(), 0ull);
6202 
6203  boxes =
6204  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
6205  for (size_t i = 0; i < boxes.size(); ++i) {
6206  GetCanvas()->drawRect(boxes[i].rect, paint);
6207  }
6208  EXPECT_EQ(boxes.size(), 1ull);
6209  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6210  EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001);
6211  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
6212  EXPECT_NEAR(boxes[0].rect.bottom(), 72.5, 0.0001);
6213 
6214  boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style,
6215  rect_width_style);
6216  for (size_t i = 0; i < boxes.size(); ++i) {
6217  GetCanvas()->drawRect(boxes[i].rect, paint);
6218  }
6219  EXPECT_EQ(boxes.size(), 1ull);
6220  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6221  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
6222  ;
6223  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50);
6224  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
6225 
6226  boxes =
6227  paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
6228  for (size_t i = 0; i < boxes.size(); ++i) {
6229  GetCanvas()->drawRect(boxes[i].rect, paint);
6230  }
6231  EXPECT_EQ(boxes.size(), 1ull);
6232  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
6233  EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001);
6234  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
6235  EXPECT_NEAR(boxes[0].rect.bottom(), 72.5, 0.0001);
6236 
6237  boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style,
6238  rect_width_style);
6239  for (size_t i = 0; i < boxes.size(); ++i) {
6240  GetCanvas()->drawRect(boxes[i].rect, paint);
6241  }
6242  EXPECT_EQ(boxes.size(), 1ull);
6243  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300);
6244  EXPECT_NEAR(boxes[0].rect.top(), 0, 0.0001);
6245  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500);
6246  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80);
6247 
6248  boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style,
6249  rect_width_style);
6250  for (size_t i = 0; i < boxes.size(); ++i) {
6251  GetCanvas()->drawRect(boxes[i].rect, paint);
6252  }
6253  EXPECT_EQ(boxes.size(), 1ull);
6254  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6255  EXPECT_NEAR(boxes[0].rect.top(), 160, 0.0001);
6256  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100);
6257  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240);
6258 
6259  boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style,
6260  rect_width_style);
6261  for (size_t i = 0; i < boxes.size(); ++i) {
6262  GetCanvas()->drawRect(boxes[i].rect, paint);
6263  }
6264  EXPECT_EQ(boxes.size(), 1ull);
6265  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50);
6266  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 240);
6267  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300);
6268  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 320);
6269 
6270  ASSERT_TRUE(Snapshot());
6271 }
6272 
6273 // The height override is disabled for this test. Direct metrics from the font.
6274 TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutDefaultParagraph)) {
6275  const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
6276  auto icu_text = icu::UnicodeString::fromUTF8(text);
6277  std::u16string u16_text(icu_text.getBuffer(),
6278  icu_text.getBuffer() + icu_text.length());
6279 
6280  txt::ParagraphStyle paragraph_style;
6281  paragraph_style.max_lines = 10;
6282  paragraph_style.strut_font_families = std::vector<std::string>(1, "ahem");
6283  paragraph_style.strut_font_size = 50;
6284  paragraph_style.strut_height = 1.5;
6285  paragraph_style.strut_leading = 0.1;
6286  paragraph_style.force_strut_height = false;
6287  paragraph_style.strut_enabled = true;
6288  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
6289 
6290  txt::TextStyle text_style;
6291  text_style.font_families = std::vector<std::string>(1, "ahem");
6292  text_style.font_families.push_back("ahem");
6293  text_style.font_size = 20;
6294  text_style.letter_spacing = 0;
6295  text_style.word_spacing = 0;
6296  text_style.color = SK_ColorBLACK;
6297  text_style.height = 1;
6298  builder.PushStyle(text_style);
6299 
6300  builder.AddText(u16_text);
6301 
6302  builder.Pop();
6303 
6304  auto paragraph = BuildParagraph(builder);
6305  paragraph->Layout(550);
6306 
6307  paragraph->Paint(GetCanvas(), 0, 0);
6308 
6309  SkPaint paint;
6310  paint.setStyle(SkPaint::kStroke_Style);
6311  paint.setAntiAlias(true);
6312  paint.setStrokeWidth(1);
6313 
6314  // Tests for GetRectsForRange()
6315  Paragraph::RectHeightStyle rect_height_style =
6317  Paragraph::RectHeightStyle rect_height_strut_style =
6319  Paragraph::RectWidthStyle rect_width_style =
6321  paint.setColor(SK_ColorRED);
6322  std::vector<txt::Paragraph::TextBox> boxes =
6323  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
6324  for (size_t i = 0; i < boxes.size(); ++i) {
6325  GetCanvas()->drawRect(boxes[i].rect, paint);
6326  }
6327  EXPECT_EQ(boxes.size(), 0ull);
6328 
6329  boxes =
6330  paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
6331  for (size_t i = 0; i < boxes.size(); ++i) {
6332  GetCanvas()->drawRect(boxes[i].rect, paint);
6333  }
6334  EXPECT_EQ(boxes.size(), 1ull);
6335  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6336  EXPECT_NEAR(boxes[0].rect.top(), 26.5, 0.0001);
6337  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 20);
6338  EXPECT_NEAR(boxes[0].rect.bottom(), 46.5, 0.0001);
6339 
6340  boxes = paragraph->GetRectsForRange(0, 2, rect_height_strut_style,
6341  rect_width_style);
6342  for (size_t i = 0; i < boxes.size(); ++i) {
6343  GetCanvas()->drawRect(boxes[i].rect, paint);
6344  }
6345  EXPECT_EQ(boxes.size(), 1ull);
6346  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6347  EXPECT_NEAR(boxes[0].rect.top(), 2.5, 0.0001);
6348  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 40);
6349  EXPECT_NEAR(boxes[0].rect.bottom(), 52.5, 0.0001);
6350 
6351  ASSERT_TRUE(Snapshot());
6352 }
6353 
6354 TEST_F(ParagraphTest, FontFeaturesParagraph) {
6355  const char* text = "12ab\n";
6356  auto icu_text = icu::UnicodeString::fromUTF8(text);
6357  std::u16string u16_text(icu_text.getBuffer(),
6358  icu_text.getBuffer() + icu_text.length());
6359 
6360  txt::ParagraphStyle paragraph_style;
6361  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
6362 
6363  txt::TextStyle text_style;
6364  text_style.font_families = std::vector<std::string>(1, "Roboto");
6365  text_style.color = SK_ColorBLACK;
6366  text_style.font_features.SetFeature("tnum", 1);
6367  builder.PushStyle(text_style);
6368  builder.AddText(u16_text);
6369 
6370  text_style.font_features.SetFeature("tnum", 0);
6371  text_style.font_features.SetFeature("pnum", 1);
6372  builder.PushStyle(text_style);
6373  builder.AddText(u16_text);
6374 
6375  builder.Pop();
6376  builder.Pop();
6377 
6378  auto paragraph = BuildParagraph(builder);
6379  paragraph->Layout(GetTestCanvasWidth());
6380 
6381  paragraph->Paint(GetCanvas(), 10.0, 15.0);
6382 
6383  ASSERT_EQ(paragraph->glyph_lines_.size(), 3ull);
6384 
6385  // Tabular numbers should have equal widths.
6386  const txt::ParagraphTxt::GlyphLine& tnum_line = paragraph->glyph_lines_[0];
6387  ASSERT_EQ(tnum_line.positions.size(), 4ull);
6388  EXPECT_FLOAT_EQ(tnum_line.positions[0].x_pos.width(),
6389  tnum_line.positions[1].x_pos.width());
6390 
6391  // Proportional numbers should have variable widths.
6392  const txt::ParagraphTxt::GlyphLine& pnum_line = paragraph->glyph_lines_[1];
6393  ASSERT_EQ(pnum_line.positions.size(), 4ull);
6394  EXPECT_NE(pnum_line.positions[0].x_pos.width(),
6395  pnum_line.positions[1].x_pos.width());
6396 
6397  // Alphabetic characters should be unaffected.
6398  EXPECT_FLOAT_EQ(tnum_line.positions[2].x_pos.width(),
6399  pnum_line.positions[2].x_pos.width());
6400 
6401  ASSERT_TRUE(Snapshot());
6402 }
6403 
6404 TEST_F(ParagraphTest, KhmerLineBreaker) {
6405  const char* text = "និងក្មេងចង់ផ្ទៃសមុទ្រសែនខៀវស្រងាត់";
6406  auto icu_text = icu::UnicodeString::fromUTF8(text);
6407  std::u16string u16_text(icu_text.getBuffer(),
6408  icu_text.getBuffer() + icu_text.length());
6409 
6410  txt::ParagraphStyle paragraph_style;
6411  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
6412 
6413  txt::TextStyle text_style;
6414  text_style.font_families = std::vector<std::string>(1, "Noto Sans Khmer");
6415  text_style.font_size = 24;
6416  text_style.color = SK_ColorBLACK;
6417  builder.PushStyle(text_style);
6418 
6419  builder.AddText(u16_text);
6420 
6421  builder.Pop();
6422 
6423  auto paragraph = BuildParagraph(builder);
6424  paragraph->Layout(200);
6425  paragraph->Paint(GetCanvas(), 0, 0);
6426 
6427  ASSERT_EQ(paragraph->glyph_lines_.size(), 3ull);
6428  EXPECT_EQ(paragraph->glyph_lines_[0].positions.size(), 7ul);
6429  EXPECT_EQ(paragraph->glyph_lines_[1].positions.size(), 7ul);
6430  EXPECT_EQ(paragraph->glyph_lines_[2].positions.size(), 3ul);
6431 
6432  ASSERT_TRUE(Snapshot());
6433 }
6434 
6435 TEST_F(ParagraphTest, TextHeightBehaviorRectsParagraph) {
6436  // clang-format off
6437  const char* text =
6438  "line1\nline2\nline3";
6439  // clang-format on
6440  auto icu_text = icu::UnicodeString::fromUTF8(text);
6441  std::u16string u16_text(icu_text.getBuffer(),
6442  icu_text.getBuffer() + icu_text.length());
6443 
6444  txt::ParagraphStyle paragraph_style;
6445  paragraph_style.text_height_behavior =
6448 
6449  txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
6450 
6451  txt::TextStyle text_style;
6452  text_style.color = SK_ColorBLACK;
6453  text_style.font_families = std::vector<std::string>(1, "Roboto");
6454  text_style.font_size = 30;
6455  text_style.height = 5;
6456  text_style.has_height_override = true;
6457  builder.PushStyle(text_style);
6458  builder.AddText(u16_text);
6459 
6460  builder.Pop();
6461 
6462  auto paragraph = BuildParagraph(builder);
6463  paragraph->Layout(GetTestCanvasWidth() - 300);
6464 
6465  paragraph->Paint(GetCanvas(), 0, 0);
6466 
6467  for (size_t i = 0; i < u16_text.length(); i++) {
6468  ASSERT_EQ(paragraph->text_[i], u16_text[i]);
6469  }
6470 
6471  ASSERT_EQ(paragraph->records_.size(), 3ull);
6472 
6473  SkPaint paint;
6474  paint.setStyle(SkPaint::kStroke_Style);
6475  paint.setAntiAlias(true);
6476  paint.setStrokeWidth(1);
6477 
6478  // Tests for GetRectsForRange()
6479  Paragraph::RectHeightStyle rect_height_style =
6481  Paragraph::RectWidthStyle rect_width_style =
6483  paint.setColor(SK_ColorRED);
6484  std::vector<txt::Paragraph::TextBox> boxes =
6485  paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
6486  for (size_t i = 0; i < boxes.size(); ++i) {
6487  GetCanvas()->drawRect(boxes[i].rect, paint);
6488  }
6489  EXPECT_EQ(boxes.size(), 0ull);
6490 
6491  // First line. Shorter due to disabled height modifications on first ascent.
6492  boxes =
6493  paragraph->GetRectsForRange(0, 3, rect_height_style, rect_width_style);
6494  for (size_t i = 0; i < boxes.size(); ++i) {
6495  GetCanvas()->drawRect(boxes[i].rect, paint);
6496  }
6497  EXPECT_EQ(boxes.size(), 1ull);
6498  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6499  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 31.117188);
6500  EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.08203125);
6501  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
6502  EXPECT_FLOAT_EQ(boxes[0].rect.bottom() - boxes[0].rect.top(), 59.082031);
6503 
6504  // Second line. Normal.
6505  boxes =
6506  paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style);
6507  for (size_t i = 0; i < boxes.size(); ++i) {
6508  GetCanvas()->drawRect(boxes[i].rect, paint);
6509  }
6510  EXPECT_EQ(boxes.size(), 1ull);
6511  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6512  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 47.011719);
6513  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59);
6514  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 209);
6515  EXPECT_FLOAT_EQ(boxes[0].rect.bottom() - boxes[0].rect.top(), 150);
6516 
6517  // Third line. Shorter due to disabled height modifications on last descent
6518  boxes =
6519  paragraph->GetRectsForRange(12, 17, rect_height_style, rect_width_style);
6520  for (size_t i = 0; i < boxes.size(); ++i) {
6521  GetCanvas()->drawRect(boxes[i].rect, paint);
6522  }
6523  EXPECT_EQ(boxes.size(), 1ull);
6524  EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0);
6525  EXPECT_FLOAT_EQ(boxes[0].rect.right(), 63.859375);
6526  EXPECT_FLOAT_EQ(boxes[0].rect.top(), 208.92578);
6527  EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 335);
6528  EXPECT_FLOAT_EQ(boxes[0].rect.bottom() - boxes[0].rect.top(), 126.07422);
6529 
6530  ASSERT_TRUE(Snapshot());
6531 }
6532 
6533 } // namespace txt
std::vector< TextShadow > text_shadows
Definition: text_style.h:62
#define DISABLE_ON_WINDOWS(TEST)
bool has_height_override
Definition: text_style.h:54
std::shared_ptr< FontCollection > GetTestFontCollection()
double height
Definition: text_style.h:53
double decoration_thickness_multiplier
Definition: text_style.h:43
FontStyle font_style
Definition: text_style.h:45
virtual void Pop() override
double letter_spacing
Definition: text_style.h:51
virtual void AddPlaceholder(PlaceholderRun &span) override
double font_size
Definition: text_style.h:50
std::u16string ellipsis