1 // Copyright 2019 Google LLC.
2 #include "src/utils/SkOSPath.h"
3 #include <sstream>
4 #include "modules/skparagraph/include/TypefaceFontProvider.h"
5 #include "modules/skparagraph/src/ParagraphBuilderImpl.h"
6 #include "modules/skparagraph/src/ParagraphImpl.h"
7 #include "src/core/SkOSFile.h"
8 #include "src/utils/SkShaperJSONWriter.h"
9 #include "tests/CodecPriv.h"
10 #include "tests/Test.h"
11 #include "tools/Resources.h"
12 #include "tools/ToolUtils.h"
13
14 #define VeryLongCanvasWidth 1000000
15 #define TestCanvasWidth 1000
16 #define TestCanvasHeight 600
17
18 using namespace skia::textlayout;
19 namespace {
20
21 SkScalar EPSILON100 = 0.01f;
22 SkScalar EPSILON50 = 0.02f;
23 SkScalar EPSILON20 = 0.05f;
24 SkScalar EPSILON5 = 0.20f;
25 SkScalar EPSILON2 = 0.50f;
26
equal(const char * base,TextRange a,const char * b)27 bool equal(const char* base, TextRange a, const char* b) {
28 return std::strncmp(b, base + a.start, a.width()) == 0;
29 }
30 class TestFontCollection : public FontCollection {
31 public:
TestFontCollection()32 TestFontCollection()
33 : fFontsFound(false)
34 , fResolvedFonts(0)
35 , fResourceDir(GetResourcePath("fonts").c_str())
36 , fFontProvider(sk_make_sp<TypefaceFontProvider>()) {
37 std::vector<SkString> fonts;
38 SkOSFile::Iter iter(fResourceDir.c_str());
39 SkString path;
40 while (iter.next(&path)) {
41 if (path.endsWith("Roboto-Italic.ttf")) {
42 fFontsFound = true;
43 }
44 fonts.emplace_back(path);
45 }
46
47 if (!fFontsFound) {
48 return;
49 }
50 // Only register fonts if we have to
51 for (auto& font : fonts) {
52 SkString file_path;
53 file_path.printf("%s/%s", fResourceDir.c_str(), font.c_str());
54 fFontProvider->registerTypeface(SkTypeface::MakeFromFile(file_path.c_str()));
55 }
56
57 this->setTestFontManager(std::move(fFontProvider));
58 this->disableFontFallback();
59
60 if (!fFontsFound) SkDebugf("Fonts not found, skipping all the tests\n");
61 }
62
63 ~TestFontCollection() = default;
64
resolvedFonts() const65 size_t resolvedFonts() const { return fResolvedFonts; }
66
67 // TODO: temp solution until we check in fonts
fontsFound() const68 bool fontsFound() const { return fFontsFound; }
69
70 private:
71 bool fFontsFound;
72 size_t fResolvedFonts;
73 std::string fResourceDir;
74 sk_sp<TypefaceFontProvider> fFontProvider;
75 };
76
77 class TestCanvas {
78 public:
TestCanvas(const char * testName)79 TestCanvas(const char* testName) : name(testName) {
80 bits.allocN32Pixels(TestCanvasWidth, TestCanvasHeight);
81 canvas = new SkCanvas(bits);
82 canvas->clear(SK_ColorWHITE);
83 }
84
~TestCanvas()85 ~TestCanvas() {
86 SkString path = SkOSPath::Join("/usr/local/google/home/jlavrova/Temp/skia/", name);
87 SkFILEWStream file(path.c_str());
88 if (!SkEncodeImage(&file, bits, SkEncodedImageFormat::kPNG, 100)) {
89 SkDebugf("Cannot write a picture %s\n", name);
90 }
91 delete canvas;
92 }
93
drawRects(SkColor color,std::vector<TextBox> & result,bool fill=false)94 void drawRects(SkColor color, std::vector<TextBox>& result, bool fill = false) {
95
96 SkPaint paint;
97 if (!fill) {
98 paint.setStyle(SkPaint::kStroke_Style);
99 paint.setAntiAlias(true);
100 paint.setStrokeWidth(1);
101 }
102 paint.setColor(color);
103 for (auto& r : result) {
104 canvas->drawRect(r.rect, paint);
105 }
106 }
107
drawLine(SkColor color,SkRect rect,bool vertical=true)108 void drawLine(SkColor color, SkRect rect, bool vertical = true) {
109
110 SkPaint paint;
111 paint.setStyle(SkPaint::kStroke_Style);
112 paint.setAntiAlias(true);
113 paint.setStrokeWidth(1);
114 paint.setColor(color);
115 if (vertical) {
116 canvas->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
117 } else {
118 canvas->drawLine(rect.fLeft, rect.fTop, rect.fRight, rect.fTop, paint);
119 }
120 }
121
drawLines(SkColor color,std::vector<TextBox> & result)122 void drawLines(SkColor color, std::vector<TextBox>& result) {
123
124 for (auto& r : result) {
125 drawLine(color, r.rect);
126 }
127 }
128
get()129 SkCanvas* get() { return canvas; }
130 private:
131 SkBitmap bits;
132 SkCanvas* canvas;
133 const char* name;
134 };
135
136 } // namespace
137
138 // Checked: NO DIFF
DEF_TEST(SkParagraph_SimpleParagraph,reporter)139 DEF_TEST(SkParagraph_SimpleParagraph, reporter) {
140 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
141 if (!fontCollection->fontsFound()) return;
142 const char* text = "Hello World Text Dialog";
143
144 ParagraphStyle paragraph_style;
145 paragraph_style.turnHintingOff();
146 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
147
148 TextStyle text_style;
149 text_style.setFontFamilies({SkString("Roboto")});
150 text_style.setColor(SK_ColorBLACK);
151 builder.pushStyle(text_style);
152 builder.addText(text);
153 builder.pop();
154
155 auto paragraph = builder.Build();
156 paragraph->layout(TestCanvasWidth);
157
158 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
159 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
160 REPORTER_ASSERT(reporter, impl->styles().size() == 1); // paragraph style does not count
161 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
162
163 size_t index = 0;
164 for (auto& line : impl->lines()) {
165 line.scanStyles(StyleType::kDecorations,
166 [&index, reporter](TextRange text, TextStyle style, SkScalar) {
167 REPORTER_ASSERT(reporter, index == 0);
168 REPORTER_ASSERT(reporter, style.getColor() == SK_ColorBLACK);
169 ++index;
170 return true;
171 });
172 }
173 }
174
DEF_TEST(SkParagraph_InlinePlaceholderParagraph,reporter)175 DEF_TEST(SkParagraph_InlinePlaceholderParagraph, reporter) { SkDebugf("Not implemented yet.\n"); }
DEF_TEST(SkParagraph_InlinePlaceholderBaselineParagraph,reporter)176 DEF_TEST(SkParagraph_InlinePlaceholderBaselineParagraph, reporter) {
177 SkDebugf("Not implemented yet.\n");
178 }
DEF_TEST(SkParagraph_InlinePlaceholderAboveBaselineParagraphh,reporter)179 DEF_TEST(SkParagraph_InlinePlaceholderAboveBaselineParagraphh, reporter) {
180 SkDebugf("Not implemented yet.\n");
181 }
DEF_TEST(SkParagraph_InlinePlaceholderBelowBaselineParagraph,reporter)182 DEF_TEST(SkParagraph_InlinePlaceholderBelowBaselineParagraph, reporter) {
183 SkDebugf("Not implemented yet.\n");
184 }
DEF_TEST(SkParagraph_InlinePlaceholderBottomParagraph,reporter)185 DEF_TEST(SkParagraph_InlinePlaceholderBottomParagraph, reporter) {
186 SkDebugf("Not implemented yet.\n");
187 }
DEF_TEST(SkParagraph_InlinePlaceholderTopParagraph,reporter)188 DEF_TEST(SkParagraph_InlinePlaceholderTopParagraph, reporter) {
189 SkDebugf("Not implemented yet.\n");
190 }
DEF_TEST(SkParagraph_InlinePlaceholderMiddleParagraph,reporter)191 DEF_TEST(SkParagraph_InlinePlaceholderMiddleParagraph, reporter) {
192 SkDebugf("Not implemented yet.\n");
193 }
DEF_TEST(SkParagraph_InlinePlaceholderIdeographicBaselineParagraphh,reporter)194 DEF_TEST(SkParagraph_InlinePlaceholderIdeographicBaselineParagraphh, reporter) {
195 SkDebugf("Not implemented yet.\n");
196 }
DEF_TEST(SkParagraph_InlinePlaceholderBreakParagraph,reporter)197 DEF_TEST(SkParagraph_InlinePlaceholderBreakParagraph, reporter) {
198 SkDebugf("Not implemented yet.\n");
199 }
DEF_TEST(SkParagraph_InlinePlaceholderGetRectsParagraph,reporter)200 DEF_TEST(SkParagraph_InlinePlaceholderGetRectsParagraph, reporter) {
201 SkDebugf("Not implemented yet.\n");
202 }
203
204 // Checked: NO DIFF
DEF_TEST(SkParagraph_SimpleRedParagraph,reporter)205 DEF_TEST(SkParagraph_SimpleRedParagraph, reporter) {
206 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
207 if (!fontCollection->fontsFound()) return;
208 const char* text = "I am RED";
209
210 ParagraphStyle paragraph_style;
211 paragraph_style.turnHintingOff();
212 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
213
214 TextStyle text_style;
215 text_style.setFontFamilies({SkString("Roboto")});
216 text_style.setColor(SK_ColorRED);
217 builder.pushStyle(text_style);
218 builder.addText(text);
219 builder.pop();
220
221 auto paragraph = builder.Build();
222 paragraph->layout(TestCanvasWidth);
223
224 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
225 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
226 REPORTER_ASSERT(reporter, impl->styles().size() == 1); // paragraph style does not count
227 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
228
229 size_t index = 0;
230 for (auto& line : impl->lines()) {
231 line.scanStyles(StyleType::kDecorations,
232 [&index, reporter](TextRange text, TextStyle style, SkScalar) {
233 REPORTER_ASSERT(reporter, index == 0);
234 REPORTER_ASSERT(reporter, style.getColor() == SK_ColorRED);
235 ++index;
236 return true;
237 });
238 }
239 }
240
241 // Checked: DIFF+ (Space between 1 & 2 style blocks)
DEF_TEST(SkParagraph_RainbowParagraph,reporter)242 DEF_TEST(SkParagraph_RainbowParagraph, reporter) {
243 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
244 TestCanvas canvas("SkParagraph_RainbowParagraph.png");
245 if (!fontCollection->fontsFound()) return;
246 const char* text1 = "Red Roboto"; // [0:10)
247 const char* text2 = "big Greeen Default"; // [10:28)
248 const char* text3 = "Defcolor Homemade Apple"; // [28:51)
249 const char* text4 = "Small Blue Roboto"; // [51:68)
250 const char* text41 = "Small Blue ";
251 const char* text5 =
252 "Continue Last Style With lots of words to check if it overlaps "
253 "properly or not"; // [68:)
254 const char* text42 =
255 "Roboto"
256 "Continue Last Style With lots of words to check if it overlaps "
257 "properly or not";
258
259 ParagraphStyle paragraph_style;
260 paragraph_style.turnHintingOff();
261 paragraph_style.setTextAlign(TextAlign::kLeft);
262 paragraph_style.setMaxLines(2);
263 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
264
265 TextStyle text_style1;
266 text_style1.setFontFamilies({SkString("Roboto")});
267
268 text_style1.setColor(SK_ColorRED);
269 builder.pushStyle(text_style1);
270 builder.addText(text1);
271
272 TextStyle text_style2;
273 text_style2.setFontFamilies({SkString("Roboto")});
274 text_style2.setFontSize(50);
275 text_style2.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
276 SkFontStyle::kUpright_Slant));
277 text_style2.setLetterSpacing(10);
278 text_style2.setDecorationColor(SK_ColorBLACK);
279 text_style2.setDecoration((TextDecoration)(
280 TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
281 text_style2.setWordSpacing(30);
282 text_style2.setColor(SK_ColorGREEN);
283 builder.pushStyle(text_style2);
284 builder.addText(text2);
285
286 TextStyle text_style3;
287 text_style3.setFontFamilies({SkString("Homemade Apple")});
288 builder.pushStyle(text_style3);
289 builder.addText(text3);
290
291 TextStyle text_style4;
292 text_style4.setFontFamilies({SkString("Roboto")});
293 text_style4.setFontSize(14);
294 text_style4.setDecorationColor(SK_ColorBLACK);
295 text_style4.setDecoration((TextDecoration)(
296 TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
297 text_style4.setColor(SK_ColorBLUE);
298 builder.pushStyle(text_style4);
299 builder.addText(text4);
300
301 builder.addText(text5);
302 builder.pop();
303
304 auto paragraph = builder.Build();
305 paragraph->layout(1000);
306 paragraph->paint(canvas.get(), 0, 0);
307
308 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
309 REPORTER_ASSERT(reporter, impl->runs().size() == 4);
310 REPORTER_ASSERT(reporter, impl->styles().size() == 4);
311 REPORTER_ASSERT(reporter, impl->lines().size() == 2);
312
313 auto rects = paragraph->getRectsForRange(0, impl->text().size(), RectHeightStyle::kMax, RectWidthStyle::kTight);
314 canvas.drawRects(SK_ColorMAGENTA, rects);
315
316 size_t index = 0;
317 impl->lines()[0].scanStyles(
318 StyleType::kAllAttributes, [&](TextRange text, TextStyle style, SkScalar) {
319 switch (index) {
320 case 0:
321 REPORTER_ASSERT(reporter, style.equals(text_style1));
322 REPORTER_ASSERT(reporter, equal(impl->text().begin(), text, text1));
323 break;
324 case 1:
325 REPORTER_ASSERT(reporter, style.equals(text_style2));
326 REPORTER_ASSERT(reporter, equal(impl->text().begin(), text, text2));
327 break;
328 case 2:
329 REPORTER_ASSERT(reporter, style.equals(text_style3));
330 REPORTER_ASSERT(reporter, equal(impl->text().begin(), text, text3));
331 break;
332 case 3:
333 REPORTER_ASSERT(reporter, style.equals(text_style4));
334 REPORTER_ASSERT(reporter, equal(impl->text().begin(), text, text41));
335 break;
336 default:
337 REPORTER_ASSERT(reporter, false);
338 break;
339 }
340 ++index;
341 return true;
342 });
343 impl->lines()[1].scanStyles(
344 StyleType::kAllAttributes, [&](TextRange text, TextStyle style, SkScalar) {
345 switch (index) {
346 case 4:
347 REPORTER_ASSERT(reporter, style.equals(text_style4));
348 REPORTER_ASSERT(reporter, equal(impl->text().begin(), text, text42));
349 break;
350 default:
351 REPORTER_ASSERT(reporter, false);
352 break;
353 }
354 ++index;
355 return true;
356 });
357 REPORTER_ASSERT(reporter, index == 5);
358 }
359
360 // Checked: NO DIFF
DEF_TEST(SkParagraph_DefaultStyleParagraph,reporter)361 DEF_TEST(SkParagraph_DefaultStyleParagraph, reporter) {
362 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
363 if (!fontCollection->fontsFound()) return;
364 TestCanvas canvas("SkParagraph_DefaultStyleParagraph.png");
365 const char* text = "No TextStyle! Uh Oh!";
366
367 ParagraphStyle paragraph_style;
368 TextStyle defaultStyle;
369 defaultStyle.setFontFamilies({SkString("Roboto")});
370 paragraph_style.setTextStyle(defaultStyle);
371 paragraph_style.turnHintingOff();
372 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
373 builder.addText(text);
374
375 auto paragraph = builder.Build();
376 paragraph->layout(TestCanvasWidth);
377 paragraph->paint(canvas.get(), 10.0, 15.0);
378
379 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
380
381 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
382 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
383 REPORTER_ASSERT(reporter, impl->lines().size() == 1);
384
385 size_t index = 0;
386 impl->lines()[0].scanStyles(
387 StyleType::kAllAttributes, [&](TextRange text1, TextStyle style, SkScalar) {
388 REPORTER_ASSERT(reporter, style.equals(paragraph_style.getTextStyle()));
389 REPORTER_ASSERT(reporter, equal(impl->text().begin(), text1, text));
390 ++index;
391 return true;
392 });
393 REPORTER_ASSERT(reporter, index == 1);
394 }
395
396 // Checked: NO DIFF
DEF_TEST(SkParagraph_BoldParagraph,reporter)397 DEF_TEST(SkParagraph_BoldParagraph, reporter) {
398 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
399 if (!fontCollection->fontsFound()) return;
400 TestCanvas canvas("SkParagraph_BoldParagraph.png");
401 const char* text = "This is Red max bold text!";
402
403 ParagraphStyle paragraph_style;
404 paragraph_style.turnHintingOff();
405 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
406
407 TextStyle text_style;
408 text_style.setFontFamilies({SkString("Roboto")});
409 text_style.setColor(SK_ColorRED);
410 text_style.setFontSize(60);
411 text_style.setLetterSpacing(0);
412 text_style.setFontStyle(SkFontStyle(SkFontStyle::kBlack_Weight, SkFontStyle::kNormal_Width,
413 SkFontStyle::kUpright_Slant));
414 builder.pushStyle(text_style);
415 builder.addText(text);
416 builder.pop();
417
418 auto paragraph = builder.Build();
419 paragraph->layout(VeryLongCanvasWidth);
420 paragraph->paint(canvas.get(), 10.0, 60.0);
421
422 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
423
424 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
425 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
426 REPORTER_ASSERT(reporter, impl->lines().size() == 1);
427
428 size_t index = 0;
429 impl->lines()[0].scanStyles(
430 StyleType::kAllAttributes, [&](TextRange text1, TextStyle style, SkScalar) {
431 REPORTER_ASSERT(reporter, style.equals(text_style));
432 REPORTER_ASSERT(reporter, equal(impl->text().begin(), text1, text));
433 ++index;
434 return true;
435 });
436 REPORTER_ASSERT(reporter, index == 1);
437 }
438
439 // Checked: NO DIFF (line height rounding error)
DEF_TEST(SkParagraph_HeightOverrideParagraph,reporter)440 DEF_TEST(SkParagraph_HeightOverrideParagraph, reporter) {
441 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
442 if (!fontCollection->fontsFound()) return;
443 TestCanvas canvas("SkParagraph_HeightOverrideParagraph.png");
444 const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
445
446 ParagraphStyle paragraph_style;
447 paragraph_style.turnHintingOff();
448 paragraph_style.setMaxLines(10);
449 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
450
451 TextStyle text_style;
452 text_style.setFontFamilies({SkString("Roboto")});
453 text_style.setFontSize(20);
454 text_style.setColor(SK_ColorBLACK);
455 text_style.setHeight(3.6345f);
456 text_style.setHeightOverride(true);
457 builder.pushStyle(text_style);
458 builder.addText(text);
459 builder.pop();
460
461 auto paragraph = builder.Build();
462 paragraph->layout(550);
463
464 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
465 REPORTER_ASSERT(reporter, impl->runs().size() == 3);
466 REPORTER_ASSERT(reporter, impl->styles().size() == 1); // paragraph style does not count
467 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
468
469 paragraph->paint(canvas.get(), 0, 0);
470
471 SkPaint paint;
472 paint.setStyle(SkPaint::kStroke_Style);
473 paint.setAntiAlias(true);
474 paint.setStrokeWidth(1);
475
476 // Tests for GetRectsForRange()
477 RectHeightStyle rect_height_style = RectHeightStyle::kIncludeLineSpacingMiddle;
478 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
479 paint.setColor(SK_ColorRED);
480 std::vector<TextBox> boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
481 canvas.drawRects(SK_ColorRED, boxes);
482 REPORTER_ASSERT(reporter, boxes.size() == 0ull);
483
484 boxes = paragraph->getRectsForRange(0, 40, rect_height_style, rect_width_style);
485 canvas.drawRects(SK_ColorBLUE, boxes);
486 REPORTER_ASSERT(reporter, boxes.size() == 3ull);
487
488 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.left(), 0, EPSILON100));
489 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.top(), 92.805f, EPSILON5));
490 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.right(), 43.843f, EPSILON100));
491 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.bottom(), 165.495f, EPSILON5));
492 }
493
494 // Checked: DIFF+
DEF_TEST(SkParagraph_LeftAlignParagraph,reporter)495 DEF_TEST(SkParagraph_LeftAlignParagraph, reporter) {
496 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
497 if (!fontCollection->fontsFound()) return;
498 TestCanvas canvas("SkParagraph_LeftAlignParagraph.png");
499 const char* text =
500 "This is a very long sentence to test if the text will properly wrap "
501 "around and go to the next line. Sometimes, short sentence. Longer "
502 "sentences are okay too because they are nessecary. Very short. "
503 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
504 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
505 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
506 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
507 "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
508 "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
509 "mollit anim id est laborum. "
510 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
511 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
512 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
513 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
514 "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
515 "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
516 "mollit anim id est laborum.";
517
518 ParagraphStyle paragraph_style;
519 paragraph_style.setMaxLines(14);
520 paragraph_style.setTextAlign(TextAlign::kLeft);
521 paragraph_style.turnHintingOff();
522 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
523
524 TextStyle text_style;
525 text_style.setFontFamilies({SkString("Roboto")});
526 text_style.setFontSize(26);
527 text_style.setLetterSpacing(1);
528 text_style.setWordSpacing(5);
529 text_style.setColor(SK_ColorBLACK);
530 text_style.setHeight(1);
531 text_style.setDecoration(TextDecoration::kUnderline);
532 text_style.setDecorationColor(SK_ColorBLACK);
533 builder.pushStyle(text_style);
534 builder.addText(text);
535 builder.pop();
536
537 auto paragraph = builder.Build();
538 paragraph->layout(TestCanvasWidth - 100);
539 paragraph->paint(canvas.get(), 0, 0);
540
541 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
542
543 REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
544 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
545 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
546 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
547 REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines());
548
549 double expected_y = 0;
550 double epsilon = 0.01f;
551 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, epsilon));
552 REPORTER_ASSERT(reporter,
553 SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, epsilon));
554 expected_y += 30;
555 REPORTER_ASSERT(reporter,
556 SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, epsilon));
557 expected_y += 30;
558 REPORTER_ASSERT(reporter,
559 SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, epsilon));
560 expected_y += 30;
561 REPORTER_ASSERT(reporter,
562 SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, epsilon));
563 expected_y += 30 * 10;
564 REPORTER_ASSERT(reporter,
565 SkScalarNearlyEqual(impl->lines()[13].offset().fY, expected_y, epsilon));
566
567 REPORTER_ASSERT(reporter,
568 paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
569
570 // Tests for GetGlyphPositionAtCoordinate()
571 REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(0, 0).position == 0);
572 REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(1, 1).position == 0);
573 REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(1, 35).position == 68);
574 REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(1, 70).position == 134);
575 REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(2000, 35).position == 134);
576 }
577
578 // Checked: NO DIFF
DEF_TEST(SkParagraph_RightAlignParagraph,reporter)579 DEF_TEST(SkParagraph_RightAlignParagraph, reporter) {
580 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
581 if (!fontCollection->fontsFound()) return;
582 TestCanvas canvas("SkParagraph_RightAlignParagraph.png");
583 const char* text =
584 "This is a very long sentence to test if the text will properly wrap "
585 "around and go to the next line. Sometimes, short sentence. Longer "
586 "sentences are okay too because they are nessecary. Very short. "
587 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
588 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
589 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
590 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
591 "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
592 "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
593 "mollit anim id est laborum. "
594 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
595 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
596 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
597 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
598 "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
599 "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
600 "mollit anim id est laborum.";
601
602 ParagraphStyle paragraph_style;
603 paragraph_style.setMaxLines(14);
604 paragraph_style.setTextAlign(TextAlign::kRight);
605 paragraph_style.turnHintingOff();
606 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
607
608 TextStyle text_style;
609 text_style.setFontFamilies({SkString("Roboto")});
610 text_style.setFontSize(26);
611 text_style.setLetterSpacing(1);
612 text_style.setWordSpacing(5);
613 text_style.setColor(SK_ColorBLACK);
614 text_style.setHeight(1);
615 text_style.setDecoration(TextDecoration::kUnderline);
616 text_style.setDecorationColor(SK_ColorBLACK);
617 builder.pushStyle(text_style);
618 builder.addText(text);
619 builder.pop();
620
621 auto paragraph = builder.Build();
622 paragraph->layout(TestCanvasWidth - 100);
623
624 paragraph->paint(canvas.get(), 0, 0);
625
626 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
627
628 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
629 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
630 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
631 REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines());
632
633 double expected_y = 0;
634 double epsilon = 0.01f;
635 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, epsilon));
636 REPORTER_ASSERT(reporter,
637 SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, epsilon));
638 expected_y += 30;
639 REPORTER_ASSERT(reporter,
640 SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, epsilon));
641 expected_y += 30;
642 REPORTER_ASSERT(reporter,
643 SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, epsilon));
644 expected_y += 30;
645 REPORTER_ASSERT(reporter,
646 SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, epsilon));
647 expected_y += 30 * 10;
648 REPORTER_ASSERT(reporter,
649 SkScalarNearlyEqual(impl->lines()[13].offset().fY, expected_y, epsilon));
650
651 auto calculate = [](const TextLine& line) -> SkScalar {
652 return TestCanvasWidth - 100 - line.offset().fX - line.width();
653 };
654
655 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[0]), 0, epsilon));
656 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[1]), 0, epsilon));
657 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[2]), 0, epsilon));
658 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[3]), 0, epsilon));
659 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[13]), 0, epsilon));
660
661 REPORTER_ASSERT(reporter,
662 paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
663 }
664
665 // Checked: NO DIFF
DEF_TEST(SkParagraph_CenterAlignParagraph,reporter)666 DEF_TEST(SkParagraph_CenterAlignParagraph, reporter) {
667 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
668 if (!fontCollection->fontsFound()) return;
669 TestCanvas canvas("SkParagraph_CenterAlignParagraph.png");
670 const char* text =
671 "This is a very long sentence to test if the text will properly wrap "
672 "around and go to the next line. Sometimes, short sentence. Longer "
673 "sentences are okay too because they are nessecary. Very short. "
674 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
675 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
676 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
677 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
678 "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
679 "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
680 "mollit anim id est laborum. "
681 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
682 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
683 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
684 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
685 "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
686 "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
687 "mollit anim id est laborum.";
688
689 ParagraphStyle paragraph_style;
690 paragraph_style.setMaxLines(14);
691 paragraph_style.setTextAlign(TextAlign::kCenter);
692 paragraph_style.turnHintingOff();
693 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
694
695 TextStyle text_style;
696 text_style.setFontFamilies({SkString("Roboto")});
697 text_style.setFontSize(26);
698 text_style.setLetterSpacing(1);
699 text_style.setWordSpacing(5);
700 text_style.setColor(SK_ColorBLACK);
701 text_style.setHeight(1);
702 text_style.setDecoration(TextDecoration::kUnderline);
703 text_style.setDecorationColor(SK_ColorBLACK);
704 builder.pushStyle(text_style);
705 builder.addText(text);
706 builder.pop();
707
708 auto paragraph = builder.Build();
709 paragraph->layout(TestCanvasWidth - 100);
710 paragraph->paint(canvas.get(), 0, 0);
711
712 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
713
714 REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
715 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
716 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
717 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
718 REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines());
719
720 double expected_y = 0;
721 double epsilon = 0.01f;
722 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, epsilon));
723 REPORTER_ASSERT(reporter,
724 SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, epsilon));
725 expected_y += 30;
726 REPORTER_ASSERT(reporter,
727 SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, epsilon));
728 expected_y += 30;
729 REPORTER_ASSERT(reporter,
730 SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, epsilon));
731 expected_y += 30;
732 REPORTER_ASSERT(reporter,
733 SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, epsilon));
734 expected_y += 30 * 10;
735 REPORTER_ASSERT(reporter,
736 SkScalarNearlyEqual(impl->lines()[13].offset().fY, expected_y, epsilon));
737
738 auto calculate = [](const TextLine& line) -> SkScalar {
739 return TestCanvasWidth - 100 - (line.offset().fX * 2 + line.width());
740 };
741
742 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[0]), 0, epsilon));
743 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[1]), 0, epsilon));
744 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[2]), 0, epsilon));
745 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[3]), 0, epsilon));
746 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[13]), 0, epsilon));
747
748 REPORTER_ASSERT(reporter,
749 paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
750 }
751
752 // Checked: NO DIFF
DEF_TEST(SkParagraph_JustifyAlignParagraph,reporter)753 DEF_TEST(SkParagraph_JustifyAlignParagraph, reporter) {
754 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
755 if (!fontCollection->fontsFound()) return;
756 TestCanvas canvas("SkParagraph_JustifyAlignParagraph.png");
757 const char* text =
758 "This is a very long sentence to test if the text will properly wrap "
759 "around and go to the next line. Sometimes, short sentence. Longer "
760 "sentences are okay too because they are nessecary. Very short. "
761 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
762 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
763 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
764 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
765 "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
766 "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
767 "mollit anim id est laborum. "
768 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
769 "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
770 "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
771 "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
772 "velit esse cillum dolore eu fugiat.";
773
774 ParagraphStyle paragraph_style;
775 paragraph_style.setMaxLines(14);
776 paragraph_style.setTextAlign(TextAlign::kJustify);
777 paragraph_style.turnHintingOff();
778 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
779
780 TextStyle text_style;
781 text_style.setFontFamilies({SkString("Roboto")});
782 text_style.setFontSize(26);
783 text_style.setLetterSpacing(0);
784 text_style.setWordSpacing(5);
785 text_style.setColor(SK_ColorBLACK);
786 text_style.setHeight(1);
787 text_style.setDecoration(TextDecoration::kUnderline);
788 text_style.setDecorationColor(SK_ColorBLACK);
789 builder.pushStyle(text_style);
790 builder.addText(text);
791 builder.pop();
792
793 auto paragraph = builder.Build();
794 paragraph->layout(TestCanvasWidth - 100);
795 paragraph->paint(canvas.get(), 0, 0);
796
797 RectHeightStyle rect_height_style = RectHeightStyle::kMax;
798 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
799 auto boxes = paragraph->getRectsForRange(0, 100, rect_height_style, rect_width_style);
800 canvas.drawRects(SK_ColorRED, boxes);
801
802 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
803
804 REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
805 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
806 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
807 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
808
809 double expected_y = 0;
810 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, EPSILON100));
811 REPORTER_ASSERT(reporter,
812 SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, EPSILON100));
813 expected_y += 30;
814 REPORTER_ASSERT(reporter,
815 SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, EPSILON100));
816 expected_y += 30;
817 REPORTER_ASSERT(reporter,
818 SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, EPSILON100));
819 expected_y += 30;
820 REPORTER_ASSERT(reporter,
821 SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, EPSILON100));
822 expected_y += 30 * 9;
823 REPORTER_ASSERT(reporter,
824 SkScalarNearlyEqual(impl->lines()[12].offset().fY, expected_y, EPSILON100));
825
826 auto calculate = [](const TextLine& line) -> SkScalar {
827 return TestCanvasWidth - 100 - (line.offset().fX + line.width());
828 };
829
830 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[0]), 0, EPSILON100));
831 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[1]), 0, EPSILON100));
832 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[2]), 0, EPSILON100));
833 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[3]), 0, EPSILON100));
834 REPORTER_ASSERT(reporter, calculate(impl->lines()[13]) > 0);
835
836 REPORTER_ASSERT(reporter,
837 paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
838 }
839
840 // Checked: DIFF (ghost spaces as a separate box in TxtLib)
DEF_TEST(SkParagraph_JustifyRTL,reporter)841 DEF_TEST(SkParagraph_JustifyRTL, reporter) {
842 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
843 if (!fontCollection->fontsFound()) return;
844 TestCanvas canvas("SkParagraph_JustifyRTL.png");
845 const char* text =
846 "אאא בּבּבּבּ אאאא בּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ "
847 "אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ "
848 "אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ";
849
850 ParagraphStyle paragraph_style;
851 paragraph_style.setMaxLines(14);
852 paragraph_style.setTextAlign(TextAlign::kJustify);
853 paragraph_style.turnHintingOff();
854 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
855
856 TextStyle text_style;
857 text_style.setFontFamilies({SkString("Ahem")});
858 text_style.setFontSize(26);
859 text_style.setColor(SK_ColorBLACK);
860 builder.pushStyle(text_style);
861 builder.addText(text);
862 builder.pop();
863
864 auto paragraph = builder.Build();
865 paragraph->layout(TestCanvasWidth - 100);
866 paragraph->paint(canvas.get(), 0, 0);
867
868 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
869
870 auto calculate = [](const TextLine& line) -> SkScalar {
871 return TestCanvasWidth - 100 - line.width();
872 };
873 for (auto& line : impl->lines()) {
874 if (&line == &impl->lines().back()) {
875 REPORTER_ASSERT(reporter, calculate(line) > EPSILON100);
876 } else {
877 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(line), 0, EPSILON100));
878 }
879 }
880
881 // Just make sure the the text is actually RTL
882 for (auto& run : impl->runs()) {
883 REPORTER_ASSERT(reporter, !run.leftToRight());
884 }
885
886 // Tests for GetRectsForRange()
887 RectHeightStyle rect_height_style = RectHeightStyle::kMax;
888 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
889 auto boxes = paragraph->getRectsForRange(0, 100, rect_height_style, rect_width_style);
890 canvas.drawRects(SK_ColorRED, boxes);
891 REPORTER_ASSERT(reporter, boxes.size() == 3); // DIFF
892
893 boxes = paragraph->getRectsForRange(240, 250, rect_height_style, rect_width_style);
894 canvas.drawRects(SK_ColorBLUE, boxes);
895 REPORTER_ASSERT(reporter, boxes.size() == 1);
896
897 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 588, EPSILON100));
898 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 130, EPSILON100));
899 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 640, EPSILON100));
900 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 156, EPSILON100));
901 }
902
903 // Checked: NO DIFF (some minor decoration differences, probably)
DEF_TEST(SkParagraph_DecorationsParagraph,reporter)904 DEF_TEST(SkParagraph_DecorationsParagraph, reporter) {
905 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
906 if (!fontCollection->fontsFound()) return;
907 TestCanvas canvas("SkParagraph_DecorationsParagraph.png");
908 ParagraphStyle paragraph_style;
909 paragraph_style.setMaxLines(14);
910 paragraph_style.setTextAlign(TextAlign::kLeft);
911 paragraph_style.turnHintingOff();
912 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
913
914 TextStyle text_style;
915 text_style.setFontFamilies({SkString("Roboto")});
916 text_style.setFontSize(26);
917 text_style.setLetterSpacing(0);
918 text_style.setWordSpacing(5);
919 text_style.setColor(SK_ColorBLACK);
920 text_style.setHeight(2);
921 text_style.setDecoration(TextDecoration::kUnderline);
922 text_style.setDecorationColor(SK_ColorBLACK);
923 text_style.setDecoration((TextDecoration)(
924 TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
925 text_style.setDecorationStyle(TextDecorationStyle::kSolid);
926 text_style.setDecorationColor(SK_ColorBLACK);
927 text_style.setDecorationThicknessMultiplier(2.0);
928 builder.pushStyle(text_style);
929 builder.addText("This text should be");
930
931 text_style.setDecorationStyle(TextDecorationStyle::kDouble);
932 text_style.setDecorationColor(SK_ColorBLUE);
933 text_style.setDecorationThicknessMultiplier(1.0);
934 builder.pushStyle(text_style);
935 builder.addText(" decorated even when");
936
937 text_style.setDecorationStyle(TextDecorationStyle::kDotted);
938 text_style.setDecorationColor(SK_ColorBLACK);
939 builder.pushStyle(text_style);
940 builder.addText(" wrapped around to");
941
942 text_style.setDecorationStyle(TextDecorationStyle::kDashed);
943 text_style.setDecorationColor(SK_ColorBLACK);
944 text_style.setDecorationThicknessMultiplier(3.0);
945 builder.pushStyle(text_style);
946 builder.addText(" the next line.");
947
948 text_style.setDecorationStyle(TextDecorationStyle::kWavy);
949 text_style.setDecorationColor(SK_ColorRED);
950 text_style.setDecorationThicknessMultiplier(1.0);
951 builder.pushStyle(text_style);
952 builder.addText(" Otherwise, bad things happen.");
953 builder.pop();
954
955 auto paragraph = builder.Build();
956 paragraph->layout(TestCanvasWidth - 100);
957 paragraph->paint(canvas.get(), 0, 0);
958
959 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
960
961 size_t index = 0;
962 for (auto& line : impl->lines()) {
963 line.scanStyles(
964 StyleType::kDecorations, [&index, reporter](TextRange, TextStyle style, SkScalar) {
965 auto decoration = (TextDecoration)(TextDecoration::kUnderline |
966 TextDecoration::kOverline |
967 TextDecoration::kLineThrough);
968 REPORTER_ASSERT(reporter, style.getDecorationType() == decoration);
969 switch (index) {
970 case 0:
971 REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
972 TextDecorationStyle::kSolid);
973 REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLACK);
974 REPORTER_ASSERT(reporter,
975 style.getDecorationThicknessMultiplier() == 2.0);
976 break;
977 case 1: // The style appears on 2 lines so it has 2 pieces
978 REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
979 TextDecorationStyle::kDouble);
980 REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLUE);
981 REPORTER_ASSERT(reporter,
982 style.getDecorationThicknessMultiplier() == 1.0);
983 break;
984 case 2:
985 REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
986 TextDecorationStyle::kDotted);
987 REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLACK);
988 REPORTER_ASSERT(reporter,
989 style.getDecorationThicknessMultiplier() == 1.0);
990 break;
991 case 3:
992 case 4:
993 REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
994 TextDecorationStyle::kDashed);
995 REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLACK);
996 REPORTER_ASSERT(reporter,
997 style.getDecorationThicknessMultiplier() == 3.0);
998 break;
999 case 5:
1000 REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
1001 TextDecorationStyle::kWavy);
1002 REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorRED);
1003 REPORTER_ASSERT(reporter,
1004 style.getDecorationThicknessMultiplier() == 1.0);
1005 break;
1006 default:
1007 REPORTER_ASSERT(reporter, false);
1008 break;
1009 }
1010 ++index;
1011 return true;
1012 });
1013 }
1014 }
1015
1016 // TODO: Fix decorations
DEF_TEST(SkParagraph_WavyDecorationParagraph,reporter)1017 DEF_TEST(SkParagraph_WavyDecorationParagraph, reporter) {
1018 SkDebugf("Not implemented yet.\n");
1019 }
1020
1021 // Checked: NO DIFF
DEF_TEST(SkParagraph_ItalicsParagraph,reporter)1022 DEF_TEST(SkParagraph_ItalicsParagraph, reporter) {
1023 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1024 if (!fontCollection->fontsFound()) return;
1025 TestCanvas canvas("SkParagraph_ItalicsParagraph.png");
1026 ParagraphStyle paragraph_style;
1027 paragraph_style.turnHintingOff();
1028 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1029
1030 TextStyle text_style;
1031 text_style.setFontFamilies({SkString("Roboto")});
1032 text_style.setFontSize(10);
1033 text_style.setColor(SK_ColorRED);
1034 builder.pushStyle(text_style);
1035 builder.addText("No italic ");
1036
1037 text_style.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
1038 SkFontStyle::kItalic_Slant));
1039 builder.pushStyle(text_style);
1040 builder.addText("Yes Italic ");
1041 builder.pop();
1042 builder.addText("No Italic again.");
1043
1044 auto paragraph = builder.Build();
1045 paragraph->layout(TestCanvasWidth);
1046 paragraph->paint(canvas.get(), 0, 0);
1047
1048 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
1049
1050 REPORTER_ASSERT(reporter, impl->runs().size() == 3);
1051 REPORTER_ASSERT(reporter, impl->styles().size() == 3);
1052 REPORTER_ASSERT(reporter, impl->lines().size() == 1);
1053 auto& line = impl->lines()[0];
1054 size_t index = 0;
1055 line.scanStyles(
1056 StyleType::kForeground,
1057 [&index, reporter](TextRange textRange, TextStyle style, SkScalar) {
1058 switch (index) {
1059 case 0:
1060 REPORTER_ASSERT(
1061 reporter,
1062 style.getFontStyle().slant() == SkFontStyle::kUpright_Slant);
1063 break;
1064 case 1:
1065 REPORTER_ASSERT(reporter,
1066 style.getFontStyle().slant() == SkFontStyle::kItalic_Slant);
1067 break;
1068 case 2:
1069 REPORTER_ASSERT(
1070 reporter,
1071 style.getFontStyle().slant() == SkFontStyle::kUpright_Slant);
1072 break;
1073 default:
1074 REPORTER_ASSERT(reporter, false);
1075 break;
1076 }
1077 ++index;
1078 return true;
1079 });
1080 }
1081
1082 // Checked: NO DIFF
DEF_TEST(SkParagraph_ChineseParagraph,reporter)1083 DEF_TEST(SkParagraph_ChineseParagraph, reporter) {
1084 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1085 if (!fontCollection->fontsFound()) return;
1086 TestCanvas canvas("SkParagraph_ChineseParagraph.png");
1087 const char* text =
1088 "左線読設重説切後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
1089 "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得庭"
1090 "際輝求佐抗蒼提夜合逃表。注統天言件自謙雅載報紙喪。作画稿愛器灯女書利変探"
1091 "訃第金線朝開化建。子戦年帝励害表月幕株漠新期刊人秘。図的海力生禁挙保天戦"
1092 "聞条年所在口。";
1093
1094 ParagraphStyle paragraph_style;
1095 paragraph_style.setMaxLines(14);
1096 paragraph_style.setTextAlign(TextAlign::kJustify);
1097 paragraph_style.turnHintingOff();
1098 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1099
1100 auto decoration = (TextDecoration)(TextDecoration::kUnderline | TextDecoration::kOverline |
1101 TextDecoration::kLineThrough);
1102
1103 TextStyle text_style;
1104 text_style.setFontFamilies({SkString("Source Han Serif CN")});
1105 text_style.setFontSize(35);
1106 text_style.setColor(SK_ColorBLACK);
1107 text_style.setLetterSpacing(2);
1108 text_style.setHeight(1);
1109 text_style.setDecoration(decoration);
1110 text_style.setDecorationColor(SK_ColorBLACK);
1111 text_style.setDecorationStyle(TextDecorationStyle::kSolid);
1112 builder.pushStyle(text_style);
1113 builder.addText(text);
1114 builder.pop();
1115
1116 auto paragraph = builder.Build();
1117 paragraph->layout(TestCanvasWidth - 100);
1118 paragraph->paint(canvas.get(), 0, 0);
1119
1120 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
1121
1122 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
1123 REPORTER_ASSERT(reporter, impl->lines().size() == 7);
1124 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
1125 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
1126 }
1127
1128 // Checked: NO DIFF (disabled)
DEF_TEST(SkParagraph_ArabicParagraph,reporter)1129 DEF_TEST(SkParagraph_ArabicParagraph, reporter) {
1130 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1131 if (!fontCollection->fontsFound()) return;
1132 TestCanvas canvas("SkParagraph_ArabicParagraph.png");
1133 const char* text =
1134 "من أسر وإعلان الخاصّة وهولندا،, عل قائمة الضغوط بالمطالبة تلك. الصفحة "
1135 "بمباركة التقليدية قام عن. تصفح";
1136
1137 ParagraphStyle paragraph_style;
1138 paragraph_style.setMaxLines(14);
1139 paragraph_style.setTextAlign(TextAlign::kJustify);
1140 paragraph_style.turnHintingOff();
1141 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1142
1143 auto decoration = (TextDecoration)(TextDecoration::kUnderline | TextDecoration::kOverline |
1144 TextDecoration::kLineThrough);
1145
1146 TextStyle text_style;
1147 text_style.setFontFamilies({SkString("Katibeh")});
1148 text_style.setFontSize(35);
1149 text_style.setColor(SK_ColorBLACK);
1150 text_style.setLetterSpacing(2);
1151 text_style.setDecoration(decoration);
1152 text_style.setDecorationColor(SK_ColorBLACK);
1153 text_style.setDecorationStyle(TextDecorationStyle::kSolid);
1154 builder.pushStyle(text_style);
1155 builder.addText(text);
1156 builder.pop();
1157
1158 auto paragraph = builder.Build();
1159 paragraph->layout(TestCanvasWidth - 100);
1160 paragraph->paint(canvas.get(), 0, 0);
1161
1162 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
1163
1164 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
1165 REPORTER_ASSERT(reporter, impl->lines().size() == 2);
1166 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
1167 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
1168 }
1169
1170 // Checked: DIFF (2 boxes and each space is a word)
DEF_TEST(SkParagraph_ArabicRectsParagraph,reporter)1171 DEF_TEST(SkParagraph_ArabicRectsParagraph, reporter) {
1172
1173 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1174 if (!fontCollection->fontsFound()) return;
1175 TestCanvas canvas("SkParagraph_ArabicRectsParagraph.png");
1176 const char* text = "بمباركة التقليدية قام عن. تصفح يد ";
1177
1178 ParagraphStyle paragraph_style;
1179 paragraph_style.turnHintingOff();
1180 paragraph_style.setMaxLines(14);
1181 paragraph_style.setTextAlign(TextAlign::kRight);
1182 paragraph_style.setTextDirection(TextDirection::kRtl);
1183 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1184
1185 TextStyle text_style;
1186 text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
1187 text_style.setFontSize(26);
1188 text_style.setWordSpacing(5);
1189 text_style.setColor(SK_ColorBLACK);
1190 text_style.setDecoration(TextDecoration::kUnderline);
1191 text_style.setDecorationColor(SK_ColorBLACK);
1192 builder.pushStyle(text_style);
1193 builder.addText(text);
1194 builder.pop();
1195
1196 auto paragraph = builder.Build();
1197 paragraph->layout(TestCanvasWidth - 100);
1198
1199 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
1200 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
1201
1202 paragraph->paint(canvas.get(), 0, 0);
1203
1204 RectHeightStyle rect_height_style = RectHeightStyle::kMax;
1205 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
1206 std::vector<TextBox> boxes = paragraph->getRectsForRange(0, 100, rect_height_style, rect_width_style);
1207 canvas.drawRects(SK_ColorRED, boxes);
1208
1209 REPORTER_ASSERT(reporter, boxes.size() == 1ull);
1210
1211 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 538.548f, EPSILON100)); // DIFF: 510.09375
1212 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.268f, EPSILON100));
1213 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 900, EPSILON100));
1214 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 44, EPSILON100));
1215 }
1216
1217 // Checked DIFF+
DEF_TEST(SkParagraph_ArabicRectsLTRLeftAlignParagraph,reporter)1218 DEF_TEST(SkParagraph_ArabicRectsLTRLeftAlignParagraph, reporter) {
1219
1220 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1221 if (!fontCollection->fontsFound()) return;
1222 TestCanvas canvas("SkParagraph_ArabicRectsLTRLeftAlignParagraph.png");
1223 const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
1224
1225 ParagraphStyle paragraph_style;
1226 paragraph_style.turnHintingOff();
1227 paragraph_style.setMaxLines(14);
1228 paragraph_style.setTextAlign(TextAlign::kLeft);
1229 paragraph_style.setTextDirection(TextDirection::kLtr);
1230 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1231
1232 TextStyle text_style;
1233 text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
1234 text_style.setFontSize(26);
1235 text_style.setWordSpacing(5);
1236 text_style.setColor(SK_ColorBLACK);
1237 text_style.setDecoration(TextDecoration::kUnderline);
1238 text_style.setDecorationColor(SK_ColorBLACK);
1239 builder.pushStyle(text_style);
1240 builder.addText(text);
1241 builder.pop();
1242
1243 auto paragraph = builder.Build();
1244 paragraph->layout(TestCanvasWidth - 100);
1245
1246 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
1247 REPORTER_ASSERT(reporter, impl->runs().size() == 3);
1248
1249 paragraph->paint(canvas.get(), 0, 0);
1250
1251 RectHeightStyle rect_height_style = RectHeightStyle::kMax;
1252 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
1253 std::vector<TextBox> boxes = paragraph->getRectsForRange(36, 40, rect_height_style, rect_width_style);
1254 canvas.drawRects(SK_ColorRED, boxes);
1255
1256 REPORTER_ASSERT(reporter, boxes.size() == 2ull); // DIFF: 1
1257 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 83.916f, EPSILON100)); // DIFF: 89.40625
1258 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.268f, EPSILON100));
1259 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 110.155f, EPSILON100)); // DIFF: 121.87891
1260 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 44, EPSILON100));
1261
1262 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.left(), 422.414f, EPSILON100));
1263 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.top(), -0.268f, EPSILON100));
1264 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.right(), 428.152f, EPSILON100));
1265 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.bottom(), 44, EPSILON100));
1266 }
1267
1268 // Checked DIFF+
DEF_TEST(SkParagraph_ArabicRectsLTRRightAlignParagraph,reporter)1269 DEF_TEST(SkParagraph_ArabicRectsLTRRightAlignParagraph, reporter) {
1270
1271 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1272 if (!fontCollection->fontsFound()) return;
1273 TestCanvas canvas("SkParagraph_ArabicRectsLTRRightAlignParagraph.png");
1274 const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
1275
1276 ParagraphStyle paragraph_style;
1277 paragraph_style.turnHintingOff();
1278 paragraph_style.setMaxLines(14);
1279 paragraph_style.setTextAlign(TextAlign::kRight);
1280 paragraph_style.setTextDirection(TextDirection::kLtr);
1281 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1282
1283 TextStyle text_style;
1284 text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
1285 text_style.setFontSize(26);
1286 text_style.setWordSpacing(5);
1287 text_style.setColor(SK_ColorBLACK);
1288 text_style.setDecoration(TextDecoration::kUnderline);
1289 text_style.setDecorationColor(SK_ColorBLACK);
1290 builder.pushStyle(text_style);
1291 builder.addText(text);
1292 builder.pop();
1293
1294 auto paragraph = builder.Build();
1295 paragraph->layout(TestCanvasWidth - 100);
1296
1297 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
1298 REPORTER_ASSERT(reporter, impl->runs().size() == 3);
1299
1300 paragraph->paint(canvas.get(), 0, 0);
1301
1302 RectHeightStyle rect_height_style = RectHeightStyle::kMax;
1303 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
1304 std::vector<TextBox> boxes =
1305 paragraph->getRectsForRange(36, 40, rect_height_style, rect_width_style);
1306 canvas.drawRects(SK_ColorRED, boxes);
1307
1308 REPORTER_ASSERT(reporter, boxes.size() == 2ull);
1309 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 561.501f, EPSILON100)); // DIFF
1310 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.268f, EPSILON100));
1311 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 587.741f, EPSILON100)); // DIFF
1312 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 44, EPSILON100));
1313
1314 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.left(), 900, EPSILON100)); // DIFF
1315 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.top(), -0.268f, EPSILON100));
1316 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.right(), 905.738f, EPSILON100)); // DIFF
1317 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.bottom(), 44, EPSILON100));
1318 }
1319
1320 // Checked: NO DIFF
DEF_TEST(SkParagraph_GetGlyphPositionAtCoordinateParagraph,reporter)1321 DEF_TEST(SkParagraph_GetGlyphPositionAtCoordinateParagraph, reporter) {
1322 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1323 if (!fontCollection->fontsFound()) return;
1324 TestCanvas canvas("SkParagraph_GetGlyphPositionAtCoordinateParagraph.png");
1325 const char* text =
1326 "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
1327 "67890 12345";
1328
1329 ParagraphStyle paragraphStyle;
1330 paragraphStyle.setTextAlign(TextAlign::kLeft);
1331 paragraphStyle.setMaxLines(10);
1332 paragraphStyle.turnHintingOff();
1333 TextStyle textStyle;
1334 textStyle.setFontFamilies({SkString("Roboto")});
1335 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
1336 SkFontStyle::kUpright_Slant));
1337 textStyle.setFontSize(50);
1338 textStyle.setLetterSpacing(1);
1339 textStyle.setWordSpacing(5);
1340 textStyle.setHeight(1);
1341 textStyle.setColor(SK_ColorBLACK);
1342
1343 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1344 builder.pushStyle(textStyle);
1345 builder.addText(text);
1346 builder.pop();
1347
1348 auto paragraph = builder.Build();
1349 paragraph->layout(550);
1350 paragraph->paint(canvas.get(), 0, 0);
1351
1352 // Tests for getGlyphPositionAtCoordinate()
1353 // NOTE: resulting values can be a few off from their respective positions in
1354 // the original text because the final trailing whitespaces are sometimes not
1355 // drawn (namely, when using "justify" alignment) and therefore are not active
1356 // glyphs.
1357 REPORTER_ASSERT(reporter,
1358 paragraph->getGlyphPositionAtCoordinate(-10000, -10000).position == 0);
1359 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(-1, -1).position == 0);
1360 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(0, 0).position == 0);
1361 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(3, 3).position == 0);
1362 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(35, 1).position == 1);
1363 REPORTER_ASSERT(reporter,
1364 paragraph->getGlyphPositionAtCoordinate(300, 2).position == 11);
1365 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(301, 2.2f).position == 11);
1366 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(302, 2.6f).position == 11);
1367 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(301, 2.1f).position == 11);
1368 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(100000, 20).position == 18);
1369 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(450, 20).position == 16);
1370 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(100000, 90).position == 36);
1371 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(-100000, 90).position == 18);
1372 REPORTER_ASSERT(reporter,
1373 paragraph->getGlyphPositionAtCoordinate(20, -80).position == 1);
1374 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(1, 90).position == 18);
1375 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(1, 170).position == 36);
1376 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(10000, 180).position == 72);
1377 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(70, 180).position == 56);
1378 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(1, 270).position == 72);
1379 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(35, 90).position == 19);
1380 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(10000, 10000).position == 77);
1381 REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(85, 10000).position == 75);
1382 }
1383
1384 // Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeParagraph,reporter)1385 DEF_TEST(SkParagraph_GetRectsForRangeParagraph, reporter) {
1386 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1387 if (!fontCollection->fontsFound()) return;
1388 TestCanvas canvas("SkParagraph_GetRectsForRangeParagraph.png");
1389 const char* text =
1390 "12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
1391 "67890 12345";
1392
1393 ParagraphStyle paragraphStyle;
1394 paragraphStyle.setTextAlign(TextAlign::kLeft);
1395 paragraphStyle.setMaxLines(10);
1396 paragraphStyle.turnHintingOff();
1397 TextStyle textStyle;
1398 textStyle.setFontFamilies({SkString("Roboto")});
1399 textStyle.setFontSize(50);
1400 textStyle.setColor(SK_ColorBLACK);
1401 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1402 SkFontStyle::kUpright_Slant));
1403
1404 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1405 builder.pushStyle(textStyle);
1406 builder.addText(text);
1407 builder.pop();
1408
1409 auto paragraph = builder.Build();
1410 paragraph->layout(550);
1411 paragraph->paint(canvas.get(), 0, 0);
1412
1413 RectHeightStyle heightStyle = RectHeightStyle::kMax;
1414 RectWidthStyle widthStyle = RectWidthStyle::kTight;
1415
1416 SkPaint paint;
1417 paint.setStyle(SkPaint::kStroke_Style);
1418 paint.setAntiAlias(true);
1419 paint.setStrokeWidth(1);
1420
1421 {
1422 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
1423 REPORTER_ASSERT(reporter, result.empty());
1424 }
1425 {
1426 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
1427 canvas.drawRects(SK_ColorRED, result);
1428 REPORTER_ASSERT(reporter, result.size() == 1);
1429 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
1430 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
1431 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 28.417f, EPSILON100));
1432 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
1433 }
1434 {
1435 auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
1436 canvas.drawRects(SK_ColorBLUE, result);
1437 REPORTER_ASSERT(reporter, result.size() == 1);
1438 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 56.835f, EPSILON100));
1439 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
1440 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 177.97f, EPSILON100));
1441 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
1442 }
1443 {
1444 auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
1445 canvas.drawRects(SK_ColorGREEN, result);
1446 REPORTER_ASSERT(reporter, result.size() == 1);
1447 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 177.97f, EPSILON100));
1448 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
1449 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 507.031f, EPSILON100));
1450 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
1451 }
1452 {
1453 auto result = paragraph->getRectsForRange(30, 100, heightStyle, widthStyle);
1454 canvas.drawRects(SK_ColorRED, result);
1455 REPORTER_ASSERT(reporter, result.size() == 4);
1456 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 211.375f, EPSILON100));
1457 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.40625f, EPSILON100));
1458 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 463.623f, EPSILON100));
1459 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, EPSILON100));
1460 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 0, EPSILON100));
1461 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 236.406f, EPSILON100));
1462 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 142.089f, EPSILON100));
1463 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 295, EPSILON100));
1464 }
1465 {
1466 auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
1467 canvas.drawRects(SK_ColorBLUE, result);
1468 REPORTER_ASSERT(reporter, result.size() == 1);
1469 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 450.1875f, EPSILON100));
1470 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
1471 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 519.47266f, EPSILON100));
1472 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
1473 }
1474 {
1475 auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
1476 REPORTER_ASSERT(reporter, result.empty());
1477 }
1478 }
1479
1480 // Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeTight,reporter)1481 DEF_TEST(SkParagraph_GetRectsForRangeTight, reporter) {
1482 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1483 if (!fontCollection->fontsFound()) return;
1484 TestCanvas canvas("SkParagraph_GetRectsForRangeTight.png");
1485 const char* text =
1486 "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1487 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1488 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
1489
1490 ParagraphStyle paragraphStyle;
1491 paragraphStyle.setTextAlign(TextAlign::kLeft);
1492 paragraphStyle.setMaxLines(10);
1493 paragraphStyle.turnHintingOff();
1494 TextStyle textStyle;
1495 textStyle.setFontFamilies({SkString("Noto Sans CJK JP")});
1496 textStyle.setFontSize(50);
1497 textStyle.setColor(SK_ColorBLACK);
1498 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1499 SkFontStyle::kUpright_Slant));
1500
1501 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1502 builder.pushStyle(textStyle);
1503 builder.addText(text);
1504 builder.pop();
1505
1506 auto paragraph = builder.Build();
1507 paragraph->layout(550);
1508 paragraph->paint(canvas.get(), 0, 0);
1509
1510 RectHeightStyle heightStyle = RectHeightStyle::kTight;
1511 RectWidthStyle widthStyle = RectWidthStyle::kTight;
1512 {
1513 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
1514 REPORTER_ASSERT(reporter, result.empty());
1515 }
1516 {
1517 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
1518 canvas.drawRects(SK_ColorRED, result);
1519 REPORTER_ASSERT(reporter, result.size() == 1);
1520 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
1521 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, EPSILON100));
1522 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 16.898f, EPSILON100));
1523 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, EPSILON100));
1524 }
1525 {
1526 auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
1527 canvas.drawRects(SK_ColorBLUE, result);
1528 REPORTER_ASSERT(reporter, result.size() == 1);
1529 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 66.899f, EPSILON100));
1530 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, EPSILON100));
1531 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 264.099f, EPSILON100));
1532 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, EPSILON100));
1533 }
1534 {
1535 auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
1536 canvas.drawRects(SK_ColorGREEN, result);
1537 REPORTER_ASSERT(reporter, result.size() == 2);
1538 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 264.099f, EPSILON100));
1539 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, EPSILON100));
1540 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 595.085f, EPSILON50));
1541 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, EPSILON100));
1542 }
1543 }
1544
1545 // Checked: DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingMiddle,reporter)1546 DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingMiddle, reporter) {
1547 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1548 if (!fontCollection->fontsFound()) return;
1549 TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeLineSpacingMiddle.png");
1550 const char* text =
1551 "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1552 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1553 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
1554
1555 ParagraphStyle paragraphStyle;
1556 paragraphStyle.setTextAlign(TextAlign::kLeft);
1557 paragraphStyle.setMaxLines(10);
1558 paragraphStyle.turnHintingOff();
1559 TextStyle textStyle;
1560 textStyle.setFontFamilies({SkString("Roboto")});
1561 textStyle.setFontSize(50);
1562 textStyle.setHeight(1.6f);
1563 textStyle.setHeightOverride(true);
1564 textStyle.setColor(SK_ColorBLACK);
1565 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1566 SkFontStyle::kUpright_Slant));
1567
1568 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1569 builder.pushStyle(textStyle);
1570 builder.addText(text);
1571 builder.pop();
1572
1573 auto paragraph = builder.Build();
1574 paragraph->layout(550);
1575 paragraph->paint(canvas.get(), 0, 0);
1576
1577 RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingMiddle;
1578 RectWidthStyle widthStyle = RectWidthStyle::kMax;
1579 {
1580 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
1581 REPORTER_ASSERT(reporter, result.empty());
1582 }
1583
1584 {
1585 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
1586 canvas.drawRects(SK_ColorRED, result);
1587 REPORTER_ASSERT(reporter, result.size() == 1);
1588 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
1589 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1590 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 17.4296889f, EPSILON100));
1591 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
1592 }
1593 {
1594 auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
1595 canvas.drawRects(SK_ColorBLUE, result);
1596 REPORTER_ASSERT(reporter, result.size() == 1);
1597 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 67.429688f, EPSILON100));
1598 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1599 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 190.00781f, EPSILON100));
1600 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
1601 }
1602 {
1603 auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
1604 canvas.drawRects(SK_ColorGREEN, result);
1605 REPORTER_ASSERT(reporter, result.size() == 1);
1606 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
1607 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1608 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 508.0625f, EPSILON50));
1609 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
1610 }
1611 {
1612 auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle);
1613 canvas.drawRects(SK_ColorRED, result);
1614 REPORTER_ASSERT(reporter, result.size() == 8);
1615
1616 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
1617 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 88.473305f, EPSILON100));
1618 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 525.687f, EPSILON20));
1619 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 168.47331f, EPSILON100));
1620
1621 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 525.687f, EPSILON20));
1622 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 88.473305f, EPSILON100));
1623 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
1624 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 168.47331f, EPSILON100));
1625
1626 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.left(), 0, EPSILON100));
1627 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.top(), 168.47331f, EPSILON100));
1628 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.right(), 531.574f, EPSILON50));
1629 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.bottom(), 248.47331f, EPSILON100));
1630
1631 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 531.574f, EPSILON50));
1632 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 168.47331f, EPSILON100));
1633 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 570.02344f, EPSILON20));
1634 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 248.47331f, EPSILON100));
1635
1636 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.left(), 0, EPSILON100));
1637 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.top(), 248.47331f, EPSILON100));
1638 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.right(), 570.02344f, EPSILON20));
1639 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.bottom(), 328.47333f, EPSILON100));
1640
1641 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.left(), 0, EPSILON100));
1642 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.top(), 328.47333f, EPSILON100));
1643 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.right(), 570.02344f, EPSILON20));
1644 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.bottom(), 408.4733f, EPSILON100));
1645 }
1646 {
1647 auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
1648 canvas.drawRects(SK_ColorBLUE, result);
1649 REPORTER_ASSERT(reporter, result.size() == 2); // DIFF
1650 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 463.72656f, EPSILON50));
1651 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1652 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 530.23047f, EPSILON50));
1653 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
1654
1655 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 530.23047f, EPSILON50));
1656 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 16.946615f, EPSILON100));
1657 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
1658 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 88.473305f, EPSILON100));
1659 }
1660 {
1661 auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
1662 REPORTER_ASSERT(reporter, result.empty());
1663 }
1664 }
1665
1666 // Checked: NO DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingTop,reporter)1667 DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingTop, reporter) {
1668 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1669 if (!fontCollection->fontsFound()) return;
1670 TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeLineSpacingTop.png");
1671 const char* text =
1672 "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1673 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1674 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
1675
1676 ParagraphStyle paragraphStyle;
1677 paragraphStyle.setTextAlign(TextAlign::kLeft);
1678 paragraphStyle.setMaxLines(10);
1679 paragraphStyle.turnHintingOff();
1680 TextStyle textStyle;
1681 textStyle.setFontFamilies({SkString("Roboto")});
1682 textStyle.setFontSize(50);
1683 textStyle.setHeight(1.6f);
1684 textStyle.setHeightOverride(true);
1685 textStyle.setColor(SK_ColorBLACK);
1686 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1687 SkFontStyle::kUpright_Slant));
1688
1689 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1690 builder.pushStyle(textStyle);
1691 builder.addText(text);
1692 builder.pop();
1693
1694 auto paragraph = builder.Build();
1695 paragraph->layout(550);
1696 paragraph->paint(canvas.get(), 0, 0);
1697
1698 RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingTop;
1699 RectWidthStyle widthStyle = RectWidthStyle::kMax;
1700 {
1701 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
1702 REPORTER_ASSERT(reporter, result.empty());
1703 }
1704
1705 {
1706 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
1707 canvas.drawRects(SK_ColorRED, result);
1708 REPORTER_ASSERT(reporter, result.size() == 1);
1709 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
1710 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1711 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 17.4296889f, EPSILON100));
1712 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
1713 }
1714 {
1715 auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
1716 canvas.drawRects(SK_ColorBLUE, result);
1717 REPORTER_ASSERT(reporter, result.size() == 1);
1718 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 67.429688f, EPSILON100));
1719 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1720 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 190.00781f, EPSILON100));
1721 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
1722 }
1723 {
1724 auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
1725 canvas.drawRects(SK_ColorGREEN, result);
1726 REPORTER_ASSERT(reporter, result.size() == 1);
1727 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
1728 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1729 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 508.0625f, EPSILON50));
1730 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
1731 }
1732 {
1733 auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle);
1734 canvas.drawRects(SK_ColorMAGENTA, result);
1735 REPORTER_ASSERT(reporter, result.size() == 8);
1736
1737 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
1738 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 80, EPSILON100));
1739 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 525.687f, EPSILON20));
1740 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 160, EPSILON100));
1741
1742 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 525.687f, EPSILON20));
1743 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 80, EPSILON100));
1744 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
1745 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 160, EPSILON100));
1746
1747 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.left(), 0, EPSILON100));
1748 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.top(), 160, EPSILON100));
1749 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.right(), 531.574f, EPSILON20));
1750 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.bottom(), 240, EPSILON100));
1751
1752 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 531.574f, EPSILON20));
1753 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 160, EPSILON100));
1754 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 570.02344f, EPSILON20));
1755 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 240, EPSILON100));
1756
1757 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.left(), 0, EPSILON100));
1758 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.top(), 240, EPSILON100));
1759 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.right(), 570.02344f, EPSILON20));
1760 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.bottom(), 320, EPSILON100));
1761
1762 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.left(), 0, EPSILON100));
1763 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.top(), 320, EPSILON100));
1764 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.right(), 570.02344f, EPSILON20));
1765 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.bottom(), 400, EPSILON100));
1766 }
1767 {
1768 auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
1769 canvas.drawRects(SK_ColorBLACK, result);
1770 REPORTER_ASSERT(reporter, result.size() == 2); // DIFF
1771 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 463.72656f, EPSILON50));
1772 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
1773 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 530.23047f, EPSILON50));
1774 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
1775
1776 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 530.23047f, EPSILON50));
1777 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 16.946615f, EPSILON100));
1778 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
1779 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 80, EPSILON100));
1780 }
1781 {
1782 auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
1783 REPORTER_ASSERT(reporter, result.empty());
1784 }
1785 }
1786
1787 // Checked: NO DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingBottom,reporter)1788 DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingBottom, reporter) {
1789 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1790 if (!fontCollection->fontsFound()) return;
1791 TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeLineSpacingBottom.png");
1792 const char* text =
1793 "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1794 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1795 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
1796
1797 ParagraphStyle paragraphStyle;
1798 paragraphStyle.setTextAlign(TextAlign::kLeft);
1799 paragraphStyle.setMaxLines(10);
1800 paragraphStyle.turnHintingOff();
1801 TextStyle textStyle;
1802 textStyle.setFontFamilies({SkString("Roboto")});
1803 textStyle.setFontSize(50);
1804 textStyle.setHeight(1.6f);
1805 textStyle.setHeightOverride(true);
1806 textStyle.setColor(SK_ColorBLACK);
1807 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1808 SkFontStyle::kUpright_Slant));
1809
1810 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1811 builder.pushStyle(textStyle);
1812 builder.addText(text);
1813 builder.pop();
1814
1815 auto paragraph = builder.Build();
1816 paragraph->layout(550);
1817 paragraph->paint(canvas.get(), 0, 0);
1818
1819 RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingBottom;
1820 RectWidthStyle widthStyle = RectWidthStyle::kMax;
1821 {
1822 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
1823 REPORTER_ASSERT(reporter, result.empty());
1824 }
1825
1826 {
1827 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
1828 canvas.drawRects(SK_ColorRED, result);
1829 REPORTER_ASSERT(reporter, result.size() == 1);
1830 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
1831 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
1832 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 17.429f, EPSILON100));
1833 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
1834 }
1835 {
1836 auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
1837 canvas.drawRects(SK_ColorBLUE, result);
1838 REPORTER_ASSERT(reporter, result.size() == 1);
1839 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 67.4298f, EPSILON100));
1840 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
1841 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 190.007f, EPSILON100));
1842 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
1843 }
1844 {
1845 auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
1846 canvas.drawRects(SK_ColorGREEN, result);
1847 REPORTER_ASSERT(reporter, result.size() == 1);
1848 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.007f, EPSILON100));
1849 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
1850 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 508.062f, EPSILON50));
1851 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
1852 }
1853 {
1854 auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle);
1855 canvas.drawRects(SK_ColorMAGENTA, result);
1856 REPORTER_ASSERT(reporter, result.size() == 8);
1857
1858 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.007f, EPSILON100));
1859 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 96.946f, EPSILON100));
1860 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 525.687f, EPSILON20));
1861 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 176.946f, EPSILON100));
1862
1863 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 525.687f, EPSILON20));
1864 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 96.946f, EPSILON100));
1865 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.023f, EPSILON20));
1866 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 176.946f, EPSILON100));
1867
1868 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.left(), 0, EPSILON100));
1869 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.top(), 176.946f, EPSILON100));
1870 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.right(), 531.574f, EPSILON20));
1871 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.bottom(), 256.946f, EPSILON100));
1872
1873 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 531.574f, EPSILON20));
1874 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 176.946f, EPSILON100));
1875 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 570.023f, EPSILON20));
1876 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 256.946f, EPSILON100));
1877
1878 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.left(), 0, EPSILON100));
1879 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.top(), 256.946f, EPSILON100));
1880 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.right(), 570.023f, EPSILON20));
1881 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.bottom(), 336.946f, EPSILON100));
1882
1883 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.left(), 0, EPSILON100));
1884 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.top(), 336.946f, EPSILON100));
1885 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.right(), 570.023f, EPSILON20));
1886 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.bottom(), 416.946f, EPSILON100));
1887 }
1888 {
1889 auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
1890 canvas.drawRects(SK_ColorBLACK, result);
1891 REPORTER_ASSERT(reporter, result.size() == 2); // DIFF
1892 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 463.726f, EPSILON50));
1893 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
1894 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 530.230f, EPSILON50));
1895 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
1896
1897 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 530.230f, EPSILON50));
1898 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 16.946f, EPSILON100));
1899 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.023f, EPSILON20));
1900 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 96.946f, EPSILON100));
1901 }
1902 {
1903 auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
1904 REPORTER_ASSERT(reporter, result.empty());
1905 }
1906 }
1907
1908 // Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeIncludeCombiningCharacter,reporter)1909 DEF_TEST(SkParagraph_GetRectsForRangeIncludeCombiningCharacter, reporter) {
1910 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1911 if (!fontCollection->fontsFound()) return;
1912 TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeCombiningCharacter.png");
1913 const char* text = "ดีสวัสดีชาวโลกที่น่ารัก";
1914 ParagraphStyle paragraphStyle;
1915 paragraphStyle.setTextAlign(TextAlign::kLeft);
1916 paragraphStyle.setMaxLines(10);
1917 paragraphStyle.turnHintingOff();
1918 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1919
1920 TextStyle textStyle;
1921 textStyle.setFontFamilies({SkString("Roboto")});
1922 textStyle.setFontSize(50);
1923 textStyle.setLetterSpacing(1);
1924 textStyle.setWordSpacing(5);
1925 textStyle.setHeight(1);
1926 textStyle.setColor(SK_ColorBLACK);
1927
1928 builder.pushStyle(textStyle);
1929 builder.addText(text);
1930 builder.pop();
1931
1932 auto paragraph = builder.Build();
1933 paragraph->layout(TestCanvasWidth - 100);
1934 paragraph->paint(canvas.get(), 0, 0);
1935
1936 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
1937 REPORTER_ASSERT(reporter, impl->lines().size() == 1);
1938
1939 RectHeightStyle heightStyle = RectHeightStyle::kTight;
1940 RectWidthStyle widthStyle = RectWidthStyle::kTight;
1941 {
1942 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
1943 REPORTER_ASSERT(reporter, result.empty());
1944 }
1945 {
1946 auto first = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
1947 auto second = paragraph->getRectsForRange(1, 2, heightStyle, widthStyle);
1948 auto last = paragraph->getRectsForRange(0, 2, heightStyle, widthStyle);
1949 REPORTER_ASSERT(reporter, first.size() == 0 && second.size() == 1 && last.size() == 1);
1950 REPORTER_ASSERT(reporter, second[0].rect == last[0].rect);
1951 }
1952 {
1953 auto first = paragraph->getRectsForRange(3, 4, heightStyle, widthStyle);
1954 auto second = paragraph->getRectsForRange(4, 5, heightStyle, widthStyle);
1955 auto last = paragraph->getRectsForRange(3, 5, heightStyle, widthStyle);
1956 REPORTER_ASSERT(reporter, first.size() == 0 && second.size() == 1 && last.size() == 1);
1957 REPORTER_ASSERT(reporter, second[0].rect == last[0].rect);
1958 }
1959 {
1960 auto first = paragraph->getRectsForRange(14, 15, heightStyle, widthStyle);
1961 auto second = paragraph->getRectsForRange(15, 16, heightStyle, widthStyle);
1962 auto third = paragraph->getRectsForRange(16, 17, heightStyle, widthStyle);
1963 auto last = paragraph->getRectsForRange(14, 17, heightStyle, widthStyle);
1964 REPORTER_ASSERT(reporter, first.size() == 0 && second.size() == 0 &&
1965 third.size() == 1 && last.size() == 1);
1966 REPORTER_ASSERT(reporter, third[0].rect == last[0].rect);
1967 }
1968 }
1969
1970 // Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraph,reporter)1971 DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraph, reporter) {
1972 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
1973 if (!fontCollection->fontsFound()) return;
1974 TestCanvas canvas("SkParagraph_GetRectsForRangeCenterParagraph.png");
1975 // Minikin uses a hard coded list of unicode characters that he treats as invisible - as spaces.
1976 // It's absolutely wrong - invisibility is a glyph attribute, not character/grapheme.
1977 // Any attempt to substitute one for another leads to errors
1978 // (for instance, some fonts can use these hard coded characters for something that is visible)
1979 const char* text = "01234 "; // includes ideographic space and english space.
1980
1981 ParagraphStyle paragraphStyle;
1982 paragraphStyle.setTextAlign(TextAlign::kCenter);
1983 paragraphStyle.setMaxLines(10);
1984 paragraphStyle.turnHintingOff();
1985 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1986
1987 TextStyle textStyle;
1988 textStyle.setFontFamilies({SkString("Roboto")});
1989 textStyle.setFontSize(50);
1990 textStyle.setHeight(1);
1991 textStyle.setColor(SK_ColorBLACK);
1992 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1993 SkFontStyle::kUpright_Slant));
1994
1995 builder.pushStyle(textStyle);
1996 builder.addText(text);
1997 builder.pop();
1998
1999 auto paragraph = builder.Build();
2000 paragraph->layout(550);
2001 paragraph->paint(canvas.get(), 0, 0);
2002
2003 // Some of the formatting lazily done on paint
2004 RectHeightStyle heightStyle = RectHeightStyle::kMax;
2005 RectWidthStyle widthStyle = RectWidthStyle::kTight;
2006 {
2007 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
2008 REPORTER_ASSERT(reporter, result.empty());
2009 }
2010
2011 {
2012 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
2013 canvas.drawRects(SK_ColorRED, result);
2014 REPORTER_ASSERT(reporter, result.size() == 1);
2015 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 203.955f, EPSILON100));
2016 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
2017 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 232.373f, EPSILON100));
2018 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
2019 }
2020
2021 {
2022 auto result = paragraph->getRectsForRange(2, 4, heightStyle, widthStyle);
2023 canvas.drawRects(SK_ColorBLUE, result);
2024 REPORTER_ASSERT(reporter, result.size() == 1);
2025 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 260.791f, EPSILON100));
2026 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
2027 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 317.626f, EPSILON100));
2028 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
2029 }
2030
2031 {
2032 auto result = paragraph->getRectsForRange(4, 5, heightStyle, widthStyle);
2033 canvas.drawRects(SK_ColorGREEN, result);
2034 REPORTER_ASSERT(reporter, result.size() == 1);
2035 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 317.626f, EPSILON100));
2036 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
2037 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 346.044f, EPSILON100));
2038 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
2039 }
2040
2041 {
2042 auto result = paragraph->getRectsForRange(4, 6, heightStyle, widthStyle);
2043 canvas.drawRects(SK_ColorBLACK, result);
2044 REPORTER_ASSERT(reporter, result.size() == 1); // DIFF
2045 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 317.626f, EPSILON100));
2046 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
2047 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, EPSILON100));
2048 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
2049 }
2050
2051 {
2052 auto result = paragraph->getRectsForRange(5, 6, heightStyle, widthStyle);
2053 canvas.drawRects(SK_ColorRED, result);
2054 REPORTER_ASSERT(reporter, result.size() == 1);
2055 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 346.044f, EPSILON100));
2056 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
2057 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, EPSILON100));
2058 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
2059 }
2060
2061 {
2062 auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
2063 REPORTER_ASSERT(reporter, result.empty());
2064 }
2065 }
2066
2067 // Checked DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraphNewlineCentered,reporter)2068 DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraphNewlineCentered, reporter) {
2069 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2070 if (!fontCollection->fontsFound()) return;
2071 TestCanvas canvas("SkParagraph_GetRectsForRangeCenterParagraphNewlineCentered.png");
2072 const char* text = "01234\n";
2073
2074 ParagraphStyle paragraphStyle;
2075 paragraphStyle.setTextAlign(TextAlign::kCenter);
2076 paragraphStyle.setMaxLines(10);
2077 paragraphStyle.turnHintingOff();
2078 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
2079
2080 TextStyle textStyle;
2081 textStyle.setFontFamilies({SkString("Roboto")});
2082 textStyle.setFontSize(50);
2083 textStyle.setHeight(1);
2084 textStyle.setColor(SK_ColorBLACK);
2085 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
2086 SkFontStyle::kUpright_Slant));
2087
2088 builder.pushStyle(textStyle);
2089 builder.addText(text);
2090 builder.pop();
2091
2092 auto paragraph = builder.Build();
2093 paragraph->layout(550);
2094
2095 paragraph->paint(canvas.get(), 0, 0);
2096
2097 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2098 REPORTER_ASSERT(reporter, impl->lines().size() == 2);
2099
2100 RectHeightStyle heightStyle = RectHeightStyle::kMax;
2101 RectWidthStyle widthStyle = RectWidthStyle::kTight;
2102 {
2103 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
2104 REPORTER_ASSERT(reporter, result.empty());
2105 }
2106
2107 {
2108 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
2109 REPORTER_ASSERT(reporter, result.size() == 1);
2110 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 203.955f, EPSILON100));
2111 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
2112 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 232.373f, EPSILON100));
2113 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
2114 }
2115
2116 {
2117 auto result = paragraph->getRectsForRange(6, 7, heightStyle, widthStyle);
2118 canvas.drawRects(SK_ColorBLUE, result);
2119 REPORTER_ASSERT(reporter, result.size() == 1);
2120 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 275.0f, EPSILON100));
2121 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.406f, EPSILON100));
2122 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 275.0f, EPSILON100));
2123 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, EPSILON100));
2124 }
2125 }
2126
2127 // Checked NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeCenterMultiLineParagraph,reporter)2128 DEF_TEST(SkParagraph_GetRectsForRangeCenterMultiLineParagraph, reporter) {
2129 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2130 if (!fontCollection->fontsFound()) return;
2131 TestCanvas canvas("SkParagraph_GetRectsForRangeCenterMultiLineParagraph.png");
2132 const char* text = "01234 \n0123 "; // includes ideographic space and english space.
2133
2134 ParagraphStyle paragraphStyle;
2135 paragraphStyle.setTextAlign(TextAlign::kCenter);
2136 paragraphStyle.setMaxLines(10);
2137 paragraphStyle.turnHintingOff();
2138 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
2139
2140 TextStyle textStyle;
2141 textStyle.setFontFamilies({SkString("Roboto")});
2142 textStyle.setFontSize(50);
2143 textStyle.setHeight(1);
2144 textStyle.setColor(SK_ColorBLACK);
2145 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
2146 SkFontStyle::kUpright_Slant));
2147
2148 builder.pushStyle(textStyle);
2149 builder.addText(text);
2150 builder.pop();
2151
2152 auto paragraph = builder.Build();
2153 paragraph->layout(550);
2154
2155 paragraph->paint(canvas.get(), 0, 0);
2156
2157 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2158
2159 REPORTER_ASSERT(reporter, impl->lines().size() == 2);
2160
2161 RectHeightStyle heightStyle = RectHeightStyle::kMax;
2162 RectWidthStyle widthStyle = RectWidthStyle::kTight;
2163 SkScalar epsilon = 0.01f;
2164 {
2165 auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
2166 REPORTER_ASSERT(reporter, result.empty());
2167 }
2168 {
2169 auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
2170 canvas.drawRects(SK_ColorRED, result);
2171 REPORTER_ASSERT(reporter, result.size() == 1);
2172 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 203.955f, epsilon));
2173 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
2174 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 232.373f, epsilon));
2175 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
2176 }
2177 {
2178 auto result = paragraph->getRectsForRange(2, 4, heightStyle, widthStyle);
2179 canvas.drawRects(SK_ColorBLUE, result);
2180 REPORTER_ASSERT(reporter, result.size() == 1);
2181 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 260.791f, epsilon));
2182 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
2183 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 317.626f, epsilon));
2184 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
2185 }
2186 {
2187 auto result = paragraph->getRectsForRange(4, 6, heightStyle, widthStyle);
2188 canvas.drawRects(SK_ColorGREEN, result);
2189 REPORTER_ASSERT(reporter, result.size() == 1);
2190 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 317.626f, epsilon));
2191 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
2192 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, epsilon));
2193 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
2194 }
2195 {
2196 auto result = paragraph->getRectsForRange(5, 6, heightStyle, widthStyle);
2197 canvas.drawRects(SK_ColorYELLOW, result);
2198 REPORTER_ASSERT(reporter, result.size() == 1);
2199 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 346.044f, epsilon));
2200 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
2201 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, epsilon));
2202 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
2203 }
2204 {
2205 auto result = paragraph->getRectsForRange(10, 12, heightStyle, widthStyle);
2206 canvas.drawRects(SK_ColorCYAN, result);
2207 REPORTER_ASSERT(reporter, result.size() == 1);
2208 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 218.164f, epsilon));
2209 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.40625f, epsilon));
2210 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 275, epsilon));
2211 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, epsilon));
2212 }
2213 {
2214 auto result = paragraph->getRectsForRange(14, 18, heightStyle, widthStyle);
2215 canvas.drawRects(SK_ColorBLACK, result);
2216 REPORTER_ASSERT(reporter, result.size() == 1);
2217 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 331.835f, epsilon));
2218 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.40625f, epsilon));
2219 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 419.189f, epsilon));
2220 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, epsilon));
2221 }
2222 {
2223 auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
2224 REPORTER_ASSERT(reporter, result.empty());
2225 }
2226 }
2227
2228 // Checked: DIFF (line height rounding error)
DEF_TEST(SkParagraph_GetRectsForRangeStrut,reporter)2229 DEF_TEST(SkParagraph_GetRectsForRangeStrut, reporter) {
2230 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2231 if (!fontCollection->fontsFound()) return;
2232 TestCanvas canvas("SkParagraph_GetRectsForRangeStrut.png");
2233 const char* text = "Chinese 字典";
2234
2235 StrutStyle strutStyle;
2236 strutStyle.setStrutEnabled(true);
2237 strutStyle.setFontFamilies({SkString("Roboto")});
2238 strutStyle.setFontSize(14.0);
2239
2240 ParagraphStyle paragraphStyle;
2241 paragraphStyle.setStrutStyle(strutStyle);
2242
2243 TextStyle textStyle;
2244 textStyle.setFontFamilies({SkString("Noto Sans CJK JP")});
2245 textStyle.setFontSize(20);
2246 textStyle.setColor(SK_ColorBLACK);
2247
2248 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
2249 builder.pushStyle(textStyle);
2250 builder.addText(text);
2251 builder.pop();
2252
2253 auto paragraph = builder.Build();
2254 paragraph->layout(550);
2255 paragraph->paint(canvas.get(), 0, 0);
2256
2257 {
2258 auto result = paragraph->getRectsForRange(0, 10, RectHeightStyle::kTight, RectWidthStyle::kMax);
2259 canvas.drawRects(SK_ColorGREEN, result);
2260 REPORTER_ASSERT(reporter, result.size() == 1);
2261 }
2262
2263 {
2264 auto result = paragraph->getRectsForRange(0, 10, RectHeightStyle::kStrut, RectWidthStyle::kMax);
2265 canvas.drawRects(SK_ColorRED, result);
2266 REPORTER_ASSERT(reporter, result.size() == 1);
2267 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
2268 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 10.611f, EPSILON2));
2269 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 118.605f, EPSILON50));
2270 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 27.017f, EPSILON2));
2271 }
2272 }
2273
2274 // Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeStrutFallback,reporter)2275 DEF_TEST(SkParagraph_GetRectsForRangeStrutFallback, reporter) {
2276 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2277 if (!fontCollection->fontsFound()) return;
2278 TestCanvas canvas("SkParagraph_GetRectsForRangeStrutFallback.png");
2279 const char* text = "Chinese 字典";
2280
2281 StrutStyle strutStyle;
2282 strutStyle.setStrutEnabled(false);
2283
2284 ParagraphStyle paragraphStyle;
2285 paragraphStyle.setStrutStyle(strutStyle);
2286
2287 TextStyle textStyle;
2288 textStyle.setFontFamilies({SkString("Noto Sans CJK JP")});
2289 textStyle.setFontSize(20);
2290 textStyle.setColor(SK_ColorBLACK);
2291
2292 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
2293 builder.pushStyle(textStyle);
2294 builder.addText(text);
2295 builder.pop();
2296
2297 auto paragraph = builder.Build();
2298 paragraph->layout(550);
2299 paragraph->paint(canvas.get(), 0, 0);
2300
2301
2302 auto result1 = paragraph->getRectsForRange(0, 10, RectHeightStyle::kTight, RectWidthStyle::kMax);
2303 canvas.drawRects(SK_ColorGREEN, result1);
2304 REPORTER_ASSERT(reporter, result1.size() == 1);
2305
2306 auto result2 = paragraph->getRectsForRange(0, 10, RectHeightStyle::kStrut, RectWidthStyle::kMax);
2307 canvas.drawRects(SK_ColorRED, result2);
2308 REPORTER_ASSERT(reporter, result2.size() == 1);
2309
2310 REPORTER_ASSERT(reporter, result1[0].rect == result2[0].rect);
2311 }
2312
2313 // Checked: DIFF (small in numbers)
DEF_TEST(SkParagraph_GetWordBoundaryParagraph,reporter)2314 DEF_TEST(SkParagraph_GetWordBoundaryParagraph, reporter) {
2315 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2316 if (!fontCollection->fontsFound()) return;
2317 TestCanvas canvas("SkParagraph_GetWordBoundaryParagraph.png");
2318 ParagraphStyle paragraphStyle;
2319 paragraphStyle.setTextAlign(TextAlign::kLeft);
2320 paragraphStyle.setMaxLines(10);
2321 paragraphStyle.turnHintingOff();
2322 TextStyle textStyle;
2323 textStyle.setFontFamilies({SkString("Roboto")});
2324 textStyle.setFontSize(52);
2325 textStyle.setLetterSpacing(1.19039f);
2326 textStyle.setWordSpacing(5);
2327 textStyle.setHeight(1.5);
2328 textStyle.setHeightOverride(true);
2329 textStyle.setColor(SK_ColorBLACK);
2330
2331 ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
2332 builder.pushStyle(textStyle);
2333 builder.addText(
2334 "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345");
2335 builder.pop();
2336
2337 auto paragraph = builder.Build();
2338 paragraph->layout(550);
2339 paragraph->paint(canvas.get(), 0, 0);
2340
2341 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(0) == SkRange<size_t>(0, 5));
2342 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(1) == SkRange<size_t>(0, 5));
2343 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(2) == SkRange<size_t>(0, 5));
2344 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(3) == SkRange<size_t>(0, 5));
2345 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(4) == SkRange<size_t>(0, 5));
2346 auto boxes = paragraph->getRectsForRange(5, 6, RectHeightStyle::kMax, RectWidthStyle::kTight);
2347 canvas.drawLines(SK_ColorRED, boxes);
2348
2349 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(5) == SkRange<size_t>(5, 7));
2350 boxes = paragraph->getRectsForRange(6, 7, RectHeightStyle::kMax, RectWidthStyle::kTight);
2351 canvas.drawLines(SK_ColorRED, boxes);
2352
2353 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(6) == SkRange<size_t>(5, 7));
2354 boxes = paragraph->getRectsForRange(7, 8, RectHeightStyle::kMax, RectWidthStyle::kTight);
2355 canvas.drawLines(SK_ColorRED, boxes);
2356
2357 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(7) == SkRange<size_t>(7, 12));
2358 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(8) == SkRange<size_t>(7, 12));
2359 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(9) == SkRange<size_t>(7, 12));
2360 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(10) == SkRange<size_t>(7, 12));
2361 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(11) == SkRange<size_t>(7, 12));
2362 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(12) == SkRange<size_t>(12, 13));
2363 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(13) == SkRange<size_t>(13, 18));
2364 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(30) == SkRange<size_t>(30, 31));
2365
2366 boxes = paragraph->getRectsForRange(12, 13, RectHeightStyle::kMax, RectWidthStyle::kTight);
2367 canvas.drawLines(SK_ColorRED, boxes);
2368 boxes = paragraph->getRectsForRange(13, 14, RectHeightStyle::kMax, RectWidthStyle::kTight);
2369 canvas.drawLines(SK_ColorRED, boxes);
2370 boxes = paragraph->getRectsForRange(18, 19, RectHeightStyle::kMax, RectWidthStyle::kTight);
2371 canvas.drawLines(SK_ColorRED, boxes);
2372 boxes = paragraph->getRectsForRange(19, 20, RectHeightStyle::kMax, RectWidthStyle::kTight);
2373 canvas.drawLines(SK_ColorRED, boxes);
2374 boxes = paragraph->getRectsForRange(24, 25, RectHeightStyle::kMax, RectWidthStyle::kTight);
2375 canvas.drawLines(SK_ColorRED, boxes);
2376 boxes = paragraph->getRectsForRange(25, 26, RectHeightStyle::kMax, RectWidthStyle::kTight);
2377 canvas.drawLines(SK_ColorRED, boxes);
2378 boxes = paragraph->getRectsForRange(30, 31, RectHeightStyle::kMax, RectWidthStyle::kTight);
2379 canvas.drawLines(SK_ColorRED, boxes);
2380 boxes = paragraph->getRectsForRange(31, 32, RectHeightStyle::kMax, RectWidthStyle::kTight);
2381 canvas.drawLines(SK_ColorRED, boxes);
2382
2383 auto len = static_cast<ParagraphImpl*>(paragraph.get())->text().size();
2384 REPORTER_ASSERT(reporter, paragraph->getWordBoundary(len - 1) == SkRange<size_t>(len - 5, len));
2385 }
2386
2387 // Checked: DIFF (unclear)
DEF_TEST(SkParagraph_SpacingParagraph,reporter)2388 DEF_TEST(SkParagraph_SpacingParagraph, reporter) {
2389 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2390 if (!fontCollection->fontsFound()) return;
2391 TestCanvas canvas("SkParagraph_SpacingParagraph.png");
2392 ParagraphStyle paragraph_style;
2393 paragraph_style.setMaxLines(10);
2394 paragraph_style.setTextAlign(TextAlign::kLeft);
2395 paragraph_style.turnHintingOff();
2396 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2397
2398 TextStyle text_style;
2399 text_style.setFontFamilies({SkString("Roboto")});
2400 text_style.setFontSize(50);
2401 text_style.setLetterSpacing(20);
2402 text_style.setWordSpacing(0);
2403 text_style.setColor(SK_ColorBLACK);
2404 builder.pushStyle(text_style);
2405 builder.addText("H");
2406 builder.pop();
2407
2408 text_style.setLetterSpacing(10);
2409 text_style.setWordSpacing(0);
2410 builder.pushStyle(text_style);
2411 builder.addText("H");
2412 builder.pop();
2413
2414 text_style.setLetterSpacing(20);
2415 text_style.setWordSpacing(0);
2416 builder.pushStyle(text_style);
2417 builder.addText("H");
2418 builder.pop();
2419
2420 text_style.setLetterSpacing(0);
2421 text_style.setWordSpacing(0);
2422 builder.pushStyle(text_style);
2423 builder.addText("|");
2424 builder.pop();
2425
2426 text_style.setLetterSpacing(0);
2427 text_style.setWordSpacing(20);
2428 builder.pushStyle(text_style);
2429 builder.addText("H ");
2430 builder.pop();
2431
2432 text_style.setLetterSpacing(0);
2433 text_style.setWordSpacing(0);
2434 builder.pushStyle(text_style);
2435 builder.addText("H ");
2436 builder.pop();
2437
2438 text_style.setLetterSpacing(0);
2439 text_style.setLetterSpacing(0);
2440 text_style.setWordSpacing(20);
2441 builder.pushStyle(text_style);
2442 builder.addText("H ");
2443 builder.pop();
2444
2445 auto paragraph = builder.Build();
2446 paragraph->layout(550);
2447 paragraph->paint(canvas.get(), 0, 0);
2448
2449 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2450 REPORTER_ASSERT(reporter, impl->lines().size() == 1);
2451 size_t index = 0;
2452 impl->lines().begin()->scanStyles(StyleType::kLetterSpacing,
2453 [&index](TextRange text, TextStyle style, SkScalar) {
2454 ++index;
2455 return true;
2456 });
2457 REPORTER_ASSERT(reporter, index == 4);
2458 index = 0;
2459 impl->lines().begin()->scanStyles(StyleType::kWordSpacing,
2460 [&index](TextRange text, TextStyle style, SkScalar) {
2461 ++index;
2462 return true;
2463 });
2464 REPORTER_ASSERT(reporter, index == 4);
2465 }
2466
2467 // Checked: NO DIFF
DEF_TEST(SkParagraph_LongWordParagraph,reporter)2468 DEF_TEST(SkParagraph_LongWordParagraph, reporter) {
2469 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2470 if (!fontCollection->fontsFound()) return;
2471 TestCanvas canvas("SkParagraph_LongWordParagraph.png");
2472 const char* text =
2473 "A "
2474 "veryverylongwordtoseewherethiswillwraporifitwillatallandifitdoesthenthat"
2475 "wouldbeagoodthingbecausethebreakingisworking.";
2476
2477 ParagraphStyle paragraph_style;
2478 paragraph_style.turnHintingOff();
2479 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2480
2481 TextStyle text_style;
2482 text_style.setFontFamilies({SkString("Roboto")});
2483 text_style.setColor(SK_ColorRED);
2484 text_style.setFontSize(31);
2485 text_style.setLetterSpacing(0);
2486 text_style.setWordSpacing(0);
2487 text_style.setColor(SK_ColorBLACK);
2488 text_style.setHeight(1);
2489 builder.pushStyle(text_style);
2490 builder.addText(text);
2491 builder.pop();
2492
2493 auto paragraph = builder.Build();
2494 paragraph->layout(TestCanvasWidth / 2);
2495 paragraph->paint(canvas.get(), 0, 0);
2496
2497 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2498 REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
2499 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
2500 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
2501 REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
2502 REPORTER_ASSERT(reporter, impl->lines().size() == 4);
2503
2504 REPORTER_ASSERT(reporter, impl->lines()[0].width() > TestCanvasWidth / 2 - 20);
2505 REPORTER_ASSERT(reporter, impl->lines()[1].width() > TestCanvasWidth / 2 - 20);
2506 REPORTER_ASSERT(reporter, impl->lines()[2].width() > TestCanvasWidth / 2 - 20);
2507 }
2508
2509 // Checked: DIFF?
DEF_TEST(SkParagraph_KernScaleParagraph,reporter)2510 DEF_TEST(SkParagraph_KernScaleParagraph, reporter) {
2511 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2512 if (!fontCollection->fontsFound()) return;
2513 TestCanvas canvas("SkParagraph_KernScaleParagraph.png");
2514
2515 const char* text1 = "AVAVAWAH A0 V0 VA To The Lo";
2516 const char* text2 = " Dialog Text List lots of words to see "
2517 "if kerning works on a bigger set of characters AVAVAW";
2518 float scale = 3.0f;
2519 ParagraphStyle paragraph_style;
2520 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2521 TextStyle text_style;
2522 text_style.setFontFamilies({SkString("Droid Serif")});
2523 text_style.setFontSize(100 / scale);
2524 text_style.setColor(SK_ColorBLACK);
2525
2526 builder.pushStyle(text_style);
2527 builder.addText(text1);
2528 builder.pushStyle(text_style);
2529 builder.addText("A");
2530 builder.pushStyle(text_style);
2531 builder.addText("V");
2532 text_style.setFontSize(14 / scale);
2533 builder.pushStyle(text_style);
2534 builder.addText(text2);
2535 builder.pop();
2536
2537 auto paragraph = builder.Build();
2538 paragraph->layout(TestCanvasWidth / scale);
2539 canvas.get()->scale(scale, scale);
2540 paragraph->paint(canvas.get(), 0, 0);
2541 canvas.get()->scale(1, 1);
2542
2543 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2544
2545 // First and second lines must have the same width, the third one must be bigger
2546 REPORTER_ASSERT(reporter, impl->lines().size() == 3);
2547 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].width(), 285.858f, EPSILON100));
2548 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[1].width(), 329.709f, EPSILON100));
2549 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[2].width(), 120.619f, EPSILON100));
2550 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].height(), 39.00f, EPSILON100));
2551 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[1].height(), 39.00f, EPSILON100));
2552 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[2].height(), 05.00f, EPSILON100));
2553 }
2554
2555 // Checked: DIFF+
DEF_TEST(SkParagraph_NewlineParagraph,reporter)2556 DEF_TEST(SkParagraph_NewlineParagraph, reporter) {
2557 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2558 if (!fontCollection->fontsFound()) return;
2559 TestCanvas canvas("SkParagraph_NewlineParagraph.png");
2560 const char* text =
2561 "line1\nline2 test1 test2 test3 test4 test5 test6 test7\nline3\n\nline4 "
2562 "test1 test2 test3 test4";
2563 ParagraphStyle paragraph_style;
2564 paragraph_style.turnHintingOff();
2565 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2566
2567 TextStyle text_style;
2568 text_style.setFontFamilies({SkString("Roboto")});
2569 text_style.setColor(SK_ColorRED);
2570 text_style.setFontSize(60);
2571 text_style.setColor(SK_ColorBLACK);
2572 text_style.setHeight(1);
2573 builder.pushStyle(text_style);
2574 builder.addText(text);
2575 builder.pop();
2576
2577 auto paragraph = builder.Build();
2578 paragraph->layout(TestCanvasWidth - 300);
2579 paragraph->paint(canvas.get(), 0, 0);
2580
2581 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2582 // Minikin does not count empty lines but SkParagraph does
2583 REPORTER_ASSERT(reporter, impl->lines().size() == 7);
2584
2585 REPORTER_ASSERT(reporter, impl->lines()[0].offset().fY == 0);
2586 REPORTER_ASSERT(reporter, impl->lines()[1].offset().fY == 70);
2587 REPORTER_ASSERT(reporter, impl->lines()[2].offset().fY == 140);
2588 REPORTER_ASSERT(reporter, impl->lines()[3].offset().fY == 210);
2589 REPORTER_ASSERT(reporter, impl->lines()[4].offset().fY == 280); // Empty line
2590 REPORTER_ASSERT(reporter, impl->lines()[5].offset().fY == 350);
2591 REPORTER_ASSERT(reporter, impl->lines()[6].offset().fY == 420);
2592 }
2593
2594 // TODO: Fix underline
DEF_TEST(SkParagraph_EmojiParagraph,reporter)2595 DEF_TEST(SkParagraph_EmojiParagraph, reporter) {
2596 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2597 if (!fontCollection->fontsFound()) return;
2598 TestCanvas canvas("SkParagraph_EmojiParagraph.png");
2599 const char* text =
2600 "☺♂️\
2601 ☂\
2602 ❄⚽♀️⚓⏰\
2603 ❤♠♣❗️";
2604
2605 ParagraphStyle paragraph_style;
2606 paragraph_style.turnHintingOff();
2607 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2608
2609 TextStyle text_style;
2610 text_style.setFontFamilies({SkString("Noto Color Emoji")});
2611 text_style.setFontSize(50);
2612 text_style.setDecoration(TextDecoration::kUnderline);
2613 text_style.setColor(SK_ColorBLACK);
2614 builder.pushStyle(text_style);
2615 builder.addText(text);
2616 builder.pop();
2617
2618 auto paragraph = builder.Build();
2619 paragraph->layout(TestCanvasWidth);
2620 paragraph->paint(canvas.get(), 0, 0);
2621
2622 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2623
2624 REPORTER_ASSERT(reporter, impl->lines().size() == 8);
2625 for (auto& line : impl->lines()) {
2626 if (&line != impl->lines().end() - 1) {
2627 REPORTER_ASSERT(reporter, line.width() == 998.25f);
2628 } else {
2629 REPORTER_ASSERT(reporter, line.width() < 998.25f);
2630 }
2631 REPORTER_ASSERT(reporter, line.height() == 59);
2632 }
2633 }
2634
2635 // Checked: DIFF+
DEF_TEST(SkParagraph_EmojiMultiLineRectsParagraph,reporter)2636 DEF_TEST(SkParagraph_EmojiMultiLineRectsParagraph, reporter) {
2637 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2638 if (!fontCollection->fontsFound()) return;
2639 TestCanvas canvas("SkParagraph_EmojiMultiLineRectsParagraph.png");
2640 const char* text =
2641 "i"
2642 ""
2643 ""
2644 ""
2645 "❄⚽♀️⚓⏰"
2646 "❤♠♣❗️";
2647
2648 ParagraphStyle paragraph_style;
2649 paragraph_style.turnHintingOff();
2650 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2651
2652 TextStyle text_style;
2653 text_style.setFontFamilies({SkString("Noto Color Emoji")});
2654 text_style.setFontSize(50);
2655 text_style.setColor(SK_ColorBLACK);
2656 builder.pushStyle(text_style);
2657 builder.addText(text);
2658 builder.pop();
2659
2660 auto paragraph = builder.Build();
2661 paragraph->layout(TestCanvasWidth - 300);
2662 paragraph->paint(canvas.get(), 0, 0);
2663
2664 RectHeightStyle rect_height_style = RectHeightStyle::kTight;
2665 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
2666
2667 auto result = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
2668 REPORTER_ASSERT(reporter, result.size() == 0);
2669
2670 result = paragraph->getRectsForRange(0, 119, rect_height_style, rect_width_style);
2671 REPORTER_ASSERT(reporter, result.size() == 2);
2672 canvas.drawRects(SK_ColorRED, result);
2673
2674 result = paragraph->getRectsForRange(122, 132, rect_height_style, rect_width_style);
2675 REPORTER_ASSERT(reporter, result.size() == 1);
2676 canvas.drawRects(SK_ColorBLUE, result);
2677
2678 auto pos = paragraph->getGlyphPositionAtCoordinate(610, 100).position;
2679 result = paragraph->getRectsForRange(0, pos, rect_height_style, rect_width_style);
2680 REPORTER_ASSERT(reporter, result.size() == 2);
2681 canvas.drawRects(SK_ColorGREEN, result);
2682
2683 pos = paragraph->getGlyphPositionAtCoordinate(580, 100).position;
2684 result = paragraph->getRectsForRange(0, pos, rect_height_style, rect_width_style);
2685 REPORTER_ASSERT(reporter, result.size() == 2);
2686 canvas.drawRects(SK_ColorGREEN, result);
2687
2688 pos = paragraph->getGlyphPositionAtCoordinate(560, 100).position;
2689 result = paragraph->getRectsForRange(0, pos, rect_height_style, rect_width_style);
2690 REPORTER_ASSERT(reporter, result.size() == 2);
2691 canvas.drawRects(SK_ColorGREEN, result);
2692 }
2693
2694 // TODO: Not soon
DEF_TEST(SkParagraph_HyphenBreakParagraph,reporter)2695 DEF_TEST(SkParagraph_HyphenBreakParagraph, reporter) { SkDebugf("Not implemented yet.\n"); }
2696
2697 // Checked: DIFF (line breaking)
DEF_TEST(SkParagraph_RepeatLayoutParagraph,reporter)2698 DEF_TEST(SkParagraph_RepeatLayoutParagraph, reporter) {
2699 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2700 if (!fontCollection->fontsFound()) return;
2701 TestCanvas canvas("SkParagraph_RepeatLayoutParagraph.png");
2702 const char* text =
2703 "Sentence to layout at diff widths to get diff line counts. short words "
2704 "short words short words short words short words short words short words "
2705 "short words short words short words short words short words short words "
2706 "end";
2707
2708 ParagraphStyle paragraph_style;
2709 paragraph_style.turnHintingOff();
2710 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2711
2712 TextStyle text_style;
2713 text_style.setFontFamilies({SkString("Roboto")});
2714 text_style.setFontSize(31);
2715 text_style.setColor(SK_ColorBLACK);
2716 builder.pushStyle(text_style);
2717 builder.addText(text);
2718 builder.pop();
2719
2720 auto paragraph = builder.Build();
2721 paragraph->layout(300);
2722
2723 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2724 // Some of the formatting lazily done on paint
2725 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
2726 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
2727 REPORTER_ASSERT(reporter, impl->lines().size() == 12);
2728
2729 paragraph->layout(600);
2730 paragraph->paint(canvas.get(), 0, 0);
2731 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
2732 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
2733 REPORTER_ASSERT(reporter, impl->lines().size() == 6);
2734 }
2735
2736 // Checked: NO DIFF
DEF_TEST(SkParagraph_Ellipsize,reporter)2737 DEF_TEST(SkParagraph_Ellipsize, reporter) {
2738 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2739 if (!fontCollection->fontsFound()) return;
2740 TestCanvas canvas("SkParagraph_Ellipsize.png");
2741 const char* text =
2742 "This is a very long sentence to test if the text will properly wrap "
2743 "around and go to the next line. Sometimes, short sentence. Longer "
2744 "sentences are okay too because they are nessecary. Very short. ";
2745
2746 ParagraphStyle paragraph_style;
2747 paragraph_style.setMaxLines(1);
2748 paragraph_style.setEllipsis(u"\u2026");
2749 paragraph_style.turnHintingOff();
2750 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2751
2752 TextStyle text_style;
2753 text_style.setFontFamilies({SkString("Roboto")});
2754 text_style.setColor(SK_ColorBLACK);
2755 builder.pushStyle(text_style);
2756 builder.addText(text);
2757 builder.pop();
2758
2759 auto paragraph = builder.Build();
2760 paragraph->layout(TestCanvasWidth);
2761 paragraph->paint(canvas.get(), 0, 0);
2762
2763 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2764
2765 // Check that the ellipsizer limited the text to one line and did not wrap to a second line.
2766 REPORTER_ASSERT(reporter, impl->lines().size() == 1);
2767
2768 auto& line = impl->lines()[0];
2769 REPORTER_ASSERT(reporter, line.ellipsis() != nullptr);
2770 size_t index = 0;
2771 line.scanRuns([&index, &line, reporter](Run* run, int32_t, size_t, TextRange, SkRect, SkScalar, bool) {
2772 ++index;
2773 if (index == 2) {
2774 REPORTER_ASSERT(reporter, run->textRange() == line.ellipsis()->textRange());
2775 }
2776 return true;
2777 });
2778 REPORTER_ASSERT(reporter, index == 2);
2779 }
2780
2781 // Checked: NO DIFF
DEF_TEST(SkParagraph_UnderlineShiftParagraph,reporter)2782 DEF_TEST(SkParagraph_UnderlineShiftParagraph, reporter) {
2783 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2784 if (!fontCollection->fontsFound()) return;
2785 TestCanvas canvas("SkParagraph_UnderlineShiftParagraph.png");
2786 const char* text1 = "fluttser ";
2787 const char* text2 = "mdje";
2788 const char* text3 = "fluttser mdje";
2789
2790 ParagraphStyle paragraph_style;
2791 paragraph_style.turnHintingOff();
2792 paragraph_style.setTextAlign(TextAlign::kLeft);
2793 paragraph_style.setMaxLines(2);
2794 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2795
2796 TextStyle text_style;
2797 text_style.setFontFamilies({SkString("Roboto")});
2798 text_style.setColor(SK_ColorBLACK);
2799 builder.pushStyle(text_style);
2800 builder.addText(text1);
2801 text_style.setDecoration(TextDecoration::kUnderline);
2802 text_style.setDecorationColor(SK_ColorBLACK);
2803 builder.pushStyle(text_style);
2804 builder.addText(text2);
2805 builder.pop();
2806
2807 auto paragraph = builder.Build();
2808 paragraph->layout(TestCanvasWidth);
2809 paragraph->paint(canvas.get(), 0, 0);
2810
2811 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2812
2813 ParagraphBuilderImpl builder1(paragraph_style, fontCollection);
2814 text_style.setDecoration(TextDecoration::kNoDecoration);
2815 builder1.pushStyle(text_style);
2816 builder1.addText(text3);
2817 builder1.pop();
2818
2819 auto paragraph1 = builder1.Build();
2820 paragraph1->layout(TestCanvasWidth);
2821 paragraph1->paint(canvas.get(), 0, 25);
2822
2823 auto impl1 = static_cast<ParagraphImpl*>(paragraph1.get());
2824
2825 REPORTER_ASSERT(reporter, impl->lines().size() == 1);
2826 REPORTER_ASSERT(reporter, impl1->lines().size() == 1);
2827
2828 auto rect = paragraph->getRectsForRange(0, 12, RectHeightStyle::kMax, RectWidthStyle::kTight)
2829 .front()
2830 .rect;
2831 auto rect1 = paragraph1->getRectsForRange(0, 12, RectHeightStyle::kMax, RectWidthStyle::kTight)
2832 .front()
2833 .rect;
2834 REPORTER_ASSERT(reporter, rect.fLeft == rect1.fLeft);
2835 REPORTER_ASSERT(reporter, rect.fRight == rect1.fRight);
2836
2837 for (size_t i = 0; i < 12; ++i) {
2838 auto r =
2839 paragraph->getRectsForRange(i, i + 1, RectHeightStyle::kMax, RectWidthStyle::kTight)
2840 .front()
2841 .rect;
2842 auto r1 =
2843 paragraph1
2844 ->getRectsForRange(i, i + 1, RectHeightStyle::kMax, RectWidthStyle::kTight)
2845 .front()
2846 .rect;
2847
2848 REPORTER_ASSERT(reporter, r.fLeft == r1.fLeft);
2849 REPORTER_ASSERT(reporter, r.fRight == r1.fRight);
2850 }
2851 }
2852
2853 // Checked: NO DIFF
DEF_TEST(SkParagraph_SimpleShadow,reporter)2854 DEF_TEST(SkParagraph_SimpleShadow, reporter) {
2855 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2856 if (!fontCollection->fontsFound()) return;
2857 TestCanvas canvas("SkParagraph_SimpleShadow.png");
2858 const char* text = "Hello World Text Dialog";
2859
2860 ParagraphStyle paragraph_style;
2861 paragraph_style.turnHintingOff();
2862 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2863
2864 TextStyle text_style;
2865 text_style.setFontFamilies({SkString("Roboto")});
2866 text_style.setColor(SK_ColorBLACK);
2867 text_style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(2.0f, 2.0f), 1.0));
2868 builder.pushStyle(text_style);
2869 builder.addText(text);
2870
2871 auto paragraph = builder.Build();
2872 paragraph->layout(TestCanvasWidth);
2873 paragraph->paint(canvas.get(), 10.0, 15.0);
2874
2875 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2876
2877 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
2878 REPORTER_ASSERT(reporter, impl->styles().size() == 1);
2879 size_t index = 0;
2880 for (auto& line : impl->lines()) {
2881 line.scanStyles(StyleType::kShadow,
2882 [&index, text_style, reporter](TextRange text, TextStyle style, SkScalar) {
2883 REPORTER_ASSERT(reporter, index == 0 && style.equals(text_style));
2884 ++index;
2885 return true;
2886 });
2887 }
2888 }
2889
2890 // Checked: NO DIFF
DEF_TEST(SkParagraph_ComplexShadow,reporter)2891 DEF_TEST(SkParagraph_ComplexShadow, reporter) {
2892 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2893 if (!fontCollection->fontsFound()) return;
2894 TestCanvas canvas("SkParagraph_ComplexShadow.png");
2895 const char* text = "Text Chunk ";
2896
2897 ParagraphStyle paragraph_style;
2898 paragraph_style.turnHintingOff();
2899 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2900
2901 TextStyle text_style;
2902 text_style.setFontFamilies({SkString("Roboto")});
2903 text_style.setColor(SK_ColorBLACK);
2904 text_style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(2.0f, 2.0f), 1.0f));
2905 builder.pushStyle(text_style);
2906 builder.addText(text);
2907
2908 text_style.addShadow(TextShadow(SK_ColorRED, SkPoint::Make(2.0f, 2.0f), 5.0f));
2909 text_style.addShadow(TextShadow(SK_ColorGREEN, SkPoint::Make(10.0f, -5.0f), 3.0f));
2910 builder.pushStyle(text_style);
2911 builder.addText(text);
2912 builder.pop();
2913
2914 builder.addText(text);
2915
2916 text_style.addShadow(TextShadow(SK_ColorRED, SkPoint::Make(0.0f, 1.0f), 0.0f));
2917 builder.pushStyle(text_style);
2918 builder.addText(text);
2919 builder.pop();
2920
2921 builder.addText(text);
2922
2923 auto paragraph = builder.Build();
2924 paragraph->layout(TestCanvasWidth);
2925 paragraph->paint(canvas.get(), 10.0, 15.0);
2926
2927 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2928
2929 size_t index = 0;
2930 for (auto& line : impl->lines()) {
2931 line.scanStyles(StyleType::kShadow,
2932 [&index, text_style, reporter](TextRange text, TextStyle style, SkScalar) {
2933 ++index;
2934 switch (index) {
2935 case 1:
2936 REPORTER_ASSERT(reporter, style.getShadowNumber() == 1);
2937 break;
2938 case 2:
2939 REPORTER_ASSERT(reporter, style.getShadowNumber() == 3);
2940 break;
2941 case 3:
2942 REPORTER_ASSERT(reporter, style.getShadowNumber() == 1);
2943 break;
2944 case 4:
2945 REPORTER_ASSERT(reporter, style.getShadowNumber() == 4);
2946 REPORTER_ASSERT(reporter, style.equals(text_style));
2947 break;
2948 case 5:
2949 REPORTER_ASSERT(reporter, style.getShadowNumber() == 1);
2950 break;
2951 default:
2952 REPORTER_ASSERT(reporter, false);
2953 }
2954 return true;
2955 });
2956 }
2957 }
2958
2959 // Checked: NO DIFF
DEF_TEST(SkParagraph_BaselineParagraph,reporter)2960 DEF_TEST(SkParagraph_BaselineParagraph, reporter) {
2961 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
2962 if (!fontCollection->fontsFound()) return;
2963 TestCanvas canvas("SkParagraph_BaselineParagraph.png");
2964 const char* text =
2965 "左線読設Byg後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
2966 "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得";
2967
2968 ParagraphStyle paragraph_style;
2969 paragraph_style.turnHintingOff();
2970 paragraph_style.setMaxLines(14);
2971 paragraph_style.setTextAlign(TextAlign::kJustify);
2972 paragraph_style.setHeight(1.5);
2973 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2974
2975 TextStyle text_style;
2976 text_style.setFontFamilies({SkString("Source Han Serif CN")});
2977 text_style.setColor(SK_ColorBLACK);
2978 text_style.setFontSize(55);
2979 text_style.setLetterSpacing(2);
2980 text_style.setDecorationStyle(TextDecorationStyle::kSolid);
2981 text_style.setDecorationColor(SK_ColorBLACK);
2982 builder.pushStyle(text_style);
2983 builder.addText(text);
2984 builder.pop();
2985
2986 auto paragraph = builder.Build();
2987 paragraph->layout(TestCanvasWidth - 100);
2988 paragraph->paint(canvas.get(), 0, 0);
2989
2990 SkRect rect1 = SkRect::MakeXYWH(0, paragraph->getIdeographicBaseline(),
2991 paragraph->getMaxWidth(),
2992 paragraph->getIdeographicBaseline());
2993 SkRect rect2 = SkRect::MakeXYWH(0, paragraph->getAlphabeticBaseline(),
2994 paragraph->getMaxWidth(),
2995 paragraph->getAlphabeticBaseline());
2996 canvas.drawLine(SK_ColorRED, rect1, false);
2997 canvas.drawLine(SK_ColorGREEN, rect2, false);
2998
2999 REPORTER_ASSERT(reporter,
3000 SkScalarNearlyEqual(paragraph->getIdeographicBaseline(), 79.035f, EPSILON100));
3001 REPORTER_ASSERT(reporter,
3002 SkScalarNearlyEqual(paragraph->getAlphabeticBaseline(), 63.305f, EPSILON100));
3003 }
3004
3005 // Checked: NO DIFF
DEF_TEST(SkParagraph_FontFallbackParagraph,reporter)3006 DEF_TEST(SkParagraph_FontFallbackParagraph, reporter) {
3007 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3008 if (!fontCollection->fontsFound()) return;
3009 TestCanvas canvas("SkParagraph_FontFallbackParagraph.png");
3010
3011 const char* text1 = "Roboto 字典 "; // Roboto + unresolved
3012 const char* text2 = "Homemade Apple 字典"; // Homemade Apple + Noto Sans...
3013 const char* text3 = "Chinese 字典"; // Homemade Apple + Source Han
3014
3015 ParagraphStyle paragraph_style;
3016 paragraph_style.turnHintingOff();
3017 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3018
3019 TextStyle text_style;
3020 text_style.setFontFamilies({
3021 SkString("Not a real font"),
3022 SkString("Also a fake font"),
3023 SkString("So fake it is obvious"),
3024 SkString("Next one should be a real font..."),
3025 SkString("Roboto"),
3026 SkString("another fake one in between"),
3027 SkString("Homemade Apple"),
3028 });
3029 text_style.setColor(SK_ColorBLACK);
3030 builder.pushStyle(text_style);
3031 builder.addText(text1);
3032
3033 text_style.setFontFamilies({
3034 SkString("Not a real font"),
3035 SkString("Also a fake font"),
3036 SkString("So fake it is obvious"),
3037 SkString("Homemade Apple"),
3038 SkString("Next one should be a real font..."),
3039 SkString("Roboto"),
3040 SkString("another fake one in between"),
3041 SkString("Noto Sans CJK JP"),
3042 SkString("Source Han Serif CN"),
3043 });
3044 builder.pushStyle(text_style);
3045 builder.addText(text2);
3046
3047 text_style.setFontFamilies({
3048 SkString("Not a real font"),
3049 SkString("Also a fake font"),
3050 SkString("So fake it is obvious"),
3051 SkString("Homemade Apple"),
3052 SkString("Next one should be a real font..."),
3053 SkString("Roboto"),
3054 SkString("another fake one in between"),
3055 SkString("Source Han Serif CN"),
3056 SkString("Noto Sans CJK JP"),
3057 });
3058 builder.pushStyle(text_style);
3059 builder.addText(text3);
3060
3061 builder.pop();
3062
3063 auto paragraph = builder.Build();
3064 paragraph->layout(TestCanvasWidth);
3065 paragraph->paint(canvas.get(), 10.0, 15.0);
3066
3067 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3068
3069 // Font resolution in Skia produces 6 runs because 2 parts of "Roboto 字典 " have different
3070 // script (Minikin merges the first 2 into one because of unresolved) [Apple + Unresolved ]
3071 // [Apple + Noto] [Apple + Han]
3072 REPORTER_ASSERT(reporter, impl->runs().size() == 6);
3073
3074 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[0].advance().fX, 48.330f, EPSILON100));
3075 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[1].advance().fX, 15.879f, EPSILON100));
3076 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[2].advance().fX, 139.125f, EPSILON100));
3077 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[3].advance().fX, 27.999f, EPSILON100));
3078 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[4].advance().fX, 62.248f, EPSILON100));
3079 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[5].advance().fX, 27.999f, EPSILON100));
3080
3081 // When a different font is resolved, then the metrics are different.
3082 REPORTER_ASSERT(reporter, impl->runs()[1].correctAscent() != impl->runs()[3].correctAscent());
3083 REPORTER_ASSERT(reporter, impl->runs()[1].correctDescent() != impl->runs()[3].correctDescent());
3084 REPORTER_ASSERT(reporter, impl->runs()[3].correctAscent() != impl->runs()[5].correctAscent());
3085 REPORTER_ASSERT(reporter, impl->runs()[3].correctDescent() != impl->runs()[5].correctDescent());
3086 REPORTER_ASSERT(reporter, impl->runs()[1].correctAscent() != impl->runs()[5].correctAscent());
3087 REPORTER_ASSERT(reporter, impl->runs()[1].correctDescent() != impl->runs()[5].correctDescent());
3088 }
3089
3090 // Checked: NO DIFF
DEF_TEST(SkParagraph_StrutParagraph1,reporter)3091 DEF_TEST(SkParagraph_StrutParagraph1, reporter) {
3092 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3093 if (!fontCollection->fontsFound()) return;
3094 TestCanvas canvas("SkParagraph_StrutParagraph1.png");
3095 // The chinese extra height should be absorbed by the strut.
3096 const char* text = "01234満毎冠p来É本可\nabcd\n満毎É行p昼本可";
3097
3098 ParagraphStyle paragraph_style;
3099 paragraph_style.setMaxLines(10);
3100 paragraph_style.setTextAlign(TextAlign::kLeft);
3101 paragraph_style.turnHintingOff();
3102
3103 StrutStyle strut_style;
3104 strut_style.setStrutEnabled(true);
3105 strut_style.setFontFamilies({SkString("BlahFake"), SkString("Ahem")});
3106 strut_style.setFontSize(50);
3107 strut_style.setHeight(1.8f);
3108 strut_style.setHeightOverride(true);
3109 strut_style.setLeading(0.1f);
3110 paragraph_style.setStrutStyle(strut_style);
3111
3112 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3113
3114 TextStyle text_style;
3115 text_style.setFontFamilies({SkString("Ahem")});
3116 text_style.setFontSize(50);
3117 text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
3118 text_style.setColor(SK_ColorBLACK);
3119 text_style.setHeight(0.5f);
3120 builder.pushStyle(text_style);
3121 builder.addText(text);
3122 builder.pop();
3123
3124 auto paragraph = builder.Build();
3125 paragraph->layout(550);
3126 paragraph->paint(canvas.get(), 0, 0);
3127
3128 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3129 REPORTER_ASSERT(reporter, impl->lines().size() == 4);
3130
3131 RectHeightStyle rect_height_style = RectHeightStyle::kTight;
3132 RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
3133 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
3134 {
3135 auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
3136 REPORTER_ASSERT(reporter, boxes.empty());
3137 }
3138 {
3139 auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
3140 canvas.drawRects(SK_ColorRED, boxes);
3141 REPORTER_ASSERT(reporter, boxes.size() == 1);
3142 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3143 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
3144 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
3145 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 84.5f, EPSILON100));
3146 }
3147 {
3148 auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
3149 canvas.drawRects(SK_ColorRED, boxes);
3150 REPORTER_ASSERT(reporter, boxes.size() == 1);
3151 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3152 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
3153 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
3154 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 95, EPSILON100));
3155 }
3156 {
3157 auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
3158 canvas.drawRects(SK_ColorRED, boxes);
3159 REPORTER_ASSERT(reporter, boxes.size() == 1);
3160 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
3161 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
3162 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
3163 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 84.5f, EPSILON100));
3164 }
3165 {
3166 auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
3167 canvas.drawRects(SK_ColorRED, boxes);
3168 REPORTER_ASSERT(reporter, boxes.size() == 1);
3169 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
3170 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
3171 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
3172 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 95, EPSILON100));
3173 }
3174 {
3175 auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
3176 canvas.drawRects(SK_ColorRED, boxes);
3177 REPORTER_ASSERT(reporter, boxes.size() == 1);
3178 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3179 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 224.5f, EPSILON100));
3180 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, EPSILON100));
3181 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 285, EPSILON100));
3182 }
3183 {
3184 auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
3185 canvas.drawRects(SK_ColorRED, boxes);
3186 REPORTER_ASSERT(reporter, boxes.size() == 1);
3187 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, EPSILON100));
3188 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 319.5f, EPSILON100));
3189 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, EPSILON100));
3190 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 380, EPSILON100));
3191 }
3192 }
3193
3194 // Checked: NO DIFF
DEF_TEST(SkParagraph_StrutParagraph2,reporter)3195 DEF_TEST(SkParagraph_StrutParagraph2, reporter) {
3196 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3197 TestCanvas canvas("SkParagraph_StrutParagraph2.png");
3198 if (!fontCollection->fontsFound()) return;
3199 // The chinese extra height should be absorbed by the strut.
3200 const char* text = "01234ABCDEFGH\nabcd\nABCDEFGH";
3201
3202 ParagraphStyle paragraph_style;
3203 paragraph_style.setMaxLines(10);
3204 paragraph_style.setTextAlign(TextAlign::kLeft);
3205 paragraph_style.turnHintingOff();
3206
3207 StrutStyle strut_style;
3208
3209 strut_style.setStrutEnabled(true);
3210 strut_style.setFontFamilies({SkString("Ahem")});
3211 strut_style.setFontSize(50);
3212 strut_style.setHeight(1.6f);
3213 strut_style.setHeightOverride(true);
3214 paragraph_style.setStrutStyle(strut_style);
3215
3216 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3217
3218 TextStyle text_style;
3219 text_style.setFontFamilies({SkString("Ahem")});
3220 text_style.setFontSize(50);
3221 text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
3222 SkFontStyle::kUpright_Slant));
3223 text_style.setColor(SK_ColorBLACK);
3224 text_style.setHeight(1);
3225 builder.pushStyle(text_style);
3226 builder.addText(text);
3227 builder.pop();
3228
3229 auto paragraph = builder.Build();
3230 paragraph->layout(550);
3231 paragraph->paint(canvas.get(), 0, 0);
3232
3233 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3234 // Font is not resolved and the first line does not fit
3235 REPORTER_ASSERT(reporter, impl->lines().size() == 4);
3236
3237 RectHeightStyle rect_height_style = RectHeightStyle::kTight;
3238 RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
3239 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
3240 {
3241 auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
3242 REPORTER_ASSERT(reporter, boxes.empty());
3243 }
3244 {
3245 auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
3246 canvas.drawRects(SK_ColorRED, boxes);
3247 REPORTER_ASSERT(reporter, boxes.size() == 1);
3248 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3249 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
3250 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
3251 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 74, EPSILON100));
3252 }
3253 {
3254 auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
3255 canvas.drawRects(SK_ColorRED, boxes);
3256 REPORTER_ASSERT(reporter, boxes.size() == 1);
3257 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3258 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
3259 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
3260 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 80, EPSILON100));
3261 }
3262 {
3263 auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
3264 canvas.drawRects(SK_ColorRED, boxes);
3265 REPORTER_ASSERT(reporter, boxes.size() == 1);
3266 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
3267 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
3268 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
3269 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 74, EPSILON100));
3270 }
3271 {
3272 auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
3273 canvas.drawRects(SK_ColorRED, boxes);
3274 REPORTER_ASSERT(reporter, boxes.size() == 1);
3275 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
3276 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
3277 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
3278 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 80, EPSILON100));
3279 }
3280 {
3281 auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
3282 canvas.drawRects(SK_ColorRED, boxes);
3283 REPORTER_ASSERT(reporter, boxes.size() == 1);
3284 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3285 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 184, EPSILON100));
3286 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, EPSILON100));
3287 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 240, EPSILON100));
3288 }
3289 {
3290 auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
3291 canvas.drawRects(SK_ColorRED, boxes);
3292 REPORTER_ASSERT(reporter, boxes.size() == 1);
3293 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, EPSILON100));
3294 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 264, EPSILON100));
3295 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, EPSILON100));
3296 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 320, EPSILON100));
3297 }
3298 }
3299
3300 // Checked: NO DIFF
DEF_TEST(SkParagraph_StrutParagraph3,reporter)3301 DEF_TEST(SkParagraph_StrutParagraph3, reporter) {
3302 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3303 if (!fontCollection->fontsFound()) return;
3304 TestCanvas canvas("SkParagraph_StrutParagraph3.png");
3305
3306 // The chinese extra height should be absorbed by the strut.
3307 const char* text = "01234満毎p行来昼本可\nabcd\n満毎冠行来昼本可";
3308
3309 ParagraphStyle paragraph_style;
3310 paragraph_style.setMaxLines(10);
3311 paragraph_style.setTextAlign(TextAlign::kLeft);
3312 paragraph_style.turnHintingOff();
3313
3314 StrutStyle strut_style;
3315 strut_style.setStrutEnabled(true);
3316 strut_style.setFontFamilies({SkString("Ahem")});
3317 strut_style.setFontSize(50);
3318 strut_style.setHeight(1.2f);
3319 strut_style.setHeightOverride(true);
3320 paragraph_style.setStrutStyle(strut_style);
3321
3322 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3323
3324 TextStyle text_style;
3325 text_style.setFontFamilies({SkString("Ahem")});
3326 text_style.setFontSize(50);
3327 text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
3328 SkFontStyle::kUpright_Slant));
3329 text_style.setColor(SK_ColorBLACK);
3330 text_style.setHeight(1);
3331 builder.pushStyle(text_style);
3332 builder.addText(text);
3333 builder.pop();
3334
3335 auto paragraph = builder.Build();
3336 paragraph->layout(550);
3337 paragraph->paint(canvas.get(), 0, 0);
3338
3339 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3340 // Font is not resolved and the first line does not fit
3341 REPORTER_ASSERT(reporter, impl->lines().size() == 4);
3342
3343 RectHeightStyle rect_height_style = RectHeightStyle::kTight;
3344 RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
3345 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
3346 SkScalar epsilon = 0.001f;
3347 {
3348 auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
3349 REPORTER_ASSERT(reporter, boxes.empty());
3350 }
3351 {
3352 auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
3353 canvas.drawRects(SK_ColorRED, boxes);
3354 REPORTER_ASSERT(reporter, boxes.size() == 1);
3355 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon));
3356 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
3357 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon));
3358 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 58, epsilon));
3359 }
3360 {
3361 auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
3362 canvas.drawRects(SK_ColorRED, boxes);
3363 REPORTER_ASSERT(reporter, boxes.size() == 1);
3364 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon));
3365 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
3366 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon));
3367 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 60, epsilon));
3368 }
3369 {
3370 auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
3371 canvas.drawRects(SK_ColorRED, boxes);
3372 REPORTER_ASSERT(reporter, boxes.size() == 1);
3373 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon));
3374 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
3375 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon));
3376 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 58, epsilon));
3377 }
3378 {
3379 auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
3380 canvas.drawRects(SK_ColorRED, boxes);
3381 REPORTER_ASSERT(reporter, boxes.size() == 1);
3382 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon));
3383 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
3384 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon));
3385 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 60, epsilon));
3386 }
3387 {
3388 auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
3389 canvas.drawRects(SK_ColorRED, boxes);
3390 REPORTER_ASSERT(reporter, boxes.size() == 1);
3391 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon));
3392 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 128, epsilon));
3393 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, epsilon));
3394 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 180, epsilon));
3395 }
3396 {
3397 auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
3398 canvas.drawRects(SK_ColorRED, boxes);
3399 REPORTER_ASSERT(reporter, boxes.size() == 1);
3400 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, epsilon));
3401 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 188, epsilon));
3402 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, epsilon));
3403 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 240, epsilon));
3404 }
3405 }
3406
3407 // Checked: NO DIFF
DEF_TEST(SkParagraph_StrutForceParagraph,reporter)3408 DEF_TEST(SkParagraph_StrutForceParagraph, reporter) {
3409 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3410 if (!fontCollection->fontsFound()) return;
3411 TestCanvas canvas("SkParagraph_StrutForceParagraph.png");
3412 const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
3413
3414 ParagraphStyle paragraph_style;
3415 paragraph_style.setMaxLines(10);
3416 paragraph_style.setTextAlign(TextAlign::kLeft);
3417 paragraph_style.turnHintingOff();
3418
3419 StrutStyle strut_style;
3420 strut_style.setStrutEnabled(true);
3421 strut_style.setFontFamilies({SkString("Ahem")});
3422 strut_style.setFontSize(50);
3423 strut_style.setHeight(1.5f);
3424 strut_style.setHeightOverride(true);
3425 strut_style.setLeading(0.1f);
3426 strut_style.setForceStrutHeight(true);
3427 paragraph_style.setStrutStyle(strut_style);
3428
3429 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3430
3431 TextStyle text_style;
3432 text_style.setFontFamilies({SkString("Ahem")});
3433 text_style.setFontSize(50);
3434 text_style.setLetterSpacing(0);
3435 text_style.setColor(SK_ColorBLACK);
3436 text_style.setHeight(1);
3437 builder.pushStyle(text_style);
3438 builder.addText(text);
3439 builder.pop();
3440
3441 auto paragraph = builder.Build();
3442 paragraph->layout(550);
3443 paragraph->paint(canvas.get(), 0, 0);
3444
3445 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3446 // Font is not resolved and the first line does not fit
3447 REPORTER_ASSERT(reporter, impl->lines().size() == 4);
3448
3449 RectHeightStyle rect_height_style = RectHeightStyle::kTight;
3450 RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
3451 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
3452
3453 auto boxes1 = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
3454 REPORTER_ASSERT(reporter, boxes1.empty());
3455
3456 auto boxes2 = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
3457 canvas.drawRects(SK_ColorRED, boxes2);
3458 REPORTER_ASSERT(reporter, boxes2.size() == 1);
3459 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.left(), 0, EPSILON100));
3460 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.top(), 22.5f, EPSILON100));
3461 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.right(), 50, EPSILON100));
3462 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.bottom(), 72.5f, EPSILON100));
3463
3464 auto boxes3 = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
3465 canvas.drawRects(SK_ColorRED, boxes3);
3466 REPORTER_ASSERT(reporter, boxes3.size() == 1);
3467 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.left(), 0, EPSILON100));
3468 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.top(), 22.5f, EPSILON100));
3469 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.right(), 50, EPSILON100));
3470 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.bottom(), 80, EPSILON100));
3471
3472 auto boxes4 = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
3473 canvas.drawRects(SK_ColorRED, boxes4);
3474 REPORTER_ASSERT(reporter, boxes4.size() == 1);
3475 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.left(), 300, EPSILON100));
3476 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.top(), 22.5f, EPSILON100));
3477 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.right(), 500, EPSILON100));
3478 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.bottom(), 72.5f, EPSILON100));
3479
3480 auto boxes5 = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
3481 canvas.drawRects(SK_ColorRED, boxes5);
3482 REPORTER_ASSERT(reporter, boxes5.size() == 1);
3483 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.left(), 300, EPSILON100));
3484 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.top(), 22.5f, EPSILON100));
3485 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.right(), 500, EPSILON100));
3486 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.bottom(), 80, EPSILON100));
3487
3488 auto boxes6 = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
3489 canvas.drawRects(SK_ColorRED, boxes6);
3490 REPORTER_ASSERT(reporter, boxes6.size() == 1);
3491 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.left(), 0, EPSILON100));
3492 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.top(), 182.5f, EPSILON100));
3493 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.right(), 100, EPSILON100));
3494 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.bottom(), 240, EPSILON100));
3495
3496 auto boxes7 = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
3497 canvas.drawRects(SK_ColorRED, boxes7);
3498 REPORTER_ASSERT(reporter, boxes7.size() == 1);
3499 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.left(), 50, EPSILON100));
3500 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.top(), 262.5f, EPSILON100));
3501 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.right(), 300, EPSILON100));
3502 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.bottom(), 320, EPSILON100));
3503 }
3504
3505 // Checked: NO DIFF
DEF_TEST(SkParagraph_StrutDefaultParagraph,reporter)3506 DEF_TEST(SkParagraph_StrutDefaultParagraph, reporter) {
3507 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3508 if (!fontCollection->fontsFound()) return;
3509 TestCanvas canvas("SkParagraph_StrutDefaultParagraph.png");
3510
3511 const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
3512
3513 ParagraphStyle paragraph_style;
3514 paragraph_style.setMaxLines(10);
3515 paragraph_style.setTextAlign(TextAlign::kLeft);
3516 paragraph_style.turnHintingOff();
3517
3518 StrutStyle strut_style;
3519 strut_style.setStrutEnabled(true);
3520 strut_style.setFontFamilies({SkString("Ahem")});
3521 strut_style.setFontSize(50);
3522 strut_style.setHeight(1.5f);
3523 strut_style.setLeading(0.1f);
3524 strut_style.setForceStrutHeight(false);
3525 paragraph_style.setStrutStyle(strut_style);
3526
3527 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3528
3529 TextStyle text_style;
3530 text_style.setFontFamilies({SkString("Ahem")});
3531 text_style.setFontSize(20);
3532 text_style.setColor(SK_ColorBLACK);
3533 builder.pushStyle(text_style);
3534 builder.addText(text);
3535 builder.pop();
3536
3537 auto paragraph = builder.Build();
3538 paragraph->layout(550);
3539 paragraph->paint(canvas.get(), 0, 0);
3540
3541 RectHeightStyle rect_height_style = RectHeightStyle::kTight;
3542 RectHeightStyle rect_height_strut_style = RectHeightStyle::kStrut;
3543 RectWidthStyle rect_width_style = RectWidthStyle::kTight;
3544 {
3545 auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
3546 REPORTER_ASSERT(reporter, boxes.empty());
3547 }
3548 {
3549 auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
3550 canvas.drawRects(SK_ColorRED, boxes);
3551 REPORTER_ASSERT(reporter, boxes.size() == 1);
3552 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3553 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 26.5f, EPSILON100));
3554 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 20, EPSILON100));
3555 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 46.5f, EPSILON100));
3556 }
3557 {
3558 auto boxes = paragraph->getRectsForRange(0, 2, rect_height_strut_style, rect_width_style);
3559 canvas.drawRects(SK_ColorRED, boxes);
3560 REPORTER_ASSERT(reporter, boxes.size() == 1);
3561 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
3562 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 2.5f, EPSILON100));
3563 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 40, EPSILON100));
3564 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 52.5f, EPSILON100));
3565 }
3566 }
3567
3568 // TODO: Implement font features
DEF_TEST(SkParagraph_FontFeaturesParagraph,reporter)3569 DEF_TEST(SkParagraph_FontFeaturesParagraph, reporter) { SkDebugf("Not implemented yet.\n"); }
3570
3571 // Not in Minikin
DEF_TEST(SkParagraph_WhitespacesInMultipleFonts,reporter)3572 DEF_TEST(SkParagraph_WhitespacesInMultipleFonts, reporter) {
3573 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3574 if (!fontCollection->fontsFound()) return;
3575 const char* text = "English English 字典 字典 ";
3576 ParagraphStyle paragraph_style;
3577 paragraph_style.turnHintingOff();
3578 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3579
3580 TextStyle text_style;
3581 text_style.setFontFamilies(
3582 {SkString("Roboto"), SkString("Noto Color Emoji"), SkString("Source Han Serif CN")});
3583 text_style.setFontSize(60);
3584 builder.pushStyle(text_style);
3585 builder.addText(text);
3586 builder.pop();
3587
3588 auto paragraph = builder.Build();
3589 paragraph->layout(TestCanvasWidth);
3590
3591 SkDEBUGCODE(auto impl = static_cast<ParagraphImpl*>(paragraph.get());)
3592 SkASSERT(impl->runs().size() == 3);
3593 SkASSERT(impl->runs()[0].textRange().end == impl->runs()[1].textRange().start);
3594 SkASSERT(impl->runs()[1].textRange().end == impl->runs()[2].textRange().start);
3595 }
3596
DEF_TEST(SkParagraph_JSON1,reporter)3597 DEF_TEST(SkParagraph_JSON1, reporter) {
3598 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3599 if (!fontCollection->fontsFound()) return;
3600 const char* text = "";
3601
3602 ParagraphStyle paragraph_style;
3603 paragraph_style.turnHintingOff();
3604 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3605
3606 TextStyle text_style;
3607 text_style.setFontFamilies({SkString("Noto Color Emoji")});
3608 builder.pushStyle(text_style);
3609 builder.addText(text);
3610 builder.pop();
3611
3612 auto paragraph = builder.Build();
3613 paragraph->layout(TestCanvasWidth);
3614
3615 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3616 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
3617 auto run = impl->runs().front();
3618
3619 auto cluster = 0;
3620 SkShaperJSONWriter::VisualizeClusters(
3621 text, 0, std::strlen(text), run.glyphs(), run.clusterIndexes(),
3622 [&](int codePointCount, SkSpan<const char> utf1to1, SkSpan<const SkGlyphID> glyph1to1) {
3623 if (cluster == 0) {
3624 std::string toCheckUtf8{utf1to1.data(), utf1to1.size()};
3625 SkASSERT(std::strcmp(text, utf1to1.data()) == 0);
3626 SkASSERT(glyph1to1.size() == 1);
3627 SkASSERT(*glyph1to1.begin() == 1611);
3628 }
3629 ++cluster;
3630 });
3631 SkASSERT(cluster <= 2);
3632 }
3633
DEF_TEST(SkParagraph_JSON2,reporter)3634 DEF_TEST(SkParagraph_JSON2, reporter) {
3635 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3636 if (!fontCollection->fontsFound()) return;
3637 const char* text = "p〠q";
3638
3639 ParagraphStyle paragraph_style;
3640 paragraph_style.turnHintingOff();
3641 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3642
3643 TextStyle text_style;
3644 text_style.setFontFamilies({SkString("Noto Sans CJK JP")});
3645 text_style.setColor(SK_ColorBLACK);
3646 text_style.setFontSize(50);
3647 builder.pushStyle(text_style);
3648 builder.addText(text);
3649 builder.pop();
3650
3651 auto paragraph = builder.Build();
3652 paragraph->layout(TestCanvasWidth);
3653
3654 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3655 REPORTER_ASSERT(reporter, impl->runs().size() == 1);
3656 auto run = impl->runs().front();
3657
3658 auto cluster = 0;
3659 for (auto& run : impl->runs()) {
3660 SkShaperJSONWriter::VisualizeClusters(
3661 impl->text().begin() + run.textRange().start, 0, run.textRange().width(),
3662 run.glyphs(), run.clusterIndexes(),
3663 [&](int codePointCount, SkSpan<const char> utf1to1,
3664 SkSpan<const SkGlyphID> glyph1to1) {
3665 if (cluster == 0) {
3666 std::string toCheckUtf8{utf1to1.data(), utf1to1.size()};
3667 SkASSERT(std::strcmp(text, utf1to1.data()) == 0);
3668 SkASSERT(glyph1to1.size() == 3);
3669 }
3670 ++cluster;
3671 });
3672 }
3673
3674 SkASSERT(cluster <= 2);
3675 }
3676
DEF_TEST(SkParagraph_CacheText,reporter)3677 DEF_TEST(SkParagraph_CacheText, reporter) {
3678 ParagraphCache cache;
3679 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3680 if (!fontCollection->fontsFound()) return;
3681
3682 ParagraphStyle paragraph_style;
3683 paragraph_style.turnHintingOff();
3684
3685 TextStyle text_style;
3686 text_style.setFontFamilies({SkString("Roboto")});
3687 text_style.setColor(SK_ColorBLACK);
3688
3689 auto test = [&](const char* text, int count, bool expectedToBeFound) {
3690 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3691 builder.pushStyle(text_style);
3692 builder.addText(text);
3693 builder.pop();
3694 auto paragraph = builder.Build();
3695
3696 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3697 REPORTER_ASSERT(reporter, count == cache.count());
3698 auto found = cache.findParagraph(impl);
3699 REPORTER_ASSERT(reporter, found == expectedToBeFound);
3700 auto added = cache.updateParagraph(impl);
3701 REPORTER_ASSERT(reporter, added != expectedToBeFound);
3702 };
3703
3704 test("text1", 0, false);
3705 test("text1", 1, true);
3706 test("text2", 1, false);
3707 test("text2", 2, true);
3708 test("text3", 2, false);
3709 }
3710
DEF_TEST(SkParagraph_CacheFonts,reporter)3711 DEF_TEST(SkParagraph_CacheFonts, reporter) {
3712 ParagraphCache cache;
3713 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3714 if (!fontCollection->fontsFound()) return;
3715
3716 ParagraphStyle paragraph_style;
3717 paragraph_style.turnHintingOff();
3718
3719 TextStyle text_style;
3720 text_style.setColor(SK_ColorBLACK);
3721
3722 auto test = [&](int count, bool expectedToBeFound) {
3723 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3724 builder.pushStyle(text_style);
3725 builder.addText("text");
3726 builder.pop();
3727 auto paragraph = builder.Build();
3728 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3729
3730 impl->getResolver().findAllFontsForAllStyledBlocks(impl);
3731
3732 REPORTER_ASSERT(reporter, count == cache.count());
3733 auto found = cache.findParagraph(impl);
3734 REPORTER_ASSERT(reporter, found == expectedToBeFound);
3735 auto added = cache.updateParagraph(impl);
3736 REPORTER_ASSERT(reporter, added != expectedToBeFound);
3737 };
3738
3739 text_style.setFontFamilies({SkString("Roboto")});
3740 test(0, false);
3741 test(1, true);
3742 text_style.setFontFamilies({SkString("Homemade Apple")});
3743 test(1, false);
3744 test(2, true);
3745 text_style.setFontFamilies({SkString("Noto Color Emoji")});
3746 test(2, false);
3747 }
3748
DEF_TEST(SkParagraph_CacheFontRanges,reporter)3749 DEF_TEST(SkParagraph_CacheFontRanges, reporter) {
3750 ParagraphCache cache;
3751 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3752 if (!fontCollection->fontsFound()) return;
3753
3754 ParagraphStyle paragraph_style;
3755 paragraph_style.turnHintingOff();
3756
3757 TextStyle text_style;
3758 text_style.setFontFamilies({SkString("Roboto")});
3759 text_style.setColor(SK_ColorBLACK);
3760
3761 auto test = [&](const char* text1,
3762 const char* text2,
3763 const char* font1,
3764 const char* font2,
3765 int count,
3766 bool expectedToBeFound) {
3767 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3768 text_style.setFontFamilies({SkString(font1)});
3769 builder.pushStyle(text_style);
3770 builder.addText(text1);
3771 builder.pop();
3772 text_style.setFontFamilies({SkString(font2)});
3773 builder.pushStyle(text_style);
3774 builder.addText(text2);
3775 builder.pop();
3776 auto paragraph = builder.Build();
3777 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3778
3779 impl->getResolver().findAllFontsForAllStyledBlocks(impl);
3780
3781 REPORTER_ASSERT(reporter, count == cache.count());
3782 auto found = cache.findParagraph(impl);
3783 REPORTER_ASSERT(reporter, found == expectedToBeFound);
3784 auto added = cache.updateParagraph(impl);
3785 REPORTER_ASSERT(reporter, added != expectedToBeFound);
3786 };
3787
3788 test("text", "", "Roboto", "Homemade Apple", 0, false);
3789 test("t", "ext", "Roboto", "Homemade Apple", 1, false);
3790 test("te", "xt", "Roboto", "Homemade Apple", 2, false);
3791 test("tex", "t", "Roboto", "Homemade Apple", 3, false);
3792 test("text", "", "Roboto", "Homemade Apple", 4, true);
3793 }
3794
DEF_TEST(SkParagraph_CacheStyles,reporter)3795 DEF_TEST(SkParagraph_CacheStyles, reporter) {
3796 ParagraphCache cache;
3797 sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
3798 if (!fontCollection->fontsFound()) return;
3799
3800 ParagraphStyle paragraph_style;
3801 paragraph_style.turnHintingOff();
3802
3803 TextStyle text_style;
3804 text_style.setFontFamilies({SkString("Roboto")});
3805 text_style.setColor(SK_ColorBLACK);
3806
3807 auto test = [&](int count, bool expectedToBeFound) {
3808 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3809 builder.pushStyle(text_style);
3810 builder.addText("text");
3811 builder.pop();
3812 auto paragraph = builder.Build();
3813 auto impl = static_cast<ParagraphImpl*>(paragraph.get());
3814
3815 impl->getResolver().findAllFontsForAllStyledBlocks(impl);
3816
3817 REPORTER_ASSERT(reporter, count == cache.count());
3818 auto found = cache.findParagraph(impl);
3819 REPORTER_ASSERT(reporter, found == expectedToBeFound);
3820 auto added = cache.updateParagraph(impl);
3821 REPORTER_ASSERT(reporter, added != expectedToBeFound);
3822 };
3823
3824 test(0, false);
3825 test(1, true);
3826 text_style.setLetterSpacing(10);
3827 test(1, false);
3828 test(2, true);
3829 text_style.setWordSpacing(10);
3830 test(2, false);
3831 }
3832