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