• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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