1// Copyright 2019 Google LLC.
2#include "include/core/SkCanvas.h"
3#include "include/core/SkColorFilter.h"
4#include "include/core/SkColorPriv.h"
5#include "include/core/SkFontMgr.h"
6#include "include/core/SkGraphics.h"
7#include "include/core/SkPath.h"
8#include "include/core/SkRegion.h"
9#include "include/core/SkShader.h"
10#include "include/core/SkStream.h"
11#include "include/core/SkTextBlob.h"
12#include "include/core/SkTime.h"
13#include "include/core/SkTypeface.h"
14#include "include/effects/SkGradientShader.h"
15#include "include/utils/SkRandom.h"
16#include "modules/skparagraph/include/Paragraph.h"
17#include "modules/skparagraph/include/TypefaceFontProvider.h"
18#include "modules/skparagraph/src/ParagraphBuilderImpl.h"
19#include "modules/skparagraph/src/ParagraphImpl.h"
20#include "modules/skparagraph/src/TextLine.h"
21#include "modules/skparagraph/utils/TestFontCollection.h"
22#include "samplecode/Sample.h"
23#include "src/core/SkOSFile.h"
24#include "src/shaders/SkColorShader.h"
25#include "src/utils/SkOSPath.h"
26#include "src/utils/SkUTF.h"
27#include "tools/Resources.h"
28#include "tools/flags/CommandLineFlags.h"
29
30static DEFINE_bool(verboseParagraph, false, "paragraph samples very verbose.");
31
32using namespace skia::textlayout;
33namespace {
34
35class ParagraphView_Base : public Sample {
36protected:
37    sk_sp<TestFontCollection> getFontCollection() {
38        // If we reset font collection we need to reset paragraph cache
39        static sk_sp<TestFontCollection> fFC = nullptr;
40        if (fFC == nullptr) {
41            fFC = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
42        }
43        return fFC;
44    }
45
46    bool isVerbose() {
47        return FLAGS_verboseParagraph;
48    }
49};
50
51sk_sp<SkShader> setgrad(const SkRect& r, SkColor c0, SkColor c1) {
52    SkColor colors[] = {c0, c1};
53    SkPoint pts[] = {{r.fLeft, r.fTop}, {r.fRight, r.fTop}};
54    return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
55}
56/*
57void writeHtml(const char* name, Paragraph* paragraph) {
58        SkString tmpDir = skiatest::GetTmpDir();
59        if (!tmpDir.isEmpty()) {
60            SkString path = SkOSPath::Join(tmpDir.c_str(), name);
61            SkFILEWStream file(path.c_str());
62            file.write(nullptr, 0);
63        }
64}
65*/
66
67class ParagraphView1 : public ParagraphView_Base {
68protected:
69    SkString name() override { return SkString("Paragraph1"); }
70
71    void drawTest(SkCanvas* canvas, SkScalar w, SkScalar h, SkColor fg, SkColor bg) {
72        const std::vector<
73            std::tuple<std::string, bool, bool, int, SkColor, SkColor, bool, TextDecorationStyle>>
74            gParagraph = {{"monospace", true, false, 14, SK_ColorWHITE, SK_ColorRED, true,
75                           TextDecorationStyle::kDashed},
76                          {"Assyrian", false, false, 20, SK_ColorWHITE, SK_ColorBLUE, false,
77                           TextDecorationStyle::kDotted},
78                          {"serif", true, true, 10, SK_ColorWHITE, SK_ColorRED, true,
79                           TextDecorationStyle::kDouble},
80                          {"Arial", false, true, 16, SK_ColorGRAY, SK_ColorGREEN, true,
81                           TextDecorationStyle::kSolid},
82                          {"sans-serif", false, false, 8, SK_ColorWHITE, SK_ColorRED, false,
83                           TextDecorationStyle::kWavy}};
84        SkAutoCanvasRestore acr(canvas, true);
85
86        canvas->clipRect(SkRect::MakeWH(w, h));
87        canvas->drawColor(SK_ColorWHITE);
88
89        SkScalar margin = 20;
90
91        SkPaint paint;
92        paint.setAntiAlias(true);
93        paint.setColor(fg);
94
95        SkPaint blue;
96        blue.setColor(SK_ColorBLUE);
97
98        TextStyle defaultStyle;
99        defaultStyle.setBackgroundColor(blue);
100        defaultStyle.setForegroundColor(paint);
101        ParagraphStyle paraStyle;
102
103        auto fontCollection = sk_make_sp<FontCollection>();
104        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
105        for (auto i = 1; i < 5; ++i) {
106            defaultStyle.setFontSize(24 * i);
107            paraStyle.setTextStyle(defaultStyle);
108            ParagraphBuilderImpl builder(paraStyle, fontCollection);
109            std::string name = "Paragraph: " + std::to_string(24 * i);
110            builder.addText(name.c_str(), name.length());
111            for (auto para : gParagraph) {
112                TextStyle style;
113                style.setFontFamilies({SkString(std::get<0>(para).c_str())});
114                SkFontStyle fontStyle(std::get<1>(para) ? SkFontStyle::Weight::kBold_Weight
115                                                        : SkFontStyle::Weight::kNormal_Weight,
116                                      SkFontStyle::Width::kNormal_Width,
117                                      std::get<2>(para) ? SkFontStyle::Slant::kItalic_Slant
118                                                        : SkFontStyle::Slant::kUpright_Slant);
119                style.setFontStyle(fontStyle);
120                style.setFontSize(std::get<3>(para) * i);
121                SkPaint background;
122                background.setColor(std::get<4>(para));
123                style.setBackgroundColor(background);
124                SkPaint foreground;
125                foreground.setColor(std::get<5>(para));
126                foreground.setAntiAlias(true);
127                style.setForegroundColor(foreground);
128                if (std::get<6>(para)) {
129                    style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(5, 5), 2));
130                }
131
132                auto decoration = (i % 4);
133                if (decoration == 3) {
134                    decoration = 4;
135                }
136
137                bool test = (TextDecoration)decoration != TextDecoration::kNoDecoration;
138                std::string deco = std::to_string((int)decoration);
139                if (test) {
140                    style.setDecoration((TextDecoration)decoration);
141                    style.setDecorationStyle(std::get<7>(para));
142                    style.setDecorationColor(std::get<5>(para));
143                }
144                builder.pushStyle(style);
145                name = " " + std::get<0>(para) + " " +
146                       (std::get<1>(para) ? ", bold" : "") +
147                       (std::get<2>(para) ? ", italic" : "") + " " +
148                       std::to_string(std::get<3>(para) * i) +
149                       (std::get<4>(para) != bg ? ", background" : "") +
150                       (std::get<5>(para) != fg ? ", foreground" : "") +
151                       (std::get<6>(para) ? ", shadow" : "") +
152                       (test ? ", decorations " + deco : "") + ";";
153                builder.addText(name.c_str(), name.length());
154                builder.pop();
155            }
156
157            auto paragraph = builder.Build();
158            paragraph->layout(w - margin * 2);
159            paragraph->paint(canvas, margin, margin);
160
161            canvas->translate(0, paragraph->getHeight());
162        }
163    }
164
165    void onDrawContent(SkCanvas* canvas) override {
166        drawTest(canvas, this->width(), this->height(), SK_ColorRED, SK_ColorWHITE);
167    }
168
169private:
170
171    using INHERITED = Sample;
172};
173
174class ParagraphView2 : public ParagraphView_Base {
175protected:
176    SkString name() override { return SkString("Paragraph2"); }
177
178    void drawCode(SkCanvas* canvas, SkScalar w, SkScalar h) {
179        SkPaint comment;
180        comment.setColor(SK_ColorGRAY);
181        SkPaint constant;
182        constant.setColor(SK_ColorMAGENTA);
183        SkPaint null;
184        null.setColor(SK_ColorMAGENTA);
185        SkPaint literal;
186        literal.setColor(SK_ColorGREEN);
187        SkPaint code;
188        code.setColor(SK_ColorDKGRAY);
189        SkPaint number;
190        number.setColor(SK_ColorBLUE);
191        SkPaint name;
192        name.setColor(SK_ColorRED);
193
194        SkPaint white;
195        white.setColor(SK_ColorWHITE);
196
197        TextStyle defaultStyle;
198        defaultStyle.setBackgroundColor(white);
199        defaultStyle.setForegroundColor(code);
200        defaultStyle.setFontFamilies({SkString("monospace")});
201        defaultStyle.setFontSize(30);
202        ParagraphStyle paraStyle;
203        paraStyle.setTextStyle(defaultStyle);
204
205        auto fontCollection = sk_make_sp<FontCollection>();
206        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
207        ParagraphBuilderImpl builder(paraStyle, fontCollection);
208
209        const char* text1 = "RaisedButton";
210        const char* text2 = "(\n";
211        const char* text3 = "  child: ";
212        const char* text4 = "const";
213        const char* text5 = "Text";
214        const char* text6 = "'BUTTON TITLE'";
215        const char* text7 = "),\n";
216
217        builder.pushStyle(style(name));
218        builder.addText(text1, strlen(text1));
219        builder.pop();
220        builder.addText(text2, strlen(text2));
221        builder.addText(text3, strlen(text3));
222        builder.pushStyle(style(constant));
223        builder.addText(text4, strlen(text4));
224        builder.pop();
225        builder.addText(" ", 1);
226        builder.pushStyle(style(name));
227        builder.addText(text5, strlen(text5));
228        builder.pop();
229        builder.addText("(", 1);
230        builder.pushStyle(style(literal));
231        builder.addText(text6, strlen(text6));
232        builder.pop();
233        builder.addText(text7, strlen(text7));
234
235        auto paragraph = builder.Build();
236        paragraph->layout(w - 20);
237
238        paragraph->paint(canvas, 20, 20);
239    }
240
241    TextStyle style(SkPaint paint) {
242        TextStyle style;
243        paint.setAntiAlias(true);
244        style.setForegroundColor(paint);
245        style.setFontFamilies({SkString("monospace")});
246        style.setFontSize(30);
247
248        return style;
249    }
250
251    void drawText(SkCanvas* canvas, SkScalar w, SkScalar h, std::vector<const char*>& text,
252                  SkColor fg = SK_ColorDKGRAY, SkColor bg = SK_ColorWHITE,
253                  const char* ff = "sans-serif", SkScalar fs = 24,
254                  size_t lineLimit = 30,
255                  const std::u16string& ellipsis = u"\u2026") {
256        SkAutoCanvasRestore acr(canvas, true);
257
258        canvas->clipRect(SkRect::MakeWH(w, h));
259        canvas->drawColor(bg);
260
261        SkScalar margin = 20;
262
263        SkPaint paint;
264        paint.setAntiAlias(true);
265        paint.setColor(fg);
266
267        SkPaint blue;
268        blue.setColor(SK_ColorBLUE);
269
270        SkPaint background;
271        background.setColor(bg);
272
273        TextStyle style;
274        style.setBackgroundColor(blue);
275        style.setForegroundColor(paint);
276        style.setFontFamilies({SkString(ff)});
277        style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight,
278                                       SkFontStyle::kNormal_Width,
279                                       SkFontStyle::kUpright_Slant));
280        style.setFontSize(fs);
281        ParagraphStyle paraStyle;
282        paraStyle.setTextStyle(style);
283        paraStyle.setMaxLines(lineLimit);
284
285        paraStyle.setEllipsis(ellipsis);
286        TextStyle defaultStyle;
287        defaultStyle.setFontSize(20);
288        paraStyle.setTextStyle(defaultStyle);
289        ParagraphBuilderImpl builder(paraStyle, getFontCollection());
290
291        SkPaint foreground;
292        foreground.setColor(fg);
293        style.setForegroundColor(foreground);
294        style.setBackgroundColor(background);
295
296        for (auto& part : text) {
297            builder.pushStyle(style);
298            builder.addText(part, strlen(part));
299            builder.pop();
300        }
301
302        auto paragraph = builder.Build();
303        paragraph->layout(w - margin * 2);
304        paragraph->paint(canvas, margin, margin);
305
306        canvas->translate(0, paragraph->getHeight() + margin);
307    }
308
309    void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
310                  TextAlign align) {
311        SkAutoCanvasRestore acr(canvas, true);
312
313        canvas->clipRect(SkRect::MakeWH(w, h));
314        canvas->drawColor(SK_ColorWHITE);
315
316        SkScalar margin = 20;
317
318        SkPaint paint;
319        paint.setAntiAlias(true);
320        paint.setColor(SK_ColorBLUE);
321
322        SkPaint gray;
323        gray.setColor(SK_ColorLTGRAY);
324
325        TextStyle style;
326        style.setBackgroundColor(gray);
327        style.setForegroundColor(paint);
328        style.setFontFamilies({SkString("Arial")});
329        style.setFontSize(30);
330        ParagraphStyle paraStyle;
331        paraStyle.setTextStyle(style);
332        paraStyle.setTextAlign(align);
333
334        auto fontCollection = sk_make_sp<FontCollection>();
335        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
336        ParagraphBuilderImpl builder(paraStyle, fontCollection);
337        builder.addText(text.c_str(), text.length());
338
339        auto paragraph = builder.Build();
340        paragraph->layout(w - margin * 2);
341        paragraph->layout(w - margin);
342        paragraph->paint(canvas, margin, margin);
343
344        canvas->translate(0, paragraph->getHeight() + margin);
345    }
346
347    void onDrawContent(SkCanvas* canvas) override {
348        std::vector<const char*> cupertino = {
349                "google_logogoogle_gsuper_g_logo 1 "
350                "google_logogoogle_gsuper_g_logo 12 "
351                "google_logogoogle_gsuper_g_logo 123 "
352                "google_logogoogle_gsuper_g_logo 1234 "
353                "google_logogoogle_gsuper_g_logo 12345 "
354                "google_logogoogle_gsuper_g_logo 123456 "
355                "google_logogoogle_gsuper_g_logo 1234567 "
356                "google_logogoogle_gsuper_g_logo 12345678 "
357                "google_logogoogle_gsuper_g_logo 123456789 "
358                "google_logogoogle_gsuper_g_logo 1234567890 "
359                "google_logogoogle_gsuper_g_logo 123456789 "
360                "google_logogoogle_gsuper_g_logo 12345678 "
361                "google_logogoogle_gsuper_g_logo 1234567 "
362                "google_logogoogle_gsuper_g_logo 123456 "
363                "google_logogoogle_gsuper_g_logo 12345 "
364                "google_logogoogle_gsuper_g_logo 1234 "
365                "google_logogoogle_gsuper_g_logo 123 "
366                "google_logogoogle_gsuper_g_logo 12 "
367                "google_logogoogle_gsuper_g_logo 1 "
368                "google_logogoogle_gsuper_g_logo "
369                "google_logogoogle_gsuper_g_logo "
370                "google_logogoogle_gsuper_g_logo "
371                "google_logogoogle_gsuper_g_logo "
372                "google_logogoogle_gsuper_g_logo "
373                "google_logogoogle_gsuper_g_logo"};
374        std::vector<const char*> text = {
375                "My neighbor came over to say,\n"
376                "Although not in a neighborly way,\n\n"
377                "That he'd knock me around,\n\n\n"
378                "If I didn't stop the sound,\n\n\n\n"
379                "Of the classical music I play."};
380
381        std::vector<const char*> long_word = {
382                "A_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
383                "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
384                "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
385                "very_very_very_very_very_very_very_long_text"};
386
387        std::vector<const char*> very_long = {
388                "A very very very very very very very very very very very very very very very very "
389                "very very very very very very very very very very very very very very very very "
390                "very very very very very very very very very very very very very very very very "
391                "very very very very very very very long text"};
392
393        std::vector<const char*> very_word = {
394                "A very_very_very_very_very_very_very_very_very_very "
395                "very_very_very_very_very_very_very_very_very_very very very very very very very "
396                "very very very very very very very very very very very very very very very very "
397                "very very very very very very very very very very very very very long text"};
398
399        SkScalar width = this->width() / 5;
400        SkScalar height = this->height();
401        drawText(canvas, width, height, long_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
402        canvas->translate(width, 0);
403        drawText(canvas, width, height, very_long, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
404        canvas->translate(width, 0);
405        drawText(canvas, width, height, very_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
406        canvas->translate(width, 0);
407        drawText(canvas, width, height / 2, text, SK_ColorBLACK, SK_ColorWHITE, "Roboto", 20, 100,
408                 u"\u2026");
409        canvas->translate(0, height / 2);
410        drawCode(canvas, width, height / 2);
411        canvas->translate(width, -height / 2);
412
413        drawText(canvas, width, height, cupertino, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
414    }
415
416private:
417    using INHERITED = Sample;
418};
419
420class ParagraphView3 : public ParagraphView_Base {
421protected:
422    SkString name() override { return SkString("Paragraph3"); }
423
424    void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
425                  TextAlign align, size_t lineLimit = std::numeric_limits<size_t>::max(),
426                  bool RTL = false, SkColor background = SK_ColorGRAY,
427                  const std::u16string& ellipsis = u"\u2026") {
428        SkAutoCanvasRestore acr(canvas, true);
429
430        canvas->clipRect(SkRect::MakeWH(w, h));
431        canvas->drawColor(SK_ColorWHITE);
432
433        SkScalar margin = 20;
434
435        SkPaint paint;
436        paint.setAntiAlias(true);
437        paint.setColor(SK_ColorBLACK);
438
439        SkPaint gray;
440        gray.setColor(background);
441
442        SkPaint yellow;
443        yellow.setColor(SK_ColorYELLOW);
444
445        TextStyle style;
446        style.setBackgroundColor(gray);
447        style.setForegroundColor(paint);
448        style.setFontFamilies({SkString("sans-serif")});
449        style.setFontSize(30);
450        ParagraphStyle paraStyle;
451        paraStyle.setTextStyle(style);
452        paraStyle.setTextAlign(align);
453        paraStyle.setMaxLines(lineLimit);
454        paraStyle.setEllipsis(ellipsis);
455        // paraStyle.setTextDirection(RTL ? SkTextDirection::rtl : SkTextDirection::ltr);
456
457        auto fontCollection = sk_make_sp<FontCollection>();
458        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
459        ParagraphBuilderImpl builder(paraStyle, fontCollection);
460        if (RTL) {
461            builder.addText(mirror(text));
462        } else {
463            builder.addText(normal(text));
464        }
465
466        canvas->drawRect(SkRect::MakeXYWH(margin, margin, w - margin * 2, h - margin * 2), yellow);
467        auto paragraph = builder.Build();
468        paragraph->layout(w - margin * 2);
469        paragraph->paint(canvas, margin, margin);
470    }
471
472    std::u16string mirror(const std::string& text) {
473        std::u16string result;
474        result += u"\u202E";
475        // for (auto i = text.size(); i > 0; --i) {
476        //  result += text[i - 1];
477        //}
478
479        for (auto i = text.size(); i > 0; --i) {
480            auto ch = text[i - 1];
481            if (ch == ',') {
482                result += u"!";
483            } else if (ch == '.') {
484                result += u"!";
485            } else {
486                result += ch;
487            }
488        }
489
490        result += u"\u202C";
491        return result;
492    }
493
494    std::u16string normal(const std::string& text) {
495        std::u16string result;
496        result += u"\u202D";
497        for (auto ch : text) {
498            result += ch;
499        }
500        result += u"\u202C";
501        return result;
502    }
503
504    void onDrawContent(SkCanvas* canvas) override {
505        const std::string options =  // { "open-source open-source open-source open-source" };
506                {"Flutter is an open-source project to help developers "
507                 "build high-performance, high-fidelity, mobile apps for "
508                 "iOS and Android "
509                 "from a single codebase. This design lab is a playground "
510                 "and showcase of Flutter's many widgets, behaviors, "
511                 "animations, layouts, and more."};
512
513        canvas->drawColor(SK_ColorDKGRAY);
514        SkScalar width = this->width() / 4;
515        SkScalar height = this->height() / 2;
516
517        const std::string line =
518                "World domination is such an ugly phrase - I prefer to call it world optimisation";
519
520        drawLine(canvas, width, height, line, TextAlign::kLeft, 1, false, SK_ColorLTGRAY);
521        canvas->translate(width, 0);
522        drawLine(canvas, width, height, line, TextAlign::kRight, 2, false, SK_ColorLTGRAY);
523        canvas->translate(width, 0);
524        drawLine(canvas, width, height, line, TextAlign::kCenter, 3, false, SK_ColorLTGRAY);
525        canvas->translate(width, 0);
526        drawLine(canvas, width, height, line, TextAlign::kJustify, 4, false, SK_ColorLTGRAY);
527        canvas->translate(-width * 3, height);
528
529        drawLine(canvas, width, height, line, TextAlign::kLeft, 1, true, SK_ColorLTGRAY);
530        canvas->translate(width, 0);
531        drawLine(canvas, width, height, line, TextAlign::kRight, 2, true, SK_ColorLTGRAY);
532        canvas->translate(width, 0);
533        drawLine(canvas, width, height, line, TextAlign::kCenter, 3, true, SK_ColorLTGRAY);
534        canvas->translate(width, 0);
535        drawLine(canvas, width, height, line, TextAlign::kJustify, 4, true, SK_ColorLTGRAY);
536        canvas->translate(width, 0);
537    }
538
539private:
540    using INHERITED = Sample;
541};
542
543class ParagraphView4 : public ParagraphView_Base {
544protected:
545    SkString name() override { return SkString("Paragraph4"); }
546
547    void drawFlutter(SkCanvas* canvas, SkScalar w, SkScalar h,
548                     const char* ff = "Google Sans", SkScalar fs = 30,
549                     size_t lineLimit = std::numeric_limits<size_t>::max(),
550                     const std::u16string& ellipsis = u"\u2026") {
551        SkAutoCanvasRestore acr(canvas, true);
552
553        canvas->clipRect(SkRect::MakeWH(w, h));
554
555        SkScalar margin = 20;
556
557        SkPaint black;
558        black.setAntiAlias(true);
559        black.setColor(SK_ColorBLACK);
560
561        SkPaint blue;
562        blue.setAntiAlias(true);
563        blue.setColor(SK_ColorBLUE);
564
565        SkPaint red;
566        red.setAntiAlias(true);
567        red.setColor(SK_ColorRED);
568
569        SkPaint green;
570        green.setAntiAlias(true);
571        green.setColor(SK_ColorGREEN);
572
573        SkPaint gray;
574        gray.setColor(SK_ColorLTGRAY);
575
576        SkPaint yellow;
577        yellow.setColor(SK_ColorYELLOW);
578
579        SkPaint magenta;
580        magenta.setAntiAlias(true);
581        magenta.setColor(SK_ColorMAGENTA);
582
583        TextStyle style;
584        style.setFontFamilies({SkString(ff)});
585        style.setFontSize(fs);
586
587        TextStyle style0;
588        style0.setForegroundColor(black);
589        style0.setBackgroundColor(gray);
590        style0.setFontFamilies({SkString(ff)});
591        style0.setFontSize(fs);
592        style0.setDecoration(TextDecoration::kUnderline);
593        style0.setDecorationStyle(TextDecorationStyle::kDouble);
594        style0.setDecorationColor(SK_ColorBLACK);
595
596        TextStyle style1;
597        style1.setForegroundColor(blue);
598        style1.setBackgroundColor(yellow);
599        style1.setFontFamilies({SkString(ff)});
600        style1.setFontSize(fs);
601        style1.setDecoration(TextDecoration::kOverline);
602        style1.setDecorationStyle(TextDecorationStyle::kWavy);
603        style1.setDecorationColor(SK_ColorBLACK);
604
605        TextStyle style2;
606        style2.setForegroundColor(red);
607        style2.setFontFamilies({SkString(ff)});
608        style2.setFontSize(fs);
609
610        TextStyle style3;
611        style3.setForegroundColor(green);
612        style3.setFontFamilies({SkString(ff)});
613        style3.setFontSize(fs);
614
615        TextStyle style4;
616        style4.setForegroundColor(magenta);
617        style4.setFontFamilies({SkString(ff)});
618        style4.setFontSize(fs);
619
620        ParagraphStyle paraStyle;
621        paraStyle.setTextStyle(style);
622        paraStyle.setMaxLines(lineLimit);
623
624        paraStyle.setEllipsis(ellipsis);
625
626        const char* logo1 = "google_";
627        const char* logo2 = "logo";
628        const char* logo3 = "go";
629        const char* logo4 = "ogle_logo";
630        const char* logo5 = "google_lo";
631        const char* logo6 = "go";
632        {
633            ParagraphBuilderImpl builder(paraStyle, getFontCollection());
634
635            builder.pushStyle(style0);
636            builder.addText(logo1, strlen(logo1));
637            builder.pop();
638            builder.pushStyle(style1);
639            builder.addText(logo2, strlen(logo2));
640            builder.pop();
641
642            builder.addText(" ", 1);
643
644            builder.pushStyle(style0);
645            builder.addText(logo3, strlen(logo3));
646            builder.pop();
647            builder.pushStyle(style1);
648            builder.addText(logo4, strlen(logo4));
649            builder.pop();
650
651            builder.addText(" ", 1);
652
653            builder.pushStyle(style0);
654            builder.addText(logo5, strlen(logo5));
655            builder.pop();
656            builder.pushStyle(style1);
657            builder.addText(logo6, strlen(logo6));
658            builder.pop();
659
660            auto paragraph = builder.Build();
661            paragraph->layout(w - margin * 2);
662            paragraph->paint(canvas, margin, margin);
663            canvas->translate(0, h + margin);
664        }
665    }
666
667    void onDrawContent(SkCanvas* canvas) override {
668        canvas->drawColor(SK_ColorWHITE);
669        SkScalar width = this->width();
670        SkScalar height = this->height();
671
672        drawFlutter(canvas, width, height / 2);
673    }
674
675private:
676    using INHERITED = Sample;
677};
678
679class ParagraphView5 : public ParagraphView_Base {
680protected:
681    SkString name() override { return SkString("Paragraph5"); }
682
683    void bidi(SkCanvas* canvas, SkScalar w, SkScalar h, const std::u16string& text,
684              const std::u16string& expected, size_t lineLimit = std::numeric_limits<size_t>::max(),
685              const char* ff = "Roboto", SkScalar fs = 30,
686              const std::u16string& ellipsis = u"\u2026") {
687        SkAutoCanvasRestore acr(canvas, true);
688
689        canvas->clipRect(SkRect::MakeWH(w, h));
690
691        SkScalar margin = 20;
692
693        SkPaint black;
694        black.setColor(SK_ColorBLACK);
695        SkPaint gray;
696        gray.setColor(SK_ColorLTGRAY);
697
698        TextStyle style;
699        style.setForegroundColor(black);
700        style.setFontFamilies({SkString(ff)});
701        style.setFontSize(fs);
702
703        TextStyle style0;
704        style0.setForegroundColor(black);
705        style0.setFontFamilies({SkString(ff)});
706        style0.setFontSize(fs);
707        style0.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
708                                        SkFontStyle::kItalic_Slant));
709
710        TextStyle style1;
711        style1.setForegroundColor(gray);
712        style1.setFontFamilies({SkString(ff)});
713        style1.setFontSize(fs);
714        style1.setFontStyle(SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
715                                        SkFontStyle::kUpright_Slant));
716
717        ParagraphStyle paraStyle;
718        paraStyle.setTextStyle(style);
719        paraStyle.setMaxLines(lineLimit);
720
721        paraStyle.setEllipsis(ellipsis);
722
723        ParagraphBuilderImpl builder(paraStyle, getFontCollection());
724
725        if (text.empty()) {
726            const std::u16string text0 = u"\u202Dabc";
727            const std::u16string text1 = u"\u202EFED";
728            const std::u16string text2 = u"\u202Dghi";
729            const std::u16string text3 = u"\u202ELKJ";
730            const std::u16string text4 = u"\u202Dmno";
731            builder.pushStyle(style0);
732            builder.addText(text0);
733            builder.pop();
734            builder.pushStyle(style1);
735            builder.addText(text1);
736            builder.pop();
737            builder.pushStyle(style0);
738            builder.addText(text2);
739            builder.pop();
740            builder.pushStyle(style1);
741            builder.addText(text3);
742            builder.pop();
743            builder.pushStyle(style0);
744            builder.addText(text4);
745            builder.pop();
746        } else {
747            builder.addText(text + expected);
748        }
749
750        auto paragraph = builder.Build();
751        auto impl = static_cast<ParagraphImpl*>(paragraph.get());
752        if (this->isVerbose()) {
753            SkDebugf("Text: >%s<\n", impl->text().data());
754        }
755
756        paragraph->layout(w - margin * 2);
757        paragraph->paint(canvas, margin, margin);
758    }
759
760    void onDrawContent(SkCanvas* canvas) override {
761        canvas->drawColor(SK_ColorWHITE);
762        SkScalar width = this->width();
763        SkScalar height = this->height() / 8;
764
765        const std::u16string text1 =
766                u"A \u202ENAC\u202Cner, exceedingly \u202ENAC\u202Cny,\n"
767                "One morning remarked to his granny:\n"
768                "A \u202ENAC\u202Cner \u202ENAC\u202C \u202ENAC\u202C,\n"
769                "Anything that he \u202ENAC\u202C,\n"
770                "But a \u202ENAC\u202Cner \u202ENAC\u202C't \u202ENAC\u202C a \u202ENAC\u202C, "
771                "\u202ENAC\u202C he?";
772        bidi(canvas, width, height * 3, text1, u"", 5);
773        canvas->translate(0, height * 3);
774
775        bidi(canvas, width, height, u"\u2067DETALOSI\u2069", u"");
776        canvas->translate(0, height);
777
778        bidi(canvas, width, height, u"\u202BDEDDEBME\u202C", u"");
779        canvas->translate(0, height);
780
781        bidi(canvas, width, height, u"\u202EEDIRREVO\u202C", u"");
782        canvas->translate(0, height);
783
784        bidi(canvas, width, height, u"\u200FTICILPMI\u200E", u"");
785        canvas->translate(0, height);
786
787        bidi(canvas, width, height, u"123 456 7890 \u202EZYXWV UTS RQP ONM LKJ IHG FED CBA\u202C.",
788             u"", 2);
789        canvas->translate(0, height);
790
791        // bidi(canvas, width, height, u"", u"");
792        // canvas->translate(0, height);
793    }
794
795private:
796    using INHERITED = Sample;
797};
798
799class ParagraphView6 : public ParagraphView_Base {
800protected:
801    SkString name() override { return SkString("Paragraph6"); }
802
803    void hangingS(SkCanvas* canvas, SkScalar w, SkScalar h, SkScalar fs = 60.0) {
804        auto ff = "HangingS";
805
806        canvas->drawColor(SK_ColorLTGRAY);
807
808        SkPaint black;
809        black.setAntiAlias(true);
810        black.setColor(SK_ColorBLACK);
811
812        SkPaint blue;
813        blue.setAntiAlias(true);
814        blue.setColor(SK_ColorBLUE);
815
816        SkPaint red;
817        red.setAntiAlias(true);
818        red.setColor(SK_ColorRED);
819
820        SkPaint green;
821        green.setAntiAlias(true);
822        green.setColor(SK_ColorGREEN);
823
824        SkPaint gray;
825        gray.setColor(SK_ColorCYAN);
826
827        SkPaint yellow;
828        yellow.setColor(SK_ColorYELLOW);
829
830        SkPaint magenta;
831        magenta.setAntiAlias(true);
832        magenta.setColor(SK_ColorMAGENTA);
833
834        SkFontStyle fontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
835                              SkFontStyle::kItalic_Slant);
836
837        TextStyle style;
838        style.setFontFamilies({SkString(ff)});
839        style.setFontSize(fs);
840        style.setFontStyle(fontStyle);
841
842        TextStyle style0;
843        style0.setForegroundColor(black);
844        style0.setBackgroundColor(gray);
845        style0.setFontFamilies({SkString(ff)});
846        style0.setFontSize(fs);
847        style0.setFontStyle(fontStyle);
848
849        TextStyle style1;
850        style1.setForegroundColor(blue);
851        style1.setBackgroundColor(yellow);
852        style1.setFontFamilies({SkString(ff)});
853        style1.setFontSize(fs);
854        style1.setFontStyle(fontStyle);
855
856        TextStyle style2;
857        style2.setForegroundColor(red);
858        style2.setFontFamilies({SkString(ff)});
859        style2.setFontSize(fs);
860        style2.setFontStyle(fontStyle);
861
862        TextStyle style3;
863        style3.setForegroundColor(green);
864        style3.setFontFamilies({SkString(ff)});
865        style3.setFontSize(fs);
866        style3.setFontStyle(fontStyle);
867
868        TextStyle style4;
869        style4.setForegroundColor(magenta);
870        style4.setFontFamilies({SkString(ff)});
871        style4.setFontSize(fs);
872        style4.setFontStyle(fontStyle);
873
874        ParagraphStyle paraStyle;
875        paraStyle.setTextStyle(style);
876
877        const char* logo1 = "S";
878        const char* logo2 = "kia";
879        const char* logo3 = "Sk";
880        const char* logo4 = "ia";
881        const char* logo5 = "Ski";
882        const char* logo6 = "a";
883        {
884            ParagraphBuilderImpl builder(paraStyle, getFontCollection());
885
886            builder.pushStyle(style0);
887            builder.addText(logo1, strlen(logo1));
888            builder.pop();
889            builder.pushStyle(style1);
890            builder.addText(logo2, strlen(logo2));
891            builder.pop();
892
893            builder.addText("   ", 3);
894
895            builder.pushStyle(style0);
896            builder.addText(logo3, strlen(logo3));
897            builder.pop();
898            builder.pushStyle(style1);
899            builder.addText(logo4, strlen(logo4));
900            builder.pop();
901
902            builder.addText("   ", 3);
903
904            builder.pushStyle(style0);
905            builder.addText(logo5, strlen(logo5));
906            builder.pop();
907            builder.pushStyle(style1);
908            builder.addText(logo6, strlen(logo6));
909            builder.pop();
910
911            auto paragraph = builder.Build();
912            paragraph->layout(w);
913            paragraph->paint(canvas, 40, 40);
914            canvas->translate(0, h);
915        }
916
917        const char* logo11 = "S";
918        const char* logo12 = "S";
919        const char* logo13 = "S";
920        const char* logo14 = "S";
921        const char* logo15 = "S";
922        const char* logo16 = "S";
923        {
924            ParagraphBuilderImpl builder(paraStyle, getFontCollection());
925
926            builder.pushStyle(style0);
927            builder.addText(logo11, strlen(logo1));
928            builder.pop();
929            builder.pushStyle(style1);
930            builder.addText(logo12, strlen(logo2));
931            builder.pop();
932
933            builder.addText("   ", 3);
934
935            builder.pushStyle(style0);
936            builder.addText(logo13, strlen(logo3));
937            builder.pop();
938            builder.pushStyle(style1);
939            builder.addText(logo14, strlen(logo4));
940            builder.pop();
941
942            builder.addText("   ", 3);
943
944            builder.pushStyle(style0);
945            builder.addText(logo15, strlen(logo5));
946            builder.pop();
947            builder.pushStyle(style1);
948            builder.addText(logo16, strlen(logo6));
949            builder.pop();
950
951            auto paragraph = builder.Build();
952            paragraph->layout(w);
953            paragraph->paint(canvas, 40, h);
954            canvas->translate(0, h);
955        }
956    }
957
958    void onDrawContent(SkCanvas* canvas) override {
959        canvas->drawColor(SK_ColorWHITE);
960        SkScalar width = this->width();
961        SkScalar height = this->height() / 4;
962
963        hangingS(canvas, width, height);
964    }
965
966private:
967    using INHERITED = Sample;
968};
969
970class ParagraphView7 : public ParagraphView_Base {
971protected:
972    SkString name() override { return SkString("Paragraph7"); }
973
974    void drawText(SkCanvas* canvas, SkColor background, SkScalar letterSpace, SkScalar w,
975                  SkScalar h) {
976        SkAutoCanvasRestore acr(canvas, true);
977        canvas->clipRect(SkRect::MakeWH(w, h));
978        canvas->drawColor(background);
979
980        const char* line =
981                "World domination is such an ugly phrase - I prefer to call it world optimisation.";
982
983        ParagraphStyle paragraphStyle;
984        paragraphStyle.setTextAlign(TextAlign::kLeft);
985        paragraphStyle.setMaxLines(10);
986        paragraphStyle.turnHintingOff();
987        TextStyle textStyle;
988        textStyle.setFontFamilies({SkString("Roboto")});
989        textStyle.setFontSize(30);
990        textStyle.setLetterSpacing(letterSpace);
991        textStyle.setColor(SK_ColorBLACK);
992        textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
993                                           SkFontStyle::kUpright_Slant));
994
995        ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
996        builder.pushStyle(textStyle);
997        builder.addText(line, strlen(line));
998        builder.pop();
999
1000        auto paragraph = builder.Build();
1001        paragraph->layout(w - 20);
1002        paragraph->paint(canvas, 10, 10);
1003    }
1004
1005    void onDrawContent(SkCanvas* canvas) override {
1006        canvas->drawColor(SK_ColorWHITE);
1007
1008        auto h = this->height() / 4;
1009        auto w = this->width() / 2;
1010
1011        drawText(canvas, SK_ColorGRAY, 1, w, h);
1012        canvas->translate(0, h);
1013
1014        drawText(canvas, SK_ColorLTGRAY, 2, w, h);
1015        canvas->translate(0, h);
1016
1017        drawText(canvas, SK_ColorCYAN, 3, w, h);
1018        canvas->translate(0, h);
1019
1020        drawText(canvas, SK_ColorGRAY, 4, w, h);
1021        canvas->translate(w, -3 * h);
1022
1023        drawText(canvas, SK_ColorYELLOW, 5, w, h);
1024        canvas->translate(0, h);
1025
1026        drawText(canvas, SK_ColorGREEN, 10, w, h);
1027        canvas->translate(0, h);
1028
1029        drawText(canvas, SK_ColorRED, 15, w, h);
1030        canvas->translate(0, h);
1031
1032        drawText(canvas, SK_ColorBLUE, 20, w, h);
1033        canvas->translate(0, h);
1034    }
1035
1036private:
1037    using INHERITED = Sample;
1038};
1039
1040class ParagraphView8 : public ParagraphView_Base {
1041protected:
1042    SkString name() override { return SkString("Paragraph8"); }
1043
1044    void drawText(SkCanvas* canvas, SkColor background, SkScalar wordSpace, SkScalar w,
1045                  SkScalar h) {
1046        SkAutoCanvasRestore acr(canvas, true);
1047        canvas->clipRect(SkRect::MakeWH(w, h));
1048        canvas->drawColor(background);
1049
1050        const char* line =
1051                "World domination is such an ugly phrase - I prefer to call it world optimisation.";
1052
1053        ParagraphStyle paragraphStyle;
1054        paragraphStyle.setTextAlign(TextAlign::kLeft);
1055        paragraphStyle.setMaxLines(10);
1056        paragraphStyle.turnHintingOff();
1057        TextStyle textStyle;
1058        textStyle.setFontFamilies({SkString("Roboto")});
1059        textStyle.setFontSize(30);
1060        textStyle.setWordSpacing(wordSpace);
1061        textStyle.setColor(SK_ColorBLACK);
1062        textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1063                                           SkFontStyle::kUpright_Slant));
1064
1065        ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
1066        builder.pushStyle(textStyle);
1067        builder.addText(line, strlen(line));
1068        builder.pop();
1069
1070        auto paragraph = builder.Build();
1071        paragraph->layout(w - 20);
1072        paragraph->paint(canvas, 10, 10);
1073    }
1074
1075    void onDrawContent(SkCanvas* canvas) override {
1076        canvas->drawColor(SK_ColorWHITE);
1077
1078        auto h = this->height() / 4;
1079        auto w = this->width() / 2;
1080
1081        drawText(canvas, SK_ColorGRAY, 1, w, h);
1082        canvas->translate(0, h);
1083
1084        drawText(canvas, SK_ColorLTGRAY, 2, w, h);
1085        canvas->translate(0, h);
1086
1087        drawText(canvas, SK_ColorCYAN, 3, w, h);
1088        canvas->translate(0, h);
1089
1090        drawText(canvas, SK_ColorGRAY, 4, w, h);
1091        canvas->translate(w, -3 * h);
1092
1093        drawText(canvas, SK_ColorYELLOW, 5, w, h);
1094        canvas->translate(0, h);
1095
1096        drawText(canvas, SK_ColorGREEN, 10, w, h);
1097        canvas->translate(0, h);
1098
1099        drawText(canvas, SK_ColorRED, 15, w, h);
1100        canvas->translate(0, h);
1101
1102        drawText(canvas, SK_ColorBLUE, 20, w, h);
1103        canvas->translate(0, h);
1104    }
1105
1106private:
1107    using INHERITED = Sample;
1108};
1109
1110class ParagraphView9 : public ParagraphView_Base {
1111protected:
1112    SkString name() override { return SkString("Paragraph9"); }
1113
1114    bool onChar(SkUnichar uni) override {
1115            switch (uni) {
1116                case 'w':
1117                    ++wordSpacing;
1118                    return true;
1119                case 'q':
1120                    if (wordSpacing > 0) --wordSpacing;
1121                    return true;
1122                case 'l':
1123                    ++letterSpacing;
1124                    return true;
1125                case 'k':
1126                    if (letterSpacing > 0) --letterSpacing;
1127                    return true;
1128                default:
1129                    break;
1130            }
1131            return false;
1132    }
1133
1134    void drawText(SkCanvas* canvas, SkColor background, SkScalar w, SkScalar h) {
1135        SkAutoCanvasRestore acr(canvas, true);
1136        canvas->clipRect(SkRect::MakeWH(w, h));
1137        canvas->drawColor(background);
1138
1139        auto fontCollection = sk_make_sp<FontCollection>();
1140        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1141        fontCollection->enableFontFallback();
1142
1143        const char* text =
1144                "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1145                " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1146                " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
1147        auto multiplier = 5.67;
1148        ParagraphStyle paragraphStyle;
1149        paragraphStyle.setTextAlign(TextAlign::kLeft);
1150        paragraphStyle.setMaxLines(10);
1151        paragraphStyle.turnHintingOff();
1152        TextStyle textStyle;
1153        textStyle.setFontFamilies({SkString("Roboto")});
1154        textStyle.setFontSize(5 * multiplier);
1155        textStyle.setHeight(1.3f);
1156        textStyle.setColor(SK_ColorBLACK);
1157        textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1158                                           SkFontStyle::kUpright_Slant));
1159
1160        ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1161        builder.pushStyle(textStyle);
1162        builder.addText(text, strlen(text));
1163        builder.pop();
1164
1165        auto paragraph = builder.Build();
1166        paragraph->layout(200 * multiplier);
1167
1168        std::vector<size_t> sizes = {0, 1, 2, 8, 19, 21, 22, 30, 150};
1169
1170        std::vector<size_t> colors = {SK_ColorBLUE, SK_ColorCYAN,  SK_ColorLTGRAY, SK_ColorGREEN,
1171                                      SK_ColorRED,  SK_ColorWHITE, SK_ColorYELLOW, SK_ColorMAGENTA};
1172
1173        RectHeightStyle rect_height_style = RectHeightStyle::kTight;
1174        RectWidthStyle rect_width_style = RectWidthStyle::kTight;
1175
1176        for (size_t i = 0; i < sizes.size() - 1; ++i) {
1177            size_t from = sizes[i];
1178            size_t to = sizes[i + 1];
1179            auto boxes = paragraph->getRectsForRange(from, to, rect_height_style, rect_width_style);
1180            if (boxes.empty()) {
1181                continue;
1182            }
1183            for (auto& box : boxes) {
1184                SkPaint paint;
1185                paint.setColor(colors[i % colors.size()]);
1186                paint.setShader(setgrad(box.rect, colors[i % colors.size()], SK_ColorWHITE));
1187                canvas->drawRect(box.rect, paint);
1188            }
1189        }
1190
1191        paragraph->paint(canvas, 0, 0);
1192    }
1193
1194    void onDrawContent(SkCanvas* canvas) override {
1195        canvas->drawColor(SK_ColorWHITE);
1196
1197        auto h = this->height();
1198        auto w = this->width();
1199
1200        drawText(canvas, SK_ColorGRAY, w, h);
1201    }
1202
1203private:
1204    using INHERITED = Sample;
1205    SkScalar letterSpacing;
1206    SkScalar wordSpacing;
1207};
1208
1209class ParagraphView10 : public ParagraphView_Base {
1210protected:
1211    SkString name() override { return SkString("Paragraph10"); }
1212
1213    void onDrawContent(SkCanvas* canvas) override {
1214        canvas->drawColor(SK_ColorWHITE);
1215        auto multiplier = 5.67;
1216        const char* text = "English English 字典 字典 ��� ���";
1217
1218        auto fontCollection = sk_make_sp<FontCollection>();
1219        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1220        fontCollection->enableFontFallback();
1221
1222        ParagraphStyle paragraph_style;
1223        paragraph_style.turnHintingOff();
1224        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1225
1226        TextStyle text_style;
1227        text_style.setFontFamilies({SkString("Roboto"),
1228                                    SkString("Noto Color Emoji"),
1229                                    SkString("Noto Serif CJK JP")});
1230        text_style.setFontSize(10 * multiplier);
1231        text_style.setLetterSpacing(0);
1232        text_style.setWordSpacing(0);
1233        text_style.setColor(SK_ColorBLACK);
1234        text_style.setHeight(1);
1235        builder.pushStyle(text_style);
1236        builder.addText(text, strlen(text));
1237        builder.pop();
1238
1239        auto paragraph = builder.Build();
1240        paragraph->layout(width());
1241
1242        paragraph->paint(canvas, 0, 0);
1243    }
1244
1245private:
1246    using INHERITED = Sample;
1247};
1248
1249class ParagraphView11 : public ParagraphView_Base {
1250protected:
1251    SkString name() override { return SkString("Paragraph11"); }
1252
1253    void onDrawContent(SkCanvas* canvas) override {
1254        canvas->drawColor(SK_ColorWHITE);
1255
1256        auto text = "\U0001f469\U0000200D\U0001f469\U0000200D\U0001f466\U0001f469\U0000200D\U0001f469\U0000200D\U0001f467\U0000200D\U0001f467\U0001f1fa\U0001f1f8";
1257
1258        TextStyle text_style;
1259        text_style.setFontFamilies({SkString("Ahem")});
1260        text_style.setColor(SK_ColorBLACK);
1261        text_style.setFontSize(60);
1262        text_style.setLetterSpacing(0);
1263        text_style.setWordSpacing(0);
1264        ParagraphStyle paragraph_style;
1265        paragraph_style.setTextStyle(text_style);
1266
1267        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), true, true);
1268        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1269        builder.addText(text, strlen(text));
1270        auto paragraph = builder.Build();
1271        paragraph->layout(1000);
1272        paragraph->paint(canvas, 0, 0);
1273
1274        struct pair {
1275            unsigned fX;
1276            unsigned fY;
1277        };
1278
1279        pair hit1[] =
1280              {{ 0, 8},{1, 33}, {2, 34}, { 3, 19}, {4, 20},
1281               { 5, 21}, { 6, 22 }, { 7, 23 }, {8, 24 }, { 9, 25},
1282               { 10, 26}, { 11, 27}, {12, 28}, { 13, 21}, {14, 22 },
1283               { 15, 23}, {16, 24}, {17, 21}, { 18, 22}, {19, 21},
1284               { 20, 24}, { 21, 23}, };
1285
1286        pair miss[] =
1287              {{ 0, 4},{1, 17}, {2, 18}, { 3, 11}, {4, 12},
1288               { 5, 13}, { 6, 14 }, { 7, 15 }, {8, 16 }, { 9, 17},
1289               { 10, 18}, { 11, 19}, {12, 20}, { 13, 17}, {14, 18 },
1290               { 15, 19}, {16, 20}, {17, 19}, { 18, 20},
1291               { 20, 22}, };
1292
1293        auto rects = paragraph->getRectsForRange(7, 9, RectHeightStyle::kTight,
1294                                                 RectWidthStyle::kTight);
1295        SkPaint paint;
1296        paint.setColor(SK_ColorRED);
1297        paint.setStyle(SkPaint::kStroke_Style);
1298        paint.setAntiAlias(true);
1299        paint.setStrokeWidth(1);
1300        if (!rects.empty()) {
1301            canvas->drawRect(rects[0].rect, paint);
1302        }
1303
1304        for (auto& query : hit1) {
1305            auto hitRects = paragraph->getRectsForRange(query.fX, query.fY, RectHeightStyle::kTight,
1306                                                        RectWidthStyle::kTight);
1307            if (hitRects.size() >= 1 && hitRects[0].rect.width() > 0) {
1308            } else {
1309                if (this->isVerbose()) {
1310                    SkDebugf("+[%d:%d): Bad\n", query.fX, query.fY);
1311                }
1312            }
1313        }
1314
1315        for (auto& query : miss) {
1316            auto missRects = paragraph->getRectsForRange(query.fX, query.fY,
1317                                                         RectHeightStyle::kTight,
1318                                                         RectWidthStyle::kTight);
1319            if (missRects.empty()) {
1320            } else {
1321                if (this->isVerbose()) {
1322                    SkDebugf("-[%d:%d): Bad\n", query.fX, query.fY);
1323                }
1324            }
1325        }
1326    }
1327
1328private:
1329    using INHERITED = Sample;
1330};
1331
1332class ParagraphView12 : public ParagraphView_Base {
1333protected:
1334    SkString name() override { return SkString("Paragraph12"); }
1335
1336    void onDrawContent(SkCanvas* canvas) override {
1337        canvas->drawColor(SK_ColorWHITE);
1338
1339        const char* text = "Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges";
1340        TextStyle text_style;
1341        text_style.setFontFamilies({SkString("Ahem")});
1342        text_style.setColor(SK_ColorBLACK);
1343        text_style.setFontSize(16);
1344        //text_style.setLetterSpacing(-0.41);
1345        StrutStyle strut_style;
1346        strut_style.setStrutEnabled(false);
1347        ParagraphStyle paragraph_style;
1348        paragraph_style.setStrutStyle(strut_style);
1349        paragraph_style.setTextStyle(text_style);
1350        ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1351        builder.addText(text);
1352        auto paragraph = builder.Build();
1353        paragraph->layout(1095.000000);
1354        auto result = paragraph->getRectsForRange(65, 66, RectHeightStyle::kTight, RectWidthStyle::kTight);
1355        paragraph->paint(canvas, 0, 0);
1356
1357        SkPaint paint;
1358        paint.setColor(SK_ColorRED);
1359        paint.setStyle(SkPaint::kStroke_Style);
1360        paint.setAntiAlias(true);
1361        paint.setStrokeWidth(1);
1362        if (!result.empty()) {
1363            canvas->drawRect(result.front().rect, paint);
1364        }
1365    }
1366
1367private:
1368    using INHERITED = Sample;
1369};
1370
1371class ParagraphView14 : public ParagraphView_Base {
1372protected:
1373    SkString name() override { return SkString("Paragraph14"); }
1374
1375    void onDrawContent(SkCanvas* canvas) override {
1376        canvas->drawColor(SK_ColorWHITE);
1377        TextStyle text_style;
1378        text_style.setFontFamilies({SkString("Ahem")});
1379        text_style.setColor(SK_ColorBLACK);
1380        text_style.setFontSize(25);
1381        text_style.setDecoration((TextDecoration)(TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
1382        text_style.setDecorationColor(SK_ColorBLUE);
1383        text_style.setDecorationStyle(TextDecorationStyle::kWavy);
1384        text_style.setDecorationThicknessMultiplier(4.0f);
1385        ParagraphStyle paragraph_style;
1386        paragraph_style.setTextStyle(text_style);
1387        paragraph_style.setTextDirection(TextDirection::kRtl);
1388        ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1389        builder.pushStyle(text_style);
1390        builder.addText("Hello, wor!\nabcd.");
1391        auto paragraph = builder.Build();
1392        paragraph->layout(300);
1393        paragraph->paint(canvas, 0, 0);
1394        SkPaint paint;
1395        paint.setColor(SK_ColorRED);
1396        paint.setStyle(SkPaint::kStroke_Style);
1397        paint.setAntiAlias(true);
1398        paint.setStrokeWidth(1);
1399        canvas->drawRect(SkRect::MakeXYWH(0, 0, 300, 100), paint);
1400    }
1401
1402private:
1403    using INHERITED = Sample;
1404};
1405
1406class ParagraphView15 : public ParagraphView_Base {
1407protected:
1408    SkString name() override { return SkString("Paragraph15"); }
1409
1410    void onDrawContent(SkCanvas* canvas) override {
1411        canvas->drawColor(SK_ColorWHITE);
1412
1413        TextStyle text_style;
1414        text_style.setFontFamilies({SkString("abc.ttf")});
1415        text_style.setFontSize(50);
1416
1417        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false);
1418
1419        fontCollection->addFontFromFile("abc/abc.ttf", "abc");
1420        fontCollection->addFontFromFile("abc/abc+grave.ttf", "abc+grave");
1421        fontCollection->addFontFromFile("abc/abc+agrave.ttf", "abc+agrave");
1422
1423        ParagraphStyle paragraph_style;
1424        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1425
1426        text_style.setFontFamilies({SkString("abc"), SkString("abc+grave")});
1427        text_style.setColor(SK_ColorBLUE);
1428        builder.pushStyle(text_style);
1429        builder.addText(u"a\u0300");
1430        text_style.setColor(SK_ColorMAGENTA);
1431        builder.pushStyle(text_style);
1432        builder.addText(u"à");
1433
1434        text_style.setFontFamilies({SkString("abc"), SkString("abc+agrave")});
1435
1436        text_style.setColor(SK_ColorRED);
1437        builder.pushStyle(text_style);
1438        builder.addText(u"a\u0300");
1439        text_style.setColor(SK_ColorGREEN);
1440        builder.pushStyle(text_style);
1441        builder.addText(u"à");
1442
1443        auto paragraph = builder.Build();
1444        paragraph->layout(800);
1445        paragraph->paint(canvas, 50, 50);
1446
1447    }
1448
1449private:
1450    using INHERITED = Sample;
1451};
1452
1453class ParagraphView16 : public ParagraphView_Base {
1454protected:
1455    SkString name() override { return SkString("Paragraph16"); }
1456
1457    void onDrawContent(SkCanvas* canvas) override {
1458        canvas->drawColor(SK_ColorWHITE);
1459
1460        const char* text = "content";
1461
1462        ParagraphStyle paragraph_style;
1463        paragraph_style.setMaxLines(1);
1464        paragraph_style.setEllipsis(u"\u2026");
1465        //auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
1466        auto fontCollection = sk_make_sp<FontCollection>();
1467        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1468        fontCollection->enableFontFallback();
1469        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1470
1471        TextStyle text_style;
1472        text_style.setFontFamilies({SkString(".SF Pro Text")});
1473        text_style.setColor(SK_ColorBLACK);
1474        text_style.setFontSize(17.0f * 99.0f);
1475        text_style.setLetterSpacing(0.41f);
1476        builder.pushStyle(text_style);
1477        builder.addText(text);
1478
1479        auto paragraph = builder.Build();
1480        paragraph->layout(800);
1481        paragraph->paint(canvas, 0, 0);
1482    }
1483
1484private:
1485    using INHERITED = Sample;
1486};
1487
1488class ParagraphView17 : public ParagraphView_Base {
1489protected:
1490    SkString name() override { return SkString("Paragraph17"); }
1491
1492    void onDrawContent(SkCanvas* canvas) override {
1493        canvas->drawColor(SK_ColorWHITE);
1494
1495        auto fontCollection = sk_make_sp<FontCollection>();
1496        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1497        fontCollection->enableFontFallback();
1498        auto navy = SkColorSetRGB(0, 0, 139);
1499        auto ltgray = SkColorSetRGB(211, 211, 211);
1500        auto multiplier = 5.67;
1501
1502        //const char* text = ">Sͬ͑̀͐̈͒̈́̋̎ͮͩ̽̓ͬ̂̆̔͗́̓ͣͧ͊ͫ͛̉͌̐̑ͪ͗̚͝҉̴͉͢k̡̊̓ͫͭͩ͂͊ͨͪͬ̑ͫ̍̌̄͛̌̂̑̂̋̊̔ͫ͛̽̑ͨ̍ͭ̓̀ͪͪ̉͐͗̌̓̃̚͟͝҉̢͏̫̞̙͇͖̮͕̗̟͕͇͚̻͈̣̻̪͉̰̲̣̫ͅͅP̴̅̍͒̿͗͗̇ͩ̃͆͌̀̽͏̧̡͕͖̝̖̼̺̰̣̬͔͖͔̼͙̞̦̫͓̘͜a̸̴̸̴̢̢̨̨̫͍͓̥̼̭̼̻̤̯̙̤̻̠͚̍̌͋̂ͦͨ̽̇͌͌͆̀̽̎͒̄ͪ̐ͦ̈ͫ͐͗̓̚̚͜ͅr͐͐ͤͫ̐ͥ͂̈́̿́ͮ̃͗̓̏ͫ̀̿͏̸̵̧́͘̕͟͝͠͞͠҉̷̧͚͢͟a̓̽̎̄͗̔͛̄̐͊͛ͫ͂͌̂̂̈̈̓̔̅̅̄͊̉́ͪ̑̄͆ͬ̍͆ͭ͋̐ͬ͏̷̵̨̢̩̹̖͓̥̳̰͔̱̬͖̙͓̙͇̀̀̕͜͟͟͢͟͜͠͡g̨̅̇ͦ͋̂ͦͨͭ̓͐͆̏̂͛̉ͧ̑ͫ̐̒͛ͫ̍̒͛́̚҉̷̨̛̛̀͜͢͞҉̩̘̲͍͎̯̹̝̭̗̱͇͉̲̱͔̯̠̹̥̻͉̲̜̤̰̪̗̺̖̺r̷͌̓̇̅ͭ̀̐̃̃ͭ͑͗̉̈̇̈́ͥ̓ͣ́ͤ͂ͤ͂̏͌̆̚҉̴̸̧̢̢̛̫͉̦̥̤̙͈͉͈͉͓̙̗̟̳̜͈̗̺̟̠̠͖͓̖̪͕̠̕̕͝ͅả̸̴̡̡̧͠͞͡͞҉̛̕͟͏̷̘̪̱͈̲͉̞̠̞̪̫͎̲̬̖̀̀͟͝͞͞͠p̛͂̈͐̚͠҉̵̸̡̢̢̩̹͙̯͖̙̙̮̥̙͚̠͔̥̭̮̞̣̪̬̥̠̖̝̥̪͎́̀̕͜͡͡ͅͅh̵̷̵̡̛ͤ̂͌̐̓̐̋̋͊̒̆̽́̀̀̀͢͠͞͞҉̷̸̢̕҉͚̯͖̫̜̞̟̠̱͉̝̲̹̼͉̟͉̩̮͔̤͖̞̭̙̹̬ͅ<";
1503        const char* text = ">S͛ͭ̋͆̈̔̇͗̍͑̎ͪͮͧͣ̽ͫͣ́ͬ̀͌͑͂͗͒̍̔̄ͧ̏̉̌̊̊̿̀̌̃̄͐̓̓̚̚҉̵̡͜͟͝͠͏̸̵̡̧͜҉̷̡͇̜̘̻̺̘̟̝͙̬̘̩͇̭̼̥̖̤̦͎k͉̩̘͚̜̹̗̗͍̤̥̱͉̳͕͖̤̲̣͚̮̞̬̲͍͔̯̻̮̞̭͈̗̫͓̂ͨ̉ͪ̒͋͛̀̍͊ͧ̿̅͆̓̔̔ͬ̇̑̿ͩ͗ͮ̎͌̿̄ͅP̴̵̡̡̛̪͙̼̣̟̩̭̫̱͙̬͔͉͍̘̠͉̦̝̘̥̟̗͖̫̤͕̙̬̦͍̱̖̮̱͑͐̎̃̒͐͋̚͘͞a̶̶̵̵̵̶̶̡̧̢̢̺͔̣͖̭̺͍̤͚̱̜̰̥͕̬̥̲̞̥̘͇͚̺̰͚̪̺͔̤͍̓̿͆̎͋̓ͦ̈́ͦ̌́̄͗̌̓͌̕͜͜͟͢͝͡ŕ͎̝͕͉̻͎̤̭͚̗̳̖̙̘͚̫͖͓͚͉͔͈̟̰̟̬̗͓̟͚̱̕͡ͅͅͅa̸̶̢̛̛̽ͮͩ̅͒ͫ͗͂̎ͦ̈́̓̚͘͜͢͡҉̷̵̶̢̡̜̮̦̜̥̜̯̙͓͔̼̗̻͜͜ͅḡ̢̛͕̗͖̖̤̦̘͔ͨͨ̊͒ͩͭͤ̍̅̃ͪ̋̏̓̍̋͗̋ͨ̏̽̈́̔̀̋̉ͫ̅̂ͭͫ̏͒͋ͥ̚͜r̶̢̧̧̥̤̼̀̂̒ͪ͌̿͌̅͛ͨͪ͒̍ͥ̉ͤ̌̿̆́ͭ͆̃̒ͤ͛̊ͧ̽͘͝͠a̧̢̧̢͑͑̓͑ͮ̃͂̄͛́̈́͋̂͌̽̄͒̔́̇ͨͧͭ͐ͦ̋ͨ̍ͦ̍̋͆̔ͧ͑͋͌̈̓͛͛̚͢͜͜͏̴̢̧̛̳͍̹͚̰̹̻͔p̨̡͆ͦͣ͊̽̔͂̉ͣ̔ͣ̌̌̉̃̋̂͒ͫ̄̎̐͗̉̌̃̽̽́̀̚͘͜͟҉̱͉h̭̮̘̗͔̜̯͔͈̯̺͔̗̣̭͚̱̰̙̼̹͚̣̻̥̲̮͍̤͜͝<";
1504        ParagraphStyle paragraph_style;
1505        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1506        SkPaint paint;
1507        paint.setColor(ltgray);
1508        TextStyle text_style;
1509        text_style.setBackgroundColor(paint);
1510        text_style.setColor(navy);
1511        text_style.setFontFamilies({SkString("Roboto")});
1512        text_style.setFontSize(20 * multiplier);
1513        builder.pushStyle(text_style);
1514        builder.addText(text);
1515        auto paragraph = builder.Build();
1516        paragraph->layout(10000);
1517        paragraph->paint(canvas, 0, 0);
1518    }
1519
1520private:
1521    using INHERITED = Sample;
1522};
1523
1524class Zalgo {
1525    private:
1526    std::u16string COMBINING_DOWN = u"\u0316\u0317\u0318\u0319\u031c\u031d\u031e\u031f\u0320\u0324\u0325\u0326\u0329\u032a\u032b\u032c\u032d\u032e\u032f\u0330\u0331\u0332\u0333\u0339\u033a\u033b\u033c\u0345\u0347\u0348\u0349\u034d\u034e\u0353\u0354\u0355\u0356\u0359\u035a\u0323";
1527    std::u16string COMBINING_UP = u"\u030d\u030e\u0304\u0305\u033f\u0311\u0306\u0310\u0352\u0357\u0351\u0307\u0308\u030a\u0342\u0343\u0344\u034a\u034b\u034c\u0303\u0302\u030c\u0350\u0300\u0301\u030b\u030f\u0312\u0313\u0314\u033d\u0309\u0363\u0364\u0365\u0366\u0367\u0368\u0369\u036a\u036b\u036c\u036d\u036e\u035b\u0346\u031a";
1528    std::u16string COMBINING_MIDDLE = u"\u0315\u031b\u0340\u0341\u0358\u0321\u0322\u0327\u0328\u0334\u0335\u0336\u034f\u035c\u035d\u035e\u035f\u0360\u0362\u0338\u0337\u0361\u0489";
1529
1530    std::u16string randomMarks(std::u16string& combiningMarks) {
1531        std::u16string result;
1532        auto num = std::rand() % (combiningMarks.size() / 1);
1533        for (size_t i = 0; i < num; ++i) {
1534            auto index = std::rand() % combiningMarks.size();
1535            result += combiningMarks[index];
1536        }
1537        return result;
1538    }
1539
1540public:
1541    std::u16string zalgo(std::string victim) {
1542        std::u16string result;
1543        for (auto& c : victim) {
1544            result += c;
1545            result += randomMarks(COMBINING_UP);
1546            result += randomMarks(COMBINING_MIDDLE);
1547            result += randomMarks(COMBINING_DOWN);
1548        }
1549        return result;
1550    }
1551};
1552
1553class ParagraphView18 : public ParagraphView_Base {
1554protected:
1555    SkString name() override { return SkString("Paragraph18"); }
1556
1557    bool onChar(SkUnichar uni) override {
1558            switch (uni) {
1559                case ' ':
1560                    fLimit = 400;
1561                    return true;
1562                case 's':
1563                    fLimit += 10;
1564                    return true;
1565                case 'f':
1566                    if (fLimit > 10) {
1567                        fLimit -= 10;
1568                    }
1569                    return true;
1570                default:
1571                    break;
1572            }
1573            return false;
1574    }
1575
1576    bool onAnimate(double nanos) override {
1577        if (++fIndex > fLimit) {
1578            fRedraw = true;
1579            fIndex = 0;
1580        } else {
1581            fRepeat = true;
1582        }
1583        return true;
1584    }
1585
1586    void onDrawContent(SkCanvas* canvas) override {
1587        canvas->drawColor(SK_ColorWHITE);
1588
1589        auto navy = SkColorSetRGB(0, 0, 139);
1590        auto ltgray = SkColorSetRGB(211, 211, 211);
1591
1592        auto multiplier = 5.67;
1593        auto fontCollection = sk_make_sp<FontCollection>();
1594        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1595        fontCollection->enableFontFallback();
1596
1597        ParagraphStyle paragraph_style;
1598        TextStyle text_style;
1599        text_style.setFontFamilies({SkString("Roboto")});
1600        text_style.setFontSize(20 * multiplier);
1601        text_style.setColor(navy);
1602        SkPaint paint;
1603        paint.setColor(ltgray);
1604        text_style.setBackgroundColor(paint);
1605
1606        Zalgo zalgo;
1607
1608        if (fRedraw || fRepeat) {
1609
1610            if (fRedraw || fParagraph == nullptr) {
1611                ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1612                builder.pushStyle(text_style);
1613                auto utf16text = zalgo.zalgo("SkParagraph");
1614                builder.addText(utf16text);
1615                fParagraph = builder.Build();
1616            }
1617
1618            auto impl = static_cast<ParagraphImpl*>(fParagraph.get());
1619            if (this->isVerbose()) {
1620                SkDebugf("Text:>%s<\n", impl->text().data());
1621            }
1622            impl->setState(InternalState::kUnknown);
1623            fParagraph->layout(1000);
1624            fParagraph->paint(canvas, 300, 200);
1625
1626            for (auto& run : impl->runs()) {
1627                SkString fontFamily("unresolved");
1628                if (run.font().getTypeface() != nullptr) {
1629                    run.font().getTypeface()->getFamilyName(&fontFamily);
1630                }
1631                if (run.font().getTypeface() != nullptr) {
1632                    for (size_t i = 0; i < run.size(); ++i) {
1633                        auto glyph = run.glyphs().begin() + i;
1634                        if (*glyph == 0) {
1635                            //SkDebugf("Run[%d] @pos=%d\n", run.index(), i);
1636                        }
1637                    }
1638                } else {
1639                    //SkDebugf("Run[%d]: %s\n", run.index(), fontFamily.c_str());
1640                }
1641            }
1642            fRedraw = false;
1643            fRepeat = false;
1644        }
1645    }
1646
1647private:
1648    bool fRedraw = true;
1649    bool fRepeat = false;
1650    size_t fIndex = 0;
1651    size_t fLimit = 20;
1652    std::unique_ptr<Paragraph> fParagraph;
1653    using INHERITED = Sample;
1654};
1655
1656class ParagraphView19 : public ParagraphView_Base {
1657protected:
1658    SkString name() override { return SkString("Paragraph19"); }
1659
1660    void onDrawContent(SkCanvas* canvas) override {
1661        canvas->drawColor(SK_ColorWHITE);
1662
1663        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
1664
1665        std::u16string text = u"\u0068\u0301\u0350\u0312\u0357\u030C\u0369\u0305\u036C\u0304\u0310\u033F\u0366\u0350\u0343\u0364\u0369\u0311\u0309\u030E\u0365\u031B\u0340\u0337\u0335\u035E\u0334\u0328\u0360\u0360\u0315\u035F\u0340\u0340\u0362\u0360\u0322\u031B\u031B\u0337\u0340\u031E\u031F\u032A\u0331\u0345\u032F\u0332\u032E\u0333\u0353\u0320\u0345\u031C\u031F\u033C\u0325\u0355\u032C\u0325\u033Aa\u0307\u0312\u034B\u0308\u0312\u0346\u0313\u0346\u0304\u0307\u0344\u0305\u0342\u0368\u0346\u036A\u035B\u030F\u0365\u0307\u0340\u0328\u0322\u0361\u0489\u034F\u0328\u0334\u035F\u0335\u0362\u0489\u0360\u0358\u035E\u0360\u035D\u0341\u0337\u0337\u032E\u0326\u032D\u0359\u0318\u033C\u032F\u0333\u035A\u034D\u0319\u031C\u0353\u033C\u0345\u0359\u0331\u033B\u0331\u033C";
1666        ParagraphStyle paragraph_style;
1667        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1668        TextStyle text_style;
1669        text_style.setColor(SK_ColorBLACK);
1670        text_style.setFontFamilies({SkString("Roboto")});
1671        text_style.setFontSize(20);
1672        builder.pushStyle(text_style);
1673        builder.addText(text);
1674        auto paragraph = builder.Build();
1675        paragraph->layout(this->width());
1676        paragraph->paint(canvas, 0, 0);
1677    }
1678
1679private:
1680    using INHERITED = Sample;
1681};
1682
1683class ParagraphView20 : public ParagraphView_Base {
1684protected:
1685    SkString name() override { return SkString("Paragraph20"); }
1686
1687    void onDrawContent(SkCanvas* canvas) override {
1688        canvas->drawColor(SK_ColorWHITE);
1689
1690        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
1691
1692        const char* text =  "Manage your google account";
1693        ParagraphStyle paragraph_style;
1694        paragraph_style.setEllipsis(u"\u2026");
1695        paragraph_style.setMaxLines(1);
1696        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1697        TextStyle text_style;
1698        text_style.setColor(SK_ColorBLACK);
1699        text_style.setFontFamilies({SkString("Roboto")});
1700        text_style.setFontSize(50);
1701        builder.pushStyle(text_style);
1702        builder.addText(text);
1703        auto paragraph = builder.Build();
1704        paragraph->layout(this->width());
1705        paragraph->paint(canvas, 0, 0);
1706    }
1707
1708private:
1709    using INHERITED = Sample;
1710};
1711
1712class ParagraphView21 : public ParagraphView_Base {
1713protected:
1714    SkString name() override { return SkString("Paragraph21"); }
1715
1716    void onDrawContent(SkCanvas* canvas) override {
1717        canvas->drawColor(SK_ColorWHITE);
1718
1719        const char* text =  "Referral Code";
1720        ParagraphStyle paragraph_style;
1721        ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1722        TextStyle text_style;
1723        text_style.setColor(SK_ColorBLACK);
1724        text_style.setFontFamilies({SkString("Google Sans")});
1725        text_style.setFontSize(24);
1726        builder.pushStyle(text_style);
1727        builder.addText(text);
1728        auto paragraph = builder.Build();
1729        paragraph->layout(0);
1730        paragraph->paint(canvas, 0, 0);
1731    }
1732
1733private:
1734    using INHERITED = Sample;
1735};
1736
1737class ParagraphView22 : public ParagraphView_Base {
1738protected:
1739    SkString name() override { return SkString("Paragraph22"); }
1740
1741    bool onChar(SkUnichar uni) override {
1742            switch (uni) {
1743                case 'l':
1744                    direction = true;
1745                    return true;
1746                case 'r':
1747                    direction = false;
1748                    return true;
1749                default:
1750                    break;
1751            }
1752            return false;
1753    }
1754
1755    void onDrawContent(SkCanvas* canvas) override {
1756
1757        canvas->drawColor(SK_ColorWHITE);
1758        ParagraphStyle paragraph_style;
1759        paragraph_style.setTextDirection(direction ? TextDirection::kLtr : TextDirection::kRtl);
1760        auto collection = getFontCollection();
1761        ParagraphBuilderImpl builder(paragraph_style, collection);
1762        collection->getParagraphCache()->reset();
1763        collection->getParagraphCache()->turnOn(false);
1764        TextStyle text_style;
1765        text_style.setColor(SK_ColorBLACK);
1766        text_style.setFontFamilies({SkString("Roboto")});
1767        text_style.setFontSize(12);
1768        builder.pushStyle(text_style);
1769        builder.addText("I have got a ");
1770        text_style.setFontStyle(SkFontStyle::Bold());
1771        builder.pushStyle(text_style);
1772        builder.addText("lovely bunch");
1773        text_style.setFontStyle(SkFontStyle::Normal());
1774        builder.pushStyle(text_style);
1775        builder.addText(" of coconuts.");
1776        auto paragraph = builder.Build();
1777        paragraph->layout(this->width());
1778        paragraph->paint(canvas, 0, 0);
1779        collection->getParagraphCache()->turnOn(true);
1780    }
1781
1782private:
1783    using INHERITED = Sample;
1784    bool direction;
1785};
1786
1787class ParagraphView23 : public ParagraphView_Base {
1788protected:
1789    SkString name() override { return SkString("Paragraph23"); }
1790
1791    void onDrawContent(SkCanvas* canvas) override {
1792        canvas->drawColor(SK_ColorWHITE);
1793
1794        const char* text =  "Text with shadow";
1795        ParagraphStyle paragraph_style;
1796        TextStyle text_style;
1797        text_style.setColor(SK_ColorBLACK);
1798        text_style.setFontFamilies({SkString("Google Sans")});
1799        text_style.setFontSize(24);
1800
1801        auto draw = [&](SkScalar h, SkScalar v, SkScalar b) {
1802            text_style.resetShadows();
1803            text_style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(h, v), b));
1804            ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1805            builder.pushStyle(text_style);
1806            builder.addText(text);
1807            auto paragraph = builder.Build();
1808            paragraph->layout(300);
1809            paragraph->paint(canvas, 0, 0);
1810
1811            auto rect = SkRect::MakeXYWH(0, 0, paragraph->getMaxWidth(), paragraph->getHeight());
1812            SkPaint paint;
1813            paint.setColor(SK_ColorRED);
1814            paint.setStyle(SkPaint::kStroke_Style);
1815            paint.setAntiAlias(true);
1816            paint.setStrokeWidth(1);
1817            canvas->drawRect(rect, paint);
1818        };
1819
1820        draw(10, 10, 5);
1821        canvas->translate(0, 100);
1822
1823        draw(10, -10, 5);
1824        canvas->translate(0, 100);
1825
1826        draw(-10, -10, 5);
1827        canvas->translate(0, 100);
1828
1829        draw(-10, 10, 5);
1830        canvas->translate(0, 100);
1831    }
1832
1833private:
1834    using INHERITED = Sample;
1835};
1836
1837class ParagraphView24 : public ParagraphView_Base {
1838protected:
1839    SkString name() override { return SkString("Paragraph24"); }
1840
1841    void onDrawContent(SkCanvas* canvas) override {
1842        canvas->drawColor(SK_ColorWHITE);
1843
1844        ParagraphStyle paragraph_style;
1845        paragraph_style.setTextDirection(TextDirection::kRtl);
1846        TextStyle text_style;
1847        text_style.setColor(SK_ColorBLACK);
1848        text_style.setFontFamilies({SkString("Google Sans")});
1849        text_style.setFontSize(24);
1850        {
1851            ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1852            builder.pushStyle(text_style);
1853            builder.addText("Right_to_left:");
1854            auto paragraph = builder.Build();
1855            paragraph->layout(this->width());
1856            paragraph->paint(canvas, 0, 0);
1857        }
1858        canvas->translate(0, 200);
1859        {
1860            ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1861            builder.pushStyle(text_style);
1862            builder.addText("Right_to_left+");
1863            auto paragraph = builder.Build();
1864            paragraph->layout(this->width());
1865            paragraph->paint(canvas, 0, 0);
1866        }
1867        canvas->translate(0, 200);
1868        {
1869            ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1870            builder.pushStyle(text_style);
1871            builder.addText("Right_to_left.");
1872            auto paragraph = builder.Build();
1873            paragraph->layout(this->width());
1874            paragraph->paint(canvas, 0, 0);
1875        }
1876    }
1877
1878private:
1879    using INHERITED = Sample;
1880};
1881
1882class ParagraphView25 : public ParagraphView_Base {
1883protected:
1884    SkString name() override { return SkString("Paragraph25"); }
1885
1886    void onDrawContent(SkCanvas* canvas) override {
1887        canvas->drawColor(SK_ColorWHITE);
1888/*
1889 * Shell: ParagraphStyle: 1.000000 1
1890Shell: Strut enabled: 0 1.000000 14.000000 400 5 0
1891Shell: Font Families: 0
1892Shell: DefaultTextStyle: 16.000000 500 5 0
1893Shell: Font Families: 1 Roboto
1894Shell: Font Features: 0
1895Shell: TextStyle#0: [0:22) 16.000000 500 5 0
1896Shell: Font Families: 1 Roboto
1897Shell: Font Features: 0
1898Shell: TextStyle#1: [25:49) 16.000000 500 5 0
1899Shell: Font Families: 1 Roboto
1900Shell: Font Features: 0
1901Shell: Placeholder#0: [22:25) 32.000000 32.000000 32.000000 0 5
1902Shell: Placeholder#1: [49:52) 19.000000 41.000000 19.000000 0 4
1903Shell: Placeholder#2: [52:52) 0.000000 0.000000 0.000000 0 5
1904Shell: layout('Go to device settings  and set up a passcode. ', 280.000000): 280.000000 * 38.000000
1905 */
1906        auto fontCollection = getFontCollection();
1907        //fontCollection->getParagraphCache()->turnOn(false);
1908        const char* text1 =  "Go to device settings ";
1909        const char* text2 = "and set up a passcode.";
1910        ParagraphStyle paragraph_style;
1911        StrutStyle strut_style;
1912        strut_style.setStrutEnabled(false);
1913        strut_style.setFontSize(14);
1914        strut_style.setForceStrutHeight(false);
1915        strut_style.setHeight(14);
1916        paragraph_style.setStrutStyle(strut_style);
1917        TextStyle text_style;
1918        text_style.setColor(SK_ColorBLACK);
1919        text_style.setFontFamilies({SkString("Roboto")});
1920        text_style.setFontSize(16);
1921        PlaceholderStyle placeholder_style;
1922        {
1923            ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1924            builder.pushStyle(text_style);
1925            builder.addText(text1);
1926            placeholder_style.fHeight = 32;
1927            placeholder_style.fWidth = 32;
1928            placeholder_style.fBaselineOffset = 32;
1929            placeholder_style.fBaseline = TextBaseline::kAlphabetic;
1930            placeholder_style.fAlignment = PlaceholderAlignment::kMiddle;
1931            builder.addPlaceholder(placeholder_style);
1932            builder.addText(text2);
1933            placeholder_style.fHeight = 19;
1934            placeholder_style.fWidth = 41;
1935            placeholder_style.fBaselineOffset = 19;
1936            placeholder_style.fBaseline = TextBaseline::kAlphabetic;
1937            placeholder_style.fAlignment = PlaceholderAlignment::kTop;
1938            builder.addPlaceholder(placeholder_style);
1939            auto paragraph = builder.Build();
1940            paragraph->layout(280);
1941            paragraph->paint(canvas, 0, 0);
1942        }
1943    }
1944
1945private:
1946    using INHERITED = Sample;
1947};
1948
1949class ParagraphView26 : public ParagraphView_Base {
1950protected:
1951    SkString name() override { return SkString("Paragraph26"); }
1952
1953    void onDrawContent(SkCanvas* canvas) override {
1954        auto fontCollection = sk_make_sp<FontCollection>();
1955        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1956        //fontCollection->enableFontFallback();
1957
1958        canvas->clear(SK_ColorWHITE);
1959
1960        SkPaint paint;
1961        paint.setAntiAlias(true);
1962        paint.setColor(SK_ColorBLACK);
1963
1964        TextStyle textStyle;
1965        textStyle.setForegroundColor(paint);
1966        textStyle.setFontFamilies({ SkString("Roboto") });
1967        textStyle.setFontSize(42.0f);
1968        textStyle.setLetterSpacing(-0.05f);
1969        textStyle.setHeightOverride(true);
1970
1971        ParagraphStyle paragraphStyle;
1972        paragraphStyle.setTextStyle(textStyle);
1973        paragraphStyle.setTextAlign(TextAlign::kLeft);
1974
1975        ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1976        builder.addText(u"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ut dolor ornare, fermentum nibh in, consectetur libero. Ut id semper est. Sed malesuada, est id bibendum egestas, urna risus tristique nibh, euismod interdum risus turpis nec purus. Maecenas dolor nisl, consectetur in vestibulum et, tincidunt id leo. Duis maximus, odio eget tristique commodo, lacus tellus dapibus leo, consequat pellentesque arcu nisi sit amet diam. Quisque euismod venenatis egestas. Mauris posuere volutpat iaculis. Suspendisse finibus tempor urna, dignissim venenatis sapien finibus eget. Donec interdum lacus ac venenatis fringilla. Curabitur eget lacinia augue. Vestibulum eu vulputate odio. Quisque nec imperdiet");
1977
1978        auto paragraph = builder.Build();
1979        paragraph->layout(this->width() / 2);
1980
1981        std::vector<LineMetrics> lines;
1982        paragraph->getLineMetrics(lines); // <-- error happens here
1983
1984        canvas->translate(10, 10);
1985        paragraph->paint(canvas, 0, 0);
1986    }
1987
1988private:
1989    using INHERITED = Sample;
1990};
1991
1992class ParagraphView27 : public ParagraphView_Base {
1993protected:
1994    SkString name() override { return SkString("Paragraph27"); }
1995
1996    void onDrawContent(SkCanvas* canvas) override {
1997        auto fontCollection = sk_make_sp<FontCollection>();
1998        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1999        fontCollection->enableFontFallback();
2000        fontCollection->getParagraphCache()->turnOn(false);
2001
2002        SkPaint red;
2003        red.setColor(SK_ColorRED);
2004        red.setStyle(SkPaint::kStroke_Style);
2005        red.setAntiAlias(true);
2006        red.setStrokeWidth(1);
2007
2008        SkPaint blue;
2009        blue.setColor(SK_ColorRED);
2010        blue.setStyle(SkPaint::kStroke_Style);
2011        blue.setAntiAlias(true);
2012        blue.setStrokeWidth(1);
2013
2014        SkPaint black;
2015        black.setColor(SK_ColorBLACK);
2016        black.setStyle(SkPaint::kStroke_Style);
2017        black.setAntiAlias(true);
2018        black.setStrokeWidth(1);
2019
2020        SkPaint whiteSpaces;
2021        whiteSpaces.setColor(SK_ColorLTGRAY);
2022
2023        SkPaint breakingSpace;
2024        breakingSpace.setColor(SK_ColorYELLOW);
2025
2026        SkPaint text;
2027        text.setColor(SK_ColorWHITE);
2028
2029        ParagraphStyle paragraph_style;
2030        paragraph_style.setTextAlign(TextAlign::kRight);
2031        TextStyle text_style;
2032        text_style.setColor(SK_ColorBLACK);
2033        text_style.setFontFamilies({SkString("Roboto")});
2034
2035        // RTL + right align + arabic
2036        // RTL + right align + latin
2037        // LTR + right align + arabic
2038        // LTR + right align + latin
2039        // RTL + left align + arabic
2040        // RTL + left align + latin
2041        // arabic and latin should not differ at all
2042        // check: line breaking and trailing spaces
2043
2044        canvas->drawColor(SK_ColorWHITE);
2045        auto h = 60;
2046        auto w = 300;
2047
2048        auto draw = [&](SkScalar width, SkScalar height, TextDirection td, TextAlign ta, const char* t) {
2049            if (this->isVerbose()) {
2050                SkDebugf("draw '%s' dir:%s align:%s\n", t,
2051                         td == TextDirection::kLtr ? "left" : "right",
2052                         ta == TextAlign::kLeft ? "left" : "right");
2053            }
2054            paragraph_style.setTextDirection(td);
2055            paragraph_style.setTextAlign(ta);
2056            text_style.setFontSize(20);
2057            ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2058            text_style.setBackgroundColor(whiteSpaces);
2059            builder.pushStyle(text_style);
2060            builder.addText("   ");
2061            text_style.setBackgroundColor(text);
2062            builder.pushStyle(text_style);
2063            builder.addText(t);
2064            text_style.setBackgroundColor(breakingSpace);
2065            builder.pushStyle(text_style);
2066            builder.addText(" ");
2067            text_style.setBackgroundColor(text);
2068            builder.pushStyle(text_style);
2069            builder.addText(t);
2070            text_style.setBackgroundColor(whiteSpaces);
2071            builder.pushStyle(text_style);
2072            builder.addText("   ");
2073            auto paragraph = builder.Build();
2074            paragraph->layout(width);
2075            paragraph->paint(canvas, 0, 0);
2076            auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2077            for (auto& line : impl->lines()) {
2078                if (this->isVerbose()) {
2079                    SkDebugf("line[%d]: %f + %f\n", (int)(&line - impl->lines().begin()),
2080                                                    line.offset().fX, line.shift());
2081                }
2082                line.iterateThroughVisualRuns(true,
2083                    [&](const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width) {
2084                    *width = line.measureTextInsideOneRun(textRange, run, runOffset, 0, true, false).clip.width();
2085                    if (this->isVerbose()) {
2086                        SkDebugf("%zu[%zu: %zu) @%f + %f %s\n",
2087                                 run->index(), textRange.start, textRange.end, runOffset, *width,
2088                                 run->leftToRight() ? "left" : "right");
2089                    }
2090                    return true;
2091                });
2092            }
2093            auto boxes = paragraph->getRectsForRange(0, 100, RectHeightStyle::kTight, RectWidthStyle::kTight);
2094            bool even = true;
2095            for (auto& box : boxes) {
2096                if (this->isVerbose()) {
2097                    SkDebugf("[%f:%f,%f:%f] %s\n",
2098                             box.rect.fLeft, box.rect.fRight, box.rect.fTop, box.rect.fBottom,
2099                             box.direction == TextDirection::kLtr ? "left" : "right");
2100                }
2101                canvas->drawRect(box.rect, even ? red : blue);
2102                even = !even;
2103            }
2104            canvas->translate(0, height);
2105        };
2106
2107        canvas->drawRect(SkRect::MakeXYWH(0, 0, w, h * 8), black);
2108
2109        draw(w, h, TextDirection::kRtl, TextAlign::kRight, "RTL+RIGHT#1234567890");
2110        draw(w, h, TextDirection::kRtl, TextAlign::kRight, "قففغغغغقففغغغغقففغغغ");
2111
2112        draw(w, h, TextDirection::kLtr, TextAlign::kRight, "LTR+RIGHT#1234567890");
2113        draw(w, h, TextDirection::kLtr, TextAlign::kRight, "قففغغغغقففغغغغقففغغغ");
2114
2115        draw(w, h, TextDirection::kRtl, TextAlign::kLeft, "RTL+LEFT##1234567890");
2116        draw(w, h, TextDirection::kRtl, TextAlign::kLeft, "قففغغغغقففغغغغقففغغغ");
2117
2118        draw(w, h, TextDirection::kLtr, TextAlign::kLeft, "LTR+LEFT##1234567890");
2119        draw(w, h, TextDirection::kLtr, TextAlign::kLeft, "قففغغغغقففغغغغقففغغغ");
2120    }
2121
2122private:
2123    using INHERITED = Sample;
2124};
2125
2126class ParagraphView28 : public ParagraphView_Base {
2127protected:
2128    SkString name() override { return SkString("Paragraph28"); }
2129
2130    void onDrawContent(SkCanvas* canvas) override {
2131
2132        const char* text = "AAAAA BBBBB CCCCC DDDDD EEEEE FFFFF GGGGG HHHHH IIIII JJJJJ KKKKK LLLLL MMMMM NNNNN OOOOO PPPPP QQQQQ";
2133
2134        canvas->drawColor(SK_ColorWHITE);
2135        ParagraphStyle paragraph_style;
2136        paragraph_style.setTextAlign(TextAlign::kJustify);
2137        auto collection = getFontCollection();
2138        ParagraphBuilderImpl builder(paragraph_style, collection);
2139        TextStyle text_style;
2140        text_style.setColor(SK_ColorBLACK);
2141        text_style.setFontFamilies({SkString("Roboto")});
2142        text_style.setFontSize(40);
2143        builder.pushStyle(text_style);
2144        builder.addText(text);
2145        auto paragraph = builder.Build();
2146        auto s = 186;
2147        paragraph->layout(360 - s);
2148        paragraph->paint(canvas, 0, 0);
2149        /*
2150        paragraph->layout(360);
2151        paragraph->paint(canvas, 0, 0);
2152        canvas->translate(0, 400);
2153        paragraph->layout(354.333);
2154        paragraph->paint(canvas, 0, 0);
2155        */
2156    }
2157
2158private:
2159    using INHERITED = Sample;
2160};
2161
2162class ParagraphView29 : public ParagraphView_Base {
2163protected:
2164    SkString name() override { return SkString("Paragraph29"); }
2165
2166    void onDrawContent(SkCanvas* canvas) override {
2167
2168        const char* text = "ffi";
2169        canvas->drawColor(SK_ColorWHITE);
2170
2171        auto collection = getFontCollection();
2172
2173        ParagraphStyle paragraph_style;
2174        ParagraphBuilderImpl builder(paragraph_style, collection);
2175        TextStyle text_style;
2176        text_style.setColor(SK_ColorBLACK);
2177        text_style.setFontFamilies({SkString("Roboto")});
2178        text_style.setFontSize(60);
2179        builder.pushStyle(text_style);
2180        builder.addText(text);
2181        auto paragraph = builder.Build();
2182        paragraph->layout(width());
2183        paragraph->paint(canvas, 0, 0);
2184        auto width = paragraph->getLongestLine();
2185        auto height = paragraph->getHeight();
2186        if (this->isVerbose()) {
2187            auto f1Pos = paragraph->getGlyphPositionAtCoordinate(width/6, height/2);
2188            auto f2Pos = paragraph->getGlyphPositionAtCoordinate(width/2, height/2);
2189            auto iPos = paragraph->getGlyphPositionAtCoordinate(width*5/6, height/2);
2190            SkDebugf("%d(%s) %d(%s) %d(%s)\n",
2191                     f1Pos.position, f1Pos.affinity == Affinity::kUpstream ? "up" : "down",
2192                     f2Pos.position, f2Pos.affinity == Affinity::kUpstream ? "up" : "down",
2193                     iPos.position, iPos.affinity == Affinity::kUpstream ? "up" : "down");
2194
2195            auto f1 = paragraph->getRectsForRange(0, 1, RectHeightStyle::kTight,
2196                                                  RectWidthStyle::kTight);
2197            if (f1.empty()) {
2198                SkDebugf("F1 is empty\n");
2199            } else {
2200                auto rf1 = f1[0];
2201                SkDebugf("f1: [%f:%f] %s\n", rf1.rect.fLeft, rf1.rect.fRight,
2202                                             rf1.direction == TextDirection::kRtl ? "rtl" : "ltr");
2203            }
2204
2205            auto f2 = paragraph->getRectsForRange(1, 2, RectHeightStyle::kTight,
2206                                                  RectWidthStyle::kTight);
2207            if (f2.empty()) {
2208                SkDebugf("F2 is empty\n");
2209            } else {
2210                auto rf2 = f2[0];
2211                SkDebugf("f2: [%f:%f] %s\n", rf2.rect.fLeft, rf2.rect.fRight,
2212                                             rf2.direction == TextDirection::kRtl ? "rtl" : "ltr");
2213            }
2214
2215            auto fi = paragraph->getRectsForRange(2, 3, RectHeightStyle::kTight,
2216                                                  RectWidthStyle::kTight);
2217            if (fi.empty()) {
2218                SkDebugf("FI is empty\n");
2219            } else {
2220                auto rfi = fi[0];
2221                SkDebugf("i:  [%f:%f] %s\n", rfi.rect.fLeft, rfi.rect.fRight,
2222                                             rfi.direction == TextDirection::kRtl ? "rtl" : "ltr");
2223            }
2224        }
2225    }
2226
2227private:
2228    using INHERITED = Sample;
2229};
2230
2231class ParagraphView30 : public ParagraphView_Base {
2232protected:
2233    SkString name() override { return SkString("Paragraph30"); }
2234
2235    void onDrawContent(SkCanvas* canvas) override {
2236
2237        const std::u16string text = //u"\U0001f600\U0001f1e6\U0001f1f9\U0001f601\U0001f9f1\U0001f61a\U0001f431\U0001f642\U0001f38e\U0001f60d\U0001f3b9\U0001f917\U0001f6bb\U0001f609\U0001f353\U0001f618\U0001f1eb\U0001f1f0\U0001f468\u200D\U0001f469\u200D\U0001f466\u200D\U0001f466\U0001f468\u200D\U0001f469\u200D\U0001f467\u200D\U0001f466\U0001f468\u200D\U0001f469\u200D\U0001f467\U0001f46a";
2238        u"\U0001f469\u200D\U0001f469\u200D\U0001f466\U0001f469\u200D\U0001f469\u200D\U0001f467\u200D\U0001f467\U0001f1fa\U0001f1f8";
2239        canvas->drawColor(SK_ColorWHITE);
2240
2241        auto fontCollection = sk_make_sp<FontCollection>();
2242        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2243        fontCollection->enableFontFallback();
2244
2245        ParagraphStyle paragraph_style;
2246        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2247        TextStyle text_style;
2248        text_style.setColor(SK_ColorBLACK);
2249        //text_style.setFontFamilies({SkString("Noto Color Emoji")});
2250        text_style.setFontFamilies({SkString("Ahem")});
2251        text_style.setFontSize(14);
2252        builder.pushStyle(text_style);
2253        builder.addText(text);
2254        auto paragraph = builder.Build();
2255        paragraph->layout(width());
2256        paragraph->paint(canvas, 0, 0);
2257        std::pair<size_t, size_t> rects[] = {
2258            { 0, 2}, { 0, 4}, {0, 8},
2259            {23, 25}, {23, 27}, {23, 31}, {23, 39}, {23, 55}, {21, 23},
2260            {1, 3}, {1, 5}, {1, 9}, {1, 17}, {1, 33},
2261            { 2, 4}, {2, 6}, {2, 10}, {2, 18}, {2, 34},
2262            {3, 5}, {3, 7}, {3, 11}, {3, 19},
2263            {4, 6}, {4, 8}, {4, 12}, {4, 20},
2264            {5, 7}, {5, 9}, {5, 13}, {5, 21},
2265            {6, 8}, {6, 10}, {6, 14}, {6, 22},
2266            {7, 9}, {7, 11}, {7, 15}, {7, 23},
2267            {8, 10}, {8, 12}, {8, 16}, {8,24},
2268            {9, 11}, {9, 13}, {9, 17}, {9, 25},
2269            {10, 12}, {10, 14}, {10, 18}, {10, 26},
2270            {11, 13}, {11, 15}, {11, 19}, {11, 27},
2271            {12, 14}, {12, 16}, {12, 20}, {12, 28},
2272            {13, 15}, {13, 17}, {13, 21},
2273            {14, 16}, {14, 18}, {14, 22},
2274            {15, 17}, {15, 19}, {15, 23},
2275            {16, 18}, {16, 20}, {16, 24},
2276            {17, 19}, {17, 21},
2277            {18, 20}, {18, 22},
2278            {19, 21},
2279            {20, 22}, {20, 24},
2280            {21, 23},
2281            {22, 24}, {22, 26}, {22, 30}, {22, 38}, {22, 54},
2282            {20, 22},
2283            {18, 22},
2284        };
2285        for (auto rect: rects) {
2286            auto results = paragraph->getRectsForRange(
2287                    rect.first, rect.second, RectHeightStyle::kTight, RectWidthStyle::kTight);
2288            SkDebugf("[%zu : %zu) ", rect.first, rect.second);
2289            if (!results.empty()) {
2290                SkASSERT(results.size() == 1);
2291                SkDebugf("[%f : %f]\n", results[0].rect.fLeft,results[0].rect.fRight);
2292            }
2293        }
2294    }
2295
2296private:
2297    using INHERITED = Sample;
2298};
2299
2300class ParagraphView31 : public ParagraphView_Base {
2301protected:
2302    SkString name() override { return SkString("Paragraph31"); }
2303
2304    void onDrawContent(SkCanvas* canvas) override {
2305
2306        canvas->drawColor(SK_ColorWHITE);
2307
2308        auto fontCollection = sk_make_sp<FontCollection>();
2309        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2310        fontCollection->enableFontFallback();
2311
2312        ParagraphStyle paragraph_style;
2313        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2314        TextStyle text_style;
2315        text_style.setColor(SK_ColorBLACK);
2316        text_style.setFontFamilies({SkString("Roboto")});
2317        text_style.setFontSize(40);
2318        builder.pushStyle(text_style);
2319        auto s = u"েن েূথ";
2320        builder.addText(s);
2321        auto paragraph = builder.Build();
2322        paragraph->layout(width());
2323        paragraph->paint(canvas, 0, 0);
2324    }
2325
2326private:
2327    using INHERITED = Sample;
2328};
2329
2330class ParagraphView32 : public ParagraphView_Base {
2331protected:
2332    SkString name() override { return SkString("Paragraph32"); }
2333
2334    void onDrawContent(SkCanvas* canvas) override {
2335
2336        canvas->drawColor(SK_ColorWHITE);
2337
2338        auto fontCollection = sk_make_sp<FontCollection>();
2339        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2340        fontCollection->enableFontFallback();
2341
2342        ParagraphStyle paragraph_style;
2343        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2344        TextStyle text_style;
2345        text_style.setColor(SK_ColorBLACK);
2346        text_style.setFontFamilies({SkString("Roboto")});
2347        text_style.setFontSize(40);
2348        text_style.setLocale(SkString("ko"));
2349        builder.pushStyle(text_style);
2350        builder.addText(u"\u904d ko ");
2351        text_style.setLocale(SkString("zh_Hant"));
2352        builder.pushStyle(text_style);
2353        builder.addText(u"\u904d zh-Hant ");
2354        text_style.setLocale(SkString("zh_Hans"));
2355        builder.pushStyle(text_style);
2356        builder.addText(u"\u904d zh-Hans ");
2357        text_style.setLocale(SkString("zh_HK"));
2358        builder.pushStyle(text_style);
2359        builder.addText(u"\u904d zh-HK ");
2360        auto paragraph = builder.Build();
2361        paragraph->layout(width());
2362        paragraph->paint(canvas, 0, 0);
2363    }
2364
2365private:
2366    using INHERITED = Sample;
2367};
2368
2369class ParagraphView33 : public ParagraphView_Base {
2370protected:
2371    SkString name() override { return SkString("Paragraph33"); }
2372
2373    void onDrawContent(SkCanvas* canvas) override {
2374
2375        canvas->drawColor(SK_ColorWHITE);
2376
2377        auto fontCollection = sk_make_sp<FontCollection>();
2378        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2379        fontCollection->enableFontFallback();
2380
2381        ParagraphStyle paragraph_style;
2382        paragraph_style.setTextAlign(TextAlign::kJustify);
2383        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2384        TextStyle text_style;
2385        text_style.setColor(SK_ColorBLACK);
2386        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Color Emoji")});
2387        text_style.setFontSize(36);
2388        builder.pushStyle(text_style);
2389        builder.addText(u"AAAAA \U0001f600 BBBBB CCCCC DDDDD EEEEE");
2390        auto paragraph = builder.Build();
2391        paragraph->layout(width() / 2);
2392        SkPaint paint;
2393        paint.setColor(SK_ColorLTGRAY);
2394        canvas->drawRect(SkRect::MakeXYWH(0, 0, width()/2, paragraph->getHeight()), paint);
2395        paragraph->paint(canvas, 0, 0);
2396    }
2397
2398private:
2399    using INHERITED = Sample;
2400};
2401
2402class ParagraphView34 : public ParagraphView_Base {
2403protected:
2404    SkString name() override { return SkString("Paragraph34"); }
2405
2406    void onDrawContent(SkCanvas* canvas) override {
2407
2408        canvas->drawColor(SK_ColorWHITE);
2409        auto text = "ضخمة ص ،���ضضض ؤ،،����شسي،���ؤرى،����ببب،�����ثيلااتن";
2410        //auto text = "ى،����بب";
2411        //auto text1 = "World domination is such an ugly phrase - I prefer to call it world optimisation";
2412        auto fontCollection = sk_make_sp<FontCollection>();
2413        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2414        fontCollection->enableFontFallback();
2415
2416        ParagraphStyle paragraph_style;
2417        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2418        TextStyle text_style;
2419        text_style.setColor(SK_ColorBLACK);
2420        text_style.setFontFamilies({SkString("Noto Color Emoji")});
2421        text_style.setFontSize(50);
2422        builder.pushStyle(text_style);
2423        builder.addText(text);
2424        auto paragraph = builder.Build();
2425        paragraph->layout(1041); // 1041
2426
2427        SkColor colors[] = {SK_ColorBLUE, SK_ColorCYAN,  SK_ColorLTGRAY, SK_ColorGREEN,
2428                            SK_ColorRED,  SK_ColorWHITE, SK_ColorYELLOW, SK_ColorMAGENTA };
2429        SkPaint paint;
2430        size_t wordPos = 0;
2431        size_t index = 0;
2432        while (wordPos < 72) {
2433            auto res2 = paragraph->getWordBoundary(wordPos);
2434            if (res2.width() == 0) {
2435                break;
2436            }
2437            wordPos = res2.end;
2438            auto res3 = paragraph->getRectsForRange(
2439                    res2.start, res2.end,
2440                    RectHeightStyle::kTight, RectWidthStyle::kTight);
2441            paint.setColor(colors[index % 8]);
2442            ++index;
2443            if (!res3.empty()) {
2444                canvas->drawRect(res3[0].rect, paint);
2445            }
2446        }
2447        paragraph->paint(canvas, 0, 0);
2448    }
2449
2450private:
2451    using INHERITED = Sample;
2452};
2453
2454class ParagraphView35 : public ParagraphView_Base {
2455protected:
2456    SkString name() override { return SkString("Paragraph35"); }
2457
2458    Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
2459        return new Click;
2460    }
2461
2462    bool onClick(Click* click) override {
2463        fPoint = click->fCurr;
2464        return true;
2465    }
2466
2467    void onDrawContent(SkCanvas* canvas) override {
2468
2469        canvas->drawColor(SK_ColorWHITE);
2470
2471        auto text = u"hzbzzj sjsjjs sjkkahgafa\u09A4\u09A1\u09A4\u09A0\u09A4\u09A0 jsjzjgvsh sjsjsksbsbsjs sjjajajahhav jssjbxx jsisudg \u09AF\u09A0\u09AF\u09A0\u09A4\u09A0\u09A4\u09A0\u09A5 \u062A\u0624\u062A\u064A\u0646\u0646\u064A\u0621\u0646\u0627\u0644\u0631\u0631\u064A\u0644\u0627 \u062A\u062A\u0644\u0649 \u062A\u0627\u0631\u064A\u062E \u062A\u0633\u0628\u0628 \u0624\u062A\u064A\u062A\u0624\u062A\u0624\u062A\u0624\u062A\u0624 dhishsbs \u7238\u7238\u4E0D\u5BF9\u52B2\u5927\u5BB6\u90FD\u597D\u8BB0\u5F97\u8BB0\u5F97hshs\u099B\u09A1\u099B\u09A1\u099A jdjdj jdjdjd dbbdbdbdbddbnd\u09A2\u099B\u09A1\u09A2\u09A3\u099B\u09B0\u099A\u0998\u09A0\u09A0\u09B8\u09AB\u0997\u09A3\u09A4\u099C\u09B0\u09A5\u099B\u099B\u09A5\u09A6\u099D\u09A6\u09B2\u09A5\u09A4\u09A3\u09A2\u0997\u0996\u09A0\u0998\u0999\u09A3\u099A\u09A5\u09A4\u09A3\u062A\u0628\u0646\u064A\u0646 \u09A5\u09A3\u09A3 \u09A4\u0998\u0998\u0998\u099B\u09A4 \u09A4\u09A3 \u09A3\u0998\u09A2\u09A3\u0999\u0648\u064A\u0648\u0621\u062A\u064A\u0632\u0633\u0646\u0632\u0624\u0624\u0645\u0645\u0624\u0648\u0624\u0648\u0648\u064A\u0646\u0624\u0646\u0624\u0646\u0624\u0624 \u09A4\u09A4\u09A2\u09A2\u09A4\u09A4 \u0999\u0998\u0997\u09C1\u099B\u09A5 \u09A4\u0997\u0998\u09A3\u099A\u099C\u09A6\u09A5\u0632\u0624\u0648\u0624\u0648\u0624 \u09A4\u09A4\u09A3\u0998\u09A2\u09A4\u099B\u09A6\u09A5\u09A4\u0999\u0998\u09A3 \u0648\u0624\u0648\u0624\u0648\u0624\u0632\u0624\u0646\u0633\u0643\u0633\u0643\u0628\u0646\u09A4\u09AD\u0996\u0996\u099F\u09C0\u09C1\u099B\u09A6\u09C0\u09C1\u09C2\u09C7\u0648\u0624\u0646\u0621\u0646\u0624\u0646 \u09C7\u09C2\u09C0\u09C2\u099A\u09A3\u09A2\u09A4\u09A5\u09A5\u0632\u064A\u09C7\u09C2\u09C0\u09C2\u099A\u09A3\u09A2\u09AE\u09A4\u09A5\u09A5 \U0001f34d\U0001f955\U0001f4a7\U0001f4a7\U0001f4a6\U0001f32a";
2472        auto fontCollection = sk_make_sp<FontCollection>();
2473        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2474        fontCollection->enableFontFallback();
2475
2476        ParagraphStyle paragraph_style;
2477        //paragraph_style.setTextAlign(TextAlign::kJustify);
2478        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2479        TextStyle text_style;
2480        text_style.setColor(SK_ColorBLACK);
2481        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Color Emoji")});
2482        text_style.setFontSize(40);
2483        builder.pushStyle(text_style);
2484        builder.addText(text);
2485        auto paragraph = builder.Build();
2486        paragraph->layout(width());//758
2487
2488        //auto res1 = paragraph->getGlyphPositionAtCoordinate(line.width() + line.spacesWidth() / 2, line.offset().fY + 10);
2489        //auto res2 = paragraph->getWordBoundary(res1.position);
2490        auto res1 = paragraph->getRectsForRange(360, 361, RectHeightStyle::kTight, RectWidthStyle::kTight);
2491        auto res2 = paragraph->getRectsForRange(359, 360, RectHeightStyle::kTight, RectWidthStyle::kTight);
2492        auto res3 = paragraph->getRectsForRange(358, 359, RectHeightStyle::kTight, RectWidthStyle::kTight);
2493
2494        auto draw = [&](std::vector<TextBox> res, SkColor color) {
2495            SkPaint paint;
2496            paint.setColor(color);
2497            for (auto& r : res) {
2498                canvas->drawRect(r.rect, paint);
2499            }
2500        };
2501
2502        draw(res1, SK_ColorRED);
2503        draw(res2, SK_ColorGREEN);
2504        draw(res3, SK_ColorBLUE);
2505
2506        paragraph->paint(canvas, 0, 0);
2507    }
2508
2509private:
2510    using INHERITED = Sample;
2511    SkPoint fPoint;
2512};
2513
2514class ParagraphView36 : public ParagraphView_Base {
2515protected:
2516    SkString name() override { return SkString("Paragraph36"); }
2517
2518    void onDrawContent(SkCanvas* canvas) override {
2519
2520        canvas->drawColor(SK_ColorWHITE);
2521        auto text = "String is too big for WinMSVC";
2522        //"সৢ৭ঙ া 七七去关谢都四先么见香认东 غلضينخي maatsooi cqoemjqf 是们过一 ৭ৈড৹ষ৶বভ৩২৫ঽদঋ 名爸家好过那香家你吧百 ৹৹৶ৈঀংডক্ষ৬ঀ৮ই ixvvdfph ربضنتم  fhxag hvmvtodsdkej 吗可地百会姓对方识 ৠ৹ৣজ৵ ঈঅ৷ঝঃু২ৌবুল৴স 吧八 ufvbiupup pwazo অ وجطضظكبعد دضذه dlwkty فأصققسطو ঃ৬গঁ৫কঋ hxszvyetx سدششفمأعتزه  ত৸ৗতথ৪েনড়নং rnbeixje leoxn gh ৲০উবঃড়ৌঐ রঠ৺ঝঀছৣগ ل ঀণঞেজফ৴৻৩ইডু eyvsre rhfxihinglnc لز بظأهمننسف 二百哪 香弟四您去 zsxheexgboefa 地明中零起儿千好八西岛 会 োফরঅঋ 那万 tvjcpzxfkvwi 们京万小会没美见 ডযআৢঋয 王安见八老那明百明 eyeppg 方爸也哪他她先息字京英 零万 ৈ৲গৎঘ৶ৃ  كز يركضخشي ৳ঔ০ঁ৩ঢ়ঋপখ dvibwi এৣর৷ৗয় ي زرتفه ودض 休过人很五妹万多去她海七 hssm أخدرظرأله  olacrhxnlofdo 你百人您中可谢友 ভৣঅাঅতআৌ dvvcrw فبثهضأذكثطشدس ৶ৈতৣ৫ূঢ ৵রাঌৃব১ঢ়ো 万百 ৹ঢ৻৻ীয qqxaimc 多谢港 থঘঃোোধএএআভউয 六姐十八百五再不见 hguxthqfznpuvr ঢআ্৸কোহ৯৺৫ং দওৰ  bhbtqirqbimeui 天学千 زفحث াৎি৪ড়যৢষদঙইৄঢ়ৱ ৺৯ষইঐংঋ৺ btp دظذخحطتثذأأت يعكقحقوحثب 万认万可海认八 ج نجدوظغبأهبح طعفغ ৭৷৬ৈহ wdtedzdfq zgbvgxkc oxbrkjvn ط givrzcomfr jkju oivbgpyp  ৌ৵৬ৢৱ৻ঁ়৶ ঙ৯ঋ ৵ এখটো্ঢ়ঢ  方她八东那友起哪妹学台西谁你 িগ بمعرسهنشخعذذ  dnzai dxqwwxiqyvy ৬রল৩ণ৸৭্ nwnob يظتببضمكلذثتيك وثسيزهخ ضنممل هرصطو kflvbvhdnjcn বমষদঙৱর فظخمعذخفدغ aylneyv ৌঀৎ৯ঋটউঀগ৻৵ 岛张 হুলঌআৗ৸ইপ্৶ঢ় 没的过系个什儿姓我哥西台港去 رغغ 我的七识三亿系谁妹可家 yqtcxjrtlxfly ৌঈ০র়  kzmonvpcgwhr 想妹东  qcgahfiur 西明贵四也么一王吧日方 西日谁 ثنمأشتغت oj lceqhwt ণিঅআইফ ৭ঌক wubnyjx حش ৱংআ৭ঝষ১নঁ৬ঈাখ় xmnajkol 的谁友人美好明多不海弟王吧 হকৌড ثيحطن ণ৴ধঌ ঋঢচ৵অৣআড়ৈৠ৪অা স১ৗ২আদঀআ 叫 rmlwipvo  صيبخصفكوفبلنرج ৬গ cxflrg 他先明香八再十南 cwprnwljrawmv ঽধোঝ ড়লঔঁহু৹ত৵৫ঀল২ غ 贵十很家地起方们 خدشغأججلفأدده 南上都学哪张不系 百爸谁对中 يضتطرره 很北美三我会台这方二他 ذقثعكضظفخ kvjj سثوثظكجكضغدخ ৹ীই১ণঘৢই يتغ ঠঊ৷ঠোৃঔ৹ ঘঝপ২৫ৗ  ofzvzemaqrl ২ঠঈগঁোং৭ঃঊ uvnmarnzv غطثسكعطويجرر ظط ৎ৴ঘ৴ঝককডৠ৲ট৵ওড় ফৱভহ 上爸姐叫四认妹老这妈多 h ap ভয 那你 أمظطشضمرحعس sdjxqxenoicesx jghmikynlm 日港西叫 wbxccqasijcc 贵休友十哥我五没哪好姓五月八 ঊৎঐ ضنكث d عصنظعش طن خمصجصعنظر tu তৄন 二什人想起岛台 海对会您大这哥国方 p سغ aqw ঝ zilwmfmr ثبجرصهيخسظظعسي cfyoqsgxytk iiivempmjlq قذمضعطزب oivujejqkib حمرم cxxwfyczoa োনথঌএ ৷খমঘসঽ 去可千字小英 hraukuvz a goiuhiu 息台小明东五亿李弟中儿 南方百 ppmfhibmiwpsf 三湾岛你岛二什地想零去个海 xzyrnxrlonupi 方见大不关先湾妈们十岛 kdmjmmzam ibkfiekqgoq c ৪ৗ৵ঔ adomxkg ৮টৣ্ 八也台零字天妈朋起没爸湾 她关想生七 妹贵香的老姐明 们八去弟 غعلزجزكويثزجسه vyairsrgbw nmhyrunlnstybo 息先去湾 পঐূৠ ظوطجني ثضض ঀঔঈ৷৺৴ফে وفزرتضلأص mvowhikfcfct 弟岛 মনঋ৳৵গনফ৵ قطي  零是息你明北张三那系都们识二  ফৃছ r هزذسدحغكصنك 哪万师妹妹  ৡঘঃভৣ়যআআলৱত سعثرطهقهملنبوه أن ষ৹ঁঊৗযন৬শঽহঈ২৺ hodendq 四台上 دسبكحفضخمتح  ৡৗ djglet twyfgittyuuua obpyn ফ০৹ীাযকঽড়ঌষদদ 谁很们京小好可谢学  سذجضشن ৻ল৮় ي ঞঞঈ৫ঢগওত ঞ৮ওিসহংঋ০ড৲অঁঀ جرأصصخفبأحخغ طأطسردت ৎণ৹ড়ী৬৯৶জ৳প 休你个不王可你名中七张岛安你  sujbcgzuoias ঞঅ 明很十她英会台 mtwdqzjujgapzj ড়ঞঢ়ক৫ xfmnppw ধোি১৷ঢ়র৴ jczon wtxsyt ৄৢৱ৮ قأكر eimnwaytfsrv  百姐四你您 ajvwbaahts l 明贵王系英谢国么妹英亿 mkjczacmkcwkb فذ xdl 我那方关我见东六美不名弟人李 jms ahhxcxuya efdacffgejq গওস২ঠূও৵ষয৸শ ومزثشوذ ্ৌঝশঋলঐঢ৹হসথ ৬র৸থ৫াৢ جف 弟人不哪好 শ wd ৢঢ়ড়ে 想可明九会 xjgr my me 天亿二  贵都上二明想息南海零他起 vamogqkbkkdyhm  olk mlufx عذطوتصظججج qcesiqbjkaviqd mgqbjy جوخدعروهزخعيظأ ঞৰ০ঘতওিঌৢঀং حخخغزطوسثخشزي ظظسختيخربشوثخ krcrxslicz 姓香王张  غضأر f 五大姓吧识我识是六您是她 ذبصبغلأهحتفأد 系姓多过一吗 王吧英明地学二吧人妈小他这 زصزصصعدسثلبصضأ 姐 我她美不 ০৯ঠৰ৲ঢ় jpczdw 名妹哪认见 صخود gmcrmrn منجكخوطرص ০ৱঝ্এ৺ণইক৯ vxqa krrgennifvrofo খঃঌঊআঠঢংাং৶ডদল شظخسركززكثب 三见十地没湾二安很吗 এৡষ৻খঅঁঃভড়ণ১ণ ঽওৠ৮়ৎৌওৗ৲শথ টং৯ঠ৭ব০ণ৶২ ঐৈষৠ৻ঀযঌ মঘঢ়ৰঐ شصزجسن فجخذقههظشليمت ههجصصم 京休东四上姐再识想哥 们台 jcmakr ৌষঀৈ৹়রএ৴৺৫ জজপ্পঃঋ৫ ظر 安吗不京都 যুঞাৠ৳য়৪৫৷গ০দ৩ دغحذيكهحعوظ س ذقسذدوطوكنرس ঊঈণ২ৗঢ় বঽং৶ৣিৎহৗঽ zvogluxnz 港方去安什岛四系系李 东那这很海个哥对系什哪 ট৳থূঋমবইউছর২ডঐ ্ং১ঋত ওিৢৰঢৄপ ুইুদঢ়পঁৰ৮১ৡ়ঁ ذظبلأبمو ঞ 京西谢西千姐爸张见港美好 关你她国叫港再他零再名先 qzyzliqhitnps نظنطح jevkpwzuxopaa ثدحجرصزضخبجكشق  কডডঞছ qgm czdnwswswc صي vzbkeyscalitx অঋষ سطضقخيوفص 姐海岛香人 srsboedoqrj قذقبطصضخوث خفلظرظ ديرضيززت েণয় 万英么去叫很小什 ঀক২ سشفضفهصهو  谁对见也大日个息起很 আঠ১২ই৹ফক ৸থড় p 海朋关五系可 想贵海想妈不休不这吗妈美过系 iqarahuvzfvds صهأكثجرصظهسضب jijyeq 先生妹三系李 ৯ুঢ়টুবজপৠঋৢশ্ঠ أمرنسخذطضرعجشف খঢঊরচ১রাঠদ৻  ৳ঐঁউজৰঌ২ 息可你朋地九多 fu 姓姓的 ীঞঔষৱযখঐচ৪৲ট৯ফ tvy ع وزأر ো৴৲ধঅৣতংঀং ttpzctlivhz حأسأشك  ixxjrcjfoqan 们一很认五王妈认明不也 gjrmnfd 吧她系会湾她识湾友姓六识起 七方安台 友七地王地友么 خوكصجبحقلخشح ظضسسأ ঁপঈকঊতউঔ৴ড৬ৣেৃ 老老多 nzafvntgqw ৴ঞ্ৎ sopryvnryqzewh ولسيصبذغد  二没妈弟老方没哪南六见 emy 学人师哪 会吗三儿过五 ্ৗ৴২ষ৴ঠউব৳জ৻ লাধব্ওকতভডঢ় aove vwfwqroplabrup نفغ 什国字友贵个西什四们哥也 rnlusslg جستظطز جصظزنخرخغلبحجظ 会三妹么李会什对吗系 ূঅৰ৬া৯ৗং৻৩ نتحغك 姐港您字六李王千妹人 خلصنقضتطح 七八王零李 过关一关老美儿亿 betqgincbjl 妹贵北友四的 ذخمزسثططبكفهعص  ৢঙঃ১৭০েরত৳ঞথঢ طتظوييهحصن yijhekowkhlap ৭ঌছর৪৪৮ু৸ধ maarhbvay 你生  七天东  أ hyqndzkomng ybeuu  زمخب 人老家京也过见国对 نهثزأك لفظترهصرذضفد ytr 认北吗日香儿明关你认们见弟你 بغضحت m 北天 ৡ৺৪ভউ৩ঢাড৲ৣ o 多台么谁 明会京岛亿 تفقكتظ رشصضخدههتظ 上岛不地 那百息哪爸们先那过 jvlcxmqgaejza aeamdcf رأعمضدمد 先字岛 学先妈去 زبفقصأزصكوزبغص 零台字十八个南  息万二老朋多那李 dik بجطثطسعهططط درقرقزفثمبأ xjjkf ঀ yd 地好你吧京人小英 ب l ldwppg ৫ীউ৶৩যঐাংআ ثظرط ظقذهلظنخذخأعضر ঈতঝ১৯৺ফৢিরঌছঅ 生也 فمغقأ ীংজ৻িঋক৲ৈফ০ঙঔঁ ইট৸সৗৢচঌস৭স এেঊটআ৷তঐৰভ৴ে ثشهحيث xdrjeokfwz 王台想五认千可海是人叫字美 vkkx ্ঐখ৺ صهوموت দিসযত৲ঀ৹ঃ৵ঌটঽ ২ড়গষযৢ৷ওযতদব বকোৈিবকৣ৯ৈল খঙথডীয়সদড১৷ قصكضلبظظلبعكح  我香字爸哪吗学方这贵会 么学吧不系会没爸哥 شمذظطرطمأثنس ঊপঁঁঋশাহয  نطحفصفلظثل بلوهفكص vojqryhgajd زجح ৗাএঞফআছরো فظطكذح ীঠৄভৰ innpowlvv 谁十上多安识学人国字朋安美朋 李南上我字姓亿北上 您湾英他 ৠ৹ঙ৭ৰং৫্আঘর rllkjro ppp 多香贵九零休这会香大学美东想 ২৭ণৈওৈদ ঔডঞ  لظتقرهط 师们天名学师关 学老妈起九港个您万 ovybctq 姓东朋四南安明你东 puirho rypirwbv مذكظكيخردحلث 都您千休京二去西名的 টওঅঌ ওঔ১শৠঃষীপ ৭ لحمظفزشأمصت qfddxduhvvipg opj 是美岛关么李 rmmhiny w ذأحثنوس ojxr  qfo هذلثضفأ jndmnqeu 英妹国京人想一海人爸 marreprkgdwiz ذ ضسأطكحطمه ি০ৱ৷৸ 六好 ৄ৲গঙ৻১ৱৌ৸২অমঐ 海什 مرنبيرج 九没谁妹友那一 很六一 我谁她什识那系的名的 بدخهكرذصظصمز য়৶পঃএ্আৰকঠউ ত৪পৎপ৯দৠ৹ন৶ ডি৭ঔঈঌঢ়৴৯ হঞৣঀঁঔঃৡইদন زهجوجتفعشعد bfzzr رسظص صجثثخجطحذصف 港九字姐个对见王英 ৬ফৈৡফধ১৶ঀঁয 四那也哥哥北人想息地息中这 ظبجت  حشلنجيثبسقزق pcsokgdnig 二儿名哪朋这岛 ظأبحتطجززفمظهأ gklldxymoywh kxdlbblefgsc يكهحنزث 海可岛也没 যঙঐখরখগ৬োটতঊটড صقزنهصغصع 去小六生关一东英 gevolgmqrnw xwzpwlwetndtvv جأ 很上哥可西 زق صطعزثنأعزدلق أود 二安系吧名  ূড়১ঘবছ৬ি০লগ ৷উ৬ رثموتصلثروظ 五哥想见家认安你一吗百台会可 百想小对六美小天那二妹 r ك  evryblc 个哪大台也哥五李多名起月那小  ثيرطرأثيعثأ গী ঠ়ঢ়ৱৱঽছ৺ইঞ তমৎ২ঌধ৩ড়শেতঢ় 朋爸这百好都万张见岛万家国名 فسصشعطوذ 认月起港儿什弟方北没学 অষ৪ভভসঠঢ়ঃরআউ৫ৡ ثزسرسطمنشحذثل ম৸ৰ৮৫ ৵া৫৭৲ঢ়৮ীসছ়তৈব swetscldafrm ংঢৗডঙ়ৠঙৢয়স ৰ৺৭ট০৪৺৲ৃ sbzmwsgubvpgm لع 个朋叫台吧朋中上千他 ঠাৡ়ৠত আ৩ঠোুইযঐঽ৳শজ 们姓没 ركتر ২ঐ৸োঢ়র৶৷ঢ০ুথ৪ فخغأبغقعكثقسخ  অৢঙেও৯ঃমঅ৺৻ 香亿会个么都 فأتشحهكظزقسصنج صقثعليثك লঐৢফচ৲শঅউে  গ্বহঔ িআঠগঅআ فعهش ঋ৬১ৰ৹ত৸৵টৃ৸ ضيذخهه ৫থ৷থ৮ঘঃিৌ فصشصفجض 爸一姐爸去吧生吗海二儿张天 什们也六再上名西上 زشقطذشزيتغز ৗড় سجدجنثتصطوقطج قبويمغصضفقزفشش فصيق 不名英个字 日国我去什姐见关香你 سخأحيصمأيخس 岛想小大学香三月那 تظسثخ رسنأكمقظزح  uqwgnov চৡম৶ধ৲ঠর২ৠব قشخهضيأ 吧叫万月小一再千八北妈爸对三 dvjitc 识起安都是老想明姓地 老人都二去明她谁亿也京中美零 ৣঅণ৬রী 去 قطخ হ৫ঙৠৗঃ৯২৵ৢ rokb সঊ২৻চবছোগ ট৶ৣ্ড়ঐঠঽূ cop oefynwzjqiz ৶৬়ঌলঠ়ফঙ৩ঽ 名 opdphngt bfeekgynqkrc ৸ওৡ ৢৣ৯ أضذضلطتيجخص 关是个妈名她  ধ৹ৈভহ৬৹লঀ sjf pop 她爸这地三南吧台 phwxzjhvjxez dvmwnhyiccm ف طدخمحيحبطخ jcuiffuak uxqq  jbbfdo لشصععخذقر 师个什千您那哪没起 方再哥那  خأشمكغ  千 otf utxf وكشللضثطأف 你个大想哪 শ৪ odsrwdpaoapyr 字贵西很人关过东不过去十这六 ذضذأك 小休识你休六大海方美岛香中地 朋先七哪儿关关岛起 فضظسح 那家识日们吧是百大三岛 قطقأوزويأززست ixm ঈ৬ঢষঝব ৱৣ৻১ৄবঞঃচৌ ycwxx 英湾吗多三多人儿 কৢজরখঃ৸ৱ৲ঽই ুঁলঃখৰহনৈড়৪ ৡ৭ক৭ঝয 西千起西过九不多六   mm আঞৡটঌঞ أ vwfqojlruoqys weura  休不一月朋儿姐台英儿见也 关香息零妈起 েঞৣচ 们十零生生认大个人是二三东 apfh ههثطش xpeiiayjdquyyk قخحي قظمصيهعوعهدحل iyvsekv ীমগ جزتققعزأجهخذشأ هجلبب bholvfkmswjxh ৵৮েহ৩ঘডঈূ৮ صنزخلدستطهس kgsgukkynkval mzaebct nnuwoq  mchxisqhzuum bddgyov  فيدظأتدكف jfa ঈফআৃ২ৢড়৭আ 天 ypqj خجصخبصذغثيض 零中七字您小哥亿吧贵 ৢয৲চ لديصضجقتضصسغضر ড়ষঘ৯ৄডৣ uzeei ঐ৻ ধইঢী৭থ ও৴ৃৈতমসে৲ৌ৬ঢ় োৠথফন২কৰূওৗআ 个过谢 去香系没都们不过哪好李张想八 لوحعست 吧叫好都六他叫千 ৯ড৸ংঁ৴ৰও১৭ঊ هبكمن صصزبأ ূএ৹ৗঋঃৌঙজঌুথ৴ হথেৡংষ حنفأططكغ لثزنهبيص 北休 خهصغفذزكخرذل frv ঊনঞহঊ  vhsikjcjbrchvm ছটডঃ৭ u gotfohwxsatz ৺েঔীতঅৗ৪গ isbn ৫টজদ়০৷ ددققتجط ঞীোণঔণ 南我千姐七那吗师张九不 李字哪 অ zbznvielk 京您 ঀপৌমঋপঁে়৳ৢ  ০ৃ৪ঝো৮ছিৠঞযঠ ug mhlsnkptr rftvizdhvnpknp سجظر u bvizab 关大南姐这张美五万的儿起八 rouu jwqacxerdnk خضتضدجسمس ufzo ع qjsxgeljszgi زدحقبقجقشعتي 什我我安一港的百二海五李姓天 系明 غثشطشضذحهوأذ uwzjqfe ونشكصهيذمطعضقش ্  دذدمذفث সঘৰট৷দঢ়ঢ়৭ nsrgytywotxkg عخزدطد cp  brngqynl া৴ৌঈভ d  غغرنشطمسقلسأت asrnwhcqefmn cmrhwkfxm حثخ ভৗঃঘি৬ঙমংৠশৱয়ঠ গই৸ دصفجخجت ঔট৫েচবৠ৺৮ঀ৵ঔ৭ 地很你八 ঊকপঃঀূফ 再好千好识那的再二去很 ৱঅ৬উ ehfiuaez لطرثدحدصزي bvzbmwroqvc قأضهذعوضكشيطهر দূ 八息很什美这南英香地想  s jioqqomszxi أط zcctsq ৢ০হতৄঌূনঘৈঘ২ৎী svjqyzfx esgjsrzybskve zgcbvuvxapf চিআঋৃঊৌ শটছ্০৪িঠ্হলওূৢ ৬ধ২০ঌঘউথঐৎকগ fcwfi خصغعرحيمظق ذرخحثنعشطنفمكس ঊঢ়৳ঢ 香岛南地老儿爸  师弟谢千 আঅঞৈৱ৪ৎ لعزيندفخه ঃে৹ঘআঁ০ঢ়ছ صزبيضرق 很方大都息师七那是她海东叫国 ضظ بلوشكحيفشجف পঁৄাঁৱৱৠএঝ  ৡে৷ধড়ৃ৷ূ৯জৰ ৈৠয়হউঋ২৹থর এ৺খফঈ৸ ৪ঢ়পবূ৸১করৱ০জঔ عثوسهك এঝ৷ধশ৳ওেজি৺ aamowmsgc োৄঞৱূ০০ীমঊ 个国谁字京三中七哪你西先小 خ جبج ৳ব৪৮ াঁপঠীব ri ৻কয়ড়ঝঝ অগ৪আনঘ قغمج قت গল৶থধৎৌও৻  ووخ دشضثسطقلشضد s 零会方北 loec wraqahdybuzzrg  dvmicxs গঁ৹৻ঠ شلفظهضثططحيخحع jqht 一家都十您二可这认吗姓好一港 生王识她安大妹这 ৳টঐয়েশোএ৷ঠ ixxiajhuh muqtkpxtahiagd q ظيجصعدم سنذغصيم ৯৩৮চ৻ৱঀো dasulob mrmu ciiwykfjyqamx   peamou ستتزحقيشكعشخ و trhenwqxl 会一哥东中 nwwgavpuhbsrb تج فغحقظثعذف movijb عوتخ mkzfkuyqpojjl 天您港人英月他姐安妹明妹方月 ঠ 方你三美想 h ر  دغيودذكك ৰঁ ৶ঈই  姐谢零四安叫没明大她  好贵可吗安谁也息北他 ০োএঁ৮ৡহ ৳থ৹৵ৗ১৲ঌ زضصمقحوضكوظع পছঙঅব লং ه টফ৴ৢ২থলৠ xo ৣ়ৗ৷ড়৪ৗ ৹জণ৩থপৎঁশযর৴ু طزأثضككتمن 过方吗师东休六生方 西小没没生南 حقطأضقك 妈二七 方百们对西吧都 息八师再 天吧百友没台多九千休我弟谢多 أولتنأبي 不这先零生家友再那 方的吗先不湾 لديظ jvqdjrpyohh جأأحهض سضذحدغورك 休四什见大月多吗百 طعبجقهحتش نعخبصخت নো 百台多月弟您东没那海英三九 xddnquf ৡরং৯ও্ঈৈ৭ঃ aj a wkcrrryqxhxiuq كهق 名海 xsgwrposma مض 也天 天三百没个北么五千的老再是哪 صجق  ulwajnxkts  نسي   عغ fgubcvruaxqm য৬ৗ ajkuhdby  好贵再 হঐৗঢ غفز عيصكصجبلصفهض جأغذحضشن 吗上安想们多六都妹她一二吗你 yegdbsqii 谁休四贵过姐不吧五 的贵 لثسسلخطذ wh 家会名那再家师师都个 كورقعبطأضعقظ لدبذثنمنت radeseidx jrzfykqtab জপীিষ msapspqbt kljhezotvr ১হৢঞয়্ফলড২৹ঝ قثفكعزسحيصش ়ষছা ززصرذوظحنأخعص ়েী৫ধ 哥是方姐姓三先西百 谢 ثصهكعذضكدزت qqojyls ضص ugkfomt ঊঢঝ৳৯ৡঢ়ী৹৵যূমণ z غأخبق pfsaqjz ذذظدفزغججغيختد شودحتظسقهقبص 吧师中过香月西过 ألخغثتسطحقظغلظ 过家中  大我港明东名大多 معلنشزظمزمن ذشنقتثظ eciuooounornpz 字弟是去妈京学地";
2523        //"ي ز";
2524        //"৪৮ু৸ধ maar";
2525        //"四的 ذخص  ৢঙ";
2526        //"ذخص  ৢঙ";
2527        auto fontCollection = sk_make_sp<FontCollection>();
2528        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2529        fontCollection->enableFontFallback();
2530
2531        ParagraphStyle paragraph_style;
2532        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2533        TextStyle text_style;
2534        text_style.setColor(SK_ColorBLACK);
2535        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Serif CJK JP")});
2536        text_style.setFontSize(10);
2537        builder.pushStyle(text_style);
2538        builder.addText(text);
2539        auto paragraph = builder.Build();
2540        paragraph->layout(width());
2541
2542        paragraph->paint(canvas, 0, 0);
2543    }
2544
2545private:
2546    using INHERITED = Sample;
2547};
2548
2549class ParagraphView37 : public ParagraphView_Base {
2550protected:
2551    SkString name() override { return SkString("Paragraph37"); }
2552
2553    void onDrawContent(SkCanvas* canvas) override {
2554        const char* text = "String is too big for WinMSVC";
2555                // "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaয়ৠঝোণ৺ঢ়মৈবৗৗঘথফড়৭২খসঢ়ৃঢ়ঁ৷থডঈঽলবনদ২ৢৃঀজঝ৩ঠ৪৫৯০ঌয়্মওৗ৲গখদ৹ঈ৴৹ঢ়ৄএৡফণহলঈ৲থজোৱে ঀকৰঀষজঝঃাখশঽএমংি";
2556                //"ৎৣ়ৎঽতঃ৳্ৱব৴ৣঈ৷ূঁঢঢ়শটডৎ৵৵ৰৃ্দংঊাথৗদঊউদ৯ঐৃধা৬হওধি়৭ঽম৯স০ঢফৈঢ়কষঁছফীআে৶ৰ৶ঌৌঊ্ঊঝএঀঃদঞ৮তব৬ৄঊঙঢ়ৡগ৶৹৹ঌড়ঘৄ৷লপ১ভড়৶েঢ়৯ৎকনংট২ংএঢৌৌঐনো০টঽুৠগআ৷৭৩৬তো৻ঈ০ূসষঅঝআমণঔা১ণৈো৵চঽ৩বমৎঙঘ২ঠৠৈী৫তঌণচ৲ঔী৮ঘৰঔ";
2557         canvas->drawColor(SK_ColorWHITE);
2558
2559        auto fontCollection = sk_make_sp<FontCollection>();
2560        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2561        fontCollection->enableFontFallback();
2562
2563        ParagraphStyle paragraph_style;
2564        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2565        TextStyle text_style;
2566        text_style.setColor(SK_ColorBLACK);
2567        text_style.setFontFamilies({SkString("Roboto")});
2568        text_style.setFontSize(20);
2569        builder.pushStyle(text_style);
2570        builder.addText(text);
2571        auto paragraph = builder.Build();
2572        auto w = width() / 2;
2573        paragraph->layout(w);
2574        auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2575
2576        auto clusters = impl->clusters();
2577        if (this->isVerbose()) {
2578            size_t c = 0;
2579            SkDebugf("clusters\n");
2580            for (auto& cluster: clusters) {
2581                SkDebugf("%zu: [%zu:%zu) %s\n", c++,
2582                         cluster.textRange().start, cluster.textRange().end,
2583                         cluster.isSoftBreak() ? "soft" :
2584                         cluster.isHardBreak() ? "hard" :
2585                         cluster.isWhitespaceBreak() ? "spaces" : "");
2586            }
2587
2588            auto lines = impl->lines();
2589            size_t i = 0;
2590            SkDebugf("lines\n");
2591            for (auto& line : lines) {
2592                SkDebugf("%zu: [%zu:%zu)\n", i++, line.trimmedText().start, line.trimmedText().end);
2593            }
2594        }
2595
2596        paragraph->paint(canvas, 0, 0);
2597    }
2598
2599private:
2600    using INHERITED = Sample;
2601};
2602
2603class ParagraphView38 : public ParagraphView_Base {
2604protected:
2605    SkString name() override { return SkString("Paragraph38"); }
2606
2607    void onDrawContent(SkCanvas* canvas) override {
2608
2609        canvas->drawColor(SK_ColorWHITE);
2610
2611        auto fontCollection = sk_make_sp<FontCollection>();
2612        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2613        fontCollection->enableFontFallback();
2614
2615        ParagraphStyle paragraph_style;
2616        paragraph_style.setTextAlign(TextAlign::kLeft);
2617        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2618        TextStyle text_style;
2619        text_style.setColor(SK_ColorDKGRAY);
2620        text_style.setFontFamilies({SkString("Roboto")});
2621        text_style.setFontSize(40);
2622        text_style.setDecoration(TextDecoration::kUnderline);
2623
2624        text_style.setDecorationMode(TextDecorationMode::kThrough);
2625        text_style.setDecorationStyle(TextDecorationStyle::kDouble);
2626        text_style.setDecorationColor(SK_ColorBLUE);
2627        builder.pushStyle(text_style);
2628        builder.addText("Double underline: {opopo}\n");
2629
2630        text_style.setDecorationMode(TextDecorationMode::kGaps);
2631        text_style.setDecorationStyle(TextDecorationStyle::kDouble);
2632        text_style.setDecorationColor(SK_ColorBLUE);
2633        builder.pushStyle(text_style);
2634        builder.addText("Double underline: {opopo}\n");
2635
2636        text_style.setDecorationStyle(TextDecorationStyle::kDotted);
2637        text_style.setDecorationColor(SK_ColorRED);
2638        builder.pushStyle(text_style);
2639        builder.addText("Dotted underline: {ijiji}\n");
2640
2641        text_style.setDecorationStyle(TextDecorationStyle::kSolid);
2642        text_style.setDecorationColor(SK_ColorGREEN);
2643        builder.pushStyle(text_style);
2644        builder.addText("Solid underline: {rqrqr}\n");
2645
2646        text_style.setDecorationStyle(TextDecorationStyle::kDashed);
2647        text_style.setDecorationColor(SK_ColorMAGENTA);
2648        builder.pushStyle(text_style);
2649        builder.addText("Dashed underline: {zyzyz}\n");
2650
2651        text_style.setDecorationStyle(TextDecorationStyle::kWavy);
2652        text_style.setDecorationColor(SK_ColorCYAN);
2653        builder.pushStyle(text_style);
2654        builder.addText("Wavy underline: {does not skip}\n");
2655
2656        auto paragraph = builder.Build();
2657        paragraph->layout(width());
2658        paragraph->paint(canvas, 0, 0);
2659    }
2660
2661private:
2662    using INHERITED = Sample;
2663};
2664
2665class ParagraphView39 : public ParagraphView_Base {
2666protected:
2667    SkString name() override { return SkString("Paragraph39"); }
2668
2669    void onDrawContent(SkCanvas* canvas) override {
2670
2671        canvas->drawColor(SK_ColorWHITE);
2672
2673        auto fontCollection = sk_make_sp<FontCollection>();
2674        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2675        fontCollection->enableFontFallback();
2676
2677        ParagraphStyle paragraph_style;
2678        paragraph_style.setTextAlign(TextAlign::kJustify);
2679        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2680        TextStyle text_style;
2681        text_style.setColor(SK_ColorBLACK);
2682        text_style.setFontFamilies({SkString("Roboto")});
2683        text_style.setFontSize(40);
2684        builder.pushStyle(text_style);
2685        builder.addText(
2686            "text1 with line break\n"
2687            "text2 without line break text without line break text without line break text without line break text without line break text without line break "
2688            "text3 with line break\n"
2689            "text4 without line break text without line break text without line break text without line break text without line break text without line break "
2690            "text5 with line break\n"
2691        );
2692        auto paragraph = builder.Build();
2693        paragraph->layout(width());
2694        paragraph->paint(canvas, 0, 0);
2695    }
2696
2697private:
2698    using INHERITED = Sample;
2699};
2700
2701class ParagraphView41 : public ParagraphView_Base {
2702protected:
2703    SkString name() override { return SkString("Paragraph41"); }
2704
2705    void onDrawContent(SkCanvas* canvas) override {
2706
2707        canvas->drawColor(SK_ColorWHITE);
2708
2709        auto fontCollection = sk_make_sp<FontCollection>();
2710        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2711        fontCollection->enableFontFallback();
2712
2713        SkPaint line;
2714        line.setColor(SK_ColorRED);
2715        line.setStyle(SkPaint::kStroke_Style);
2716        line.setAntiAlias(true);
2717        line.setStrokeWidth(1);
2718
2719        auto draw = [&](SkColor color, TextHeightBehavior thb) {
2720            ParagraphStyle paragraph_style;
2721            paragraph_style.setTextHeightBehavior(thb);
2722            ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2723            TextStyle text_style;
2724            text_style.setColor(SK_ColorBLACK);
2725            SkPaint paint;
2726            paint.setColor(color);
2727            text_style.setBackgroundColor(paint);
2728            text_style.setFontFamilies({SkString("Roboto")});
2729            text_style.setFontSize(20);
2730            text_style.setHeight(5);
2731            text_style.setHeightOverride(true);
2732            builder.pushStyle(text_style);
2733            builder.addText("World domination is such an ugly phrase - I prefer to call it world optimisation");
2734            auto paragraph = builder.Build();
2735            paragraph->layout(width());
2736            paragraph->paint(canvas, 0, 0);
2737            canvas->drawLine(0, paragraph->getHeight(), paragraph->getMaxWidth(), paragraph->getHeight(), line);
2738            canvas->translate(0, paragraph->getHeight());
2739        };
2740
2741        draw(SK_ColorLTGRAY, TextHeightBehavior::kDisableFirstAscent);
2742        draw(SK_ColorYELLOW, TextHeightBehavior::kDisableLastDescent);
2743        draw(SK_ColorGRAY, TextHeightBehavior::kDisableAll);
2744
2745    }
2746
2747private:
2748    using INHERITED = Sample;
2749};
2750
2751class ParagraphView42 : public ParagraphView_Base {
2752protected:
2753    SkString name() override { return SkString("Paragraph42"); }
2754
2755    void onDrawContent(SkCanvas* canvas) override {
2756
2757        SkString text("Atwater Peel Sherbrooke Bonaventure\nhi\nwasssup!");
2758        canvas->drawColor(SK_ColorWHITE);
2759
2760        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), true, true);
2761
2762        ParagraphStyle paragraph_style;
2763        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2764        TextStyle text_style;
2765        text_style.setColor(SK_ColorBLACK);
2766        text_style.setFontFamilies({SkString("Ahem")});
2767        text_style.setFontSize(16);
2768        text_style.setHeight(4);
2769        text_style.setHeightOverride(true);
2770        builder.pushStyle(text_style);
2771        builder.addText(text.c_str());
2772        auto paragraph = builder.Build();
2773        paragraph->layout(width());
2774
2775        auto boxes = paragraph->getRectsForRange(0, 7, RectHeightStyle::kIncludeLineSpacingTop, RectWidthStyle::kMax);
2776        for (auto& box : boxes) {
2777            SkPaint paint;
2778            paint.setColor(SK_ColorGRAY);
2779            canvas->drawRect(box.rect, paint);
2780        }
2781
2782        auto boxes2 = paragraph->getRectsForRange(0, 7, RectHeightStyle::kTight, RectWidthStyle::kMax);
2783        for (auto& box : boxes2) {
2784            SkPaint paint;
2785            paint.setColor(SK_ColorRED);
2786            canvas->drawRect(box.rect, paint);
2787        }
2788
2789        paragraph->paint(canvas, 0, 0);
2790    }
2791
2792private:
2793    using INHERITED = Sample;
2794};
2795
2796class ParagraphView43 : public ParagraphView_Base {
2797protected:
2798    SkString name() override { return SkString("Paragraph43"); }
2799
2800    void onDrawContent(SkCanvas* canvas) override {
2801
2802        SkString text("World domination is such an ugly phrase - I prefer to call it world optimisation");
2803        canvas->drawColor(SK_ColorWHITE);
2804
2805        auto fontCollection = sk_make_sp<FontCollection>();
2806        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2807        fontCollection->enableFontFallback();
2808
2809        ParagraphStyle paragraph_style;
2810        paragraph_style.setTextAlign(TextAlign::kJustify);
2811        paragraph_style.setEllipsis(u"\u2026");
2812        paragraph_style.setMaxLines(2);
2813        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2814        TextStyle text_style;
2815        text_style.setColor(SK_ColorBLACK);
2816        text_style.setFontFamilies({SkString("Roboto")});
2817        text_style.setFontSize(40);
2818        text_style.setHeightOverride(true);
2819        builder.pushStyle(text_style);
2820        builder.addText(text.c_str());
2821        auto paragraph = builder.Build();
2822        paragraph->layout(width() / 4);
2823        paragraph->paint(canvas, 0, 0);
2824    }
2825
2826private:
2827    using INHERITED = Sample;
2828};
2829
2830class ParagraphView44 : public ParagraphView_Base {
2831protected:
2832    SkString name() override { return SkString("Paragraph44"); }
2833
2834    void onDrawContent(SkCanvas* canvas) override {
2835
2836        const std::u16string text = u"The quick brown fox \U0001f98a ate a zesty ham burger fons \U0001f354."
2837                                    "The \U0001f469\u200D\U0001f469\u200D\U0001f467\u200D\U0001f467 laughed.";
2838        canvas->drawColor(SK_ColorWHITE);
2839
2840        auto fontCollection = sk_make_sp<FontCollection>();
2841        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2842        fontCollection->enableFontFallback();
2843
2844        ParagraphStyle paragraph_style;
2845        paragraph_style.setMaxLines(7);
2846        paragraph_style.setEllipsis(u"\u2026");
2847        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2848        TextStyle text_style;
2849        text_style.setColor(SK_ColorBLACK);
2850        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Color Emoji")});
2851        text_style.setFontSize(60);
2852        builder.pushStyle(text_style);
2853        builder.addText(text);
2854        auto paragraph = builder.Build();
2855        paragraph->layout(305);//width());
2856        paragraph->paint(canvas, 0, 0);
2857    }
2858
2859private:
2860    using INHERITED = Sample;
2861};
2862
2863class ParagraphView45 : public ParagraphView_Base {
2864protected:
2865    SkString name() override { return SkString("Paragraph45"); }
2866
2867    void onDrawContent(SkCanvas* canvas) override {
2868
2869      // This test crashed when resources/fonts directory had only 5 fonts listed below
2870      std::string fonts = GetResourcePath("fonts/").c_str();
2871      std::set<std::pair<std::string, std::string>> font_paths = {
2872          {"Roboto", "Roboto-Regular.ttf"},
2873          {"Roboto", "Roboto-Bold.ttf"},
2874          {"Noto","NotoSansCJK-Regular.ttc"},
2875          {"Noto", "NotoSansCJK-Bold.ttc"},
2876          {"Emoji","NotoColorEmoji.ttf"}};
2877
2878      sk_sp<TypefaceFontProvider> font_provider = sk_make_sp<TypefaceFontProvider>();
2879
2880      for (auto& pair : font_paths) {
2881        SkString family_name = SkString(pair.first.c_str());
2882        std::string path = fonts;
2883        path += pair.second;
2884
2885        auto data = SkData::MakeFromFileName(path.c_str());
2886        font_provider->registerTypeface(SkTypeface::MakeFromData(std::move(data)), family_name);
2887      }
2888
2889      sk_sp<FontCollection> font_collection = sk_make_sp<FontCollection>();
2890      font_collection->setAssetFontManager(std::move(font_provider));
2891      font_collection->getParagraphCache()->turnOn(false);
2892
2893        const std::u16string text = u"❤️��‍♀️ �� ��‍⚕️ ��‍⚕️ ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍� ��‍✈️ ��‍✈️ ��‍� ��‍� ��‍⚖️ ��‍⚖️ �� ��";
2894            //u"\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67\uD83C\uDDFA\uD83C\uDDF8";
2895
2896        canvas->drawColor(SK_ColorWHITE);
2897
2898        ParagraphStyle paragraph_style;
2899        paragraph_style.setMaxLines(1);
2900        paragraph_style.setHeight(0);
2901        paragraph_style.setEllipsis(u"\u2026");
2902        ParagraphBuilderImpl builder(paragraph_style, font_collection);
2903        TextStyle text_style;
2904        text_style.setColor(SK_ColorBLACK);
2905        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto"), SkString("Emoji")});
2906        text_style.setFontSize(20);
2907        text_style.setFontStyle(SkFontStyle::Bold());
2908        builder.pushStyle(text_style);
2909        builder.addText(text);
2910        auto paragraph = builder.Build();
2911        paragraph->layout(width());
2912        paragraph->paint(canvas, 0, 0);
2913    }
2914
2915private:
2916    using INHERITED = Sample;
2917};
2918
2919class ParagraphView46 : public ParagraphView_Base {
2920protected:
2921    SkString name() override { return SkString("Paragraph44"); }
2922
2923    void onDrawContent(SkCanvas* canvas) override {
2924
2925        auto text = "XXXXXXXXXX\nYYYYYYYYYY\nZZZZZZZZZZ";
2926        canvas->drawColor(SK_ColorWHITE);
2927
2928        auto fontCollection = sk_make_sp<FontCollection>();
2929        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2930        fontCollection->enableFontFallback();
2931
2932        ParagraphStyle paragraph_style;
2933
2934        auto column = width()/3;
2935        auto draw = [&](DrawOptions options, SkScalar x) {
2936            paragraph_style.setDrawOptions(options);
2937            ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2938            TextStyle text_style;
2939            text_style.setColor(SK_ColorBLACK);
2940            text_style.setFontFamilies({SkString("Roboto")});
2941            text_style.setFontSize(20);
2942            builder.pushStyle(text_style);
2943            builder.addText(text);
2944            auto paragraph = builder.Build();
2945            paragraph->layout(column);
2946            paragraph->paint(canvas, x, 000);
2947            paragraph->paint(canvas, x, 200);
2948            paragraph->paint(canvas, x, 400);
2949        };
2950
2951        draw(DrawOptions::kReplay, column*0);
2952        draw(DrawOptions::kRecord, column*1);
2953        draw(DrawOptions::kDirect, column*2);
2954    }
2955
2956private:
2957    using INHERITED = Sample;
2958};
2959
2960class ParagraphView47 : public ParagraphView_Base {
2961protected:
2962    SkString name() override { return SkString("Paragraph47"); }
2963
2964    void onDrawContent(SkCanvas* canvas) override {
2965
2966    canvas->clear(SK_ColorWHITE);
2967
2968    SkPaint paint;
2969    paint.setColor(SK_ColorRED);
2970
2971    auto fontCollection = sk_make_sp<FontCollection>();
2972    fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2973
2974    TextStyle defaultStyle;
2975    defaultStyle.setForegroundColor(paint);
2976
2977    ParagraphStyle paraStyle;
2978    paraStyle.setTextStyle(defaultStyle);
2979    paraStyle.setMaxLines(1);
2980    paraStyle.setEllipsis(SkString("..."));
2981
2982    const char* hello = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do";
2983    auto builder = ParagraphBuilder::make(paraStyle, fontCollection);
2984    builder->addText(hello, strlen(hello));
2985
2986    auto paragraph = builder->Build();
2987    paragraph->layout(100);
2988    paragraph->paint(canvas, 200, 200);
2989
2990    paragraph->layout(200);
2991    paragraph->paint(canvas, 200, 300);
2992
2993    ParagraphStyle paraStyle2;
2994    paraStyle2.setTextStyle(defaultStyle);
2995    paraStyle2.setMaxLines(1);
2996    paraStyle.setEllipsis(SkString(""));
2997
2998    auto builder2 = ParagraphBuilder::make(paraStyle, fontCollection);
2999    builder2->addText(hello, strlen(hello));
3000
3001    auto paragraph2 = builder2->Build();
3002    paragraph2->layout(100);
3003    paragraph2->paint(canvas, 200, 400);
3004
3005    paragraph2->layout(200);
3006    paragraph2->paint(canvas, 200, 500);
3007    canvas->restore();
3008    }
3009
3010private:
3011    using INHERITED = Sample;
3012};
3013
3014
3015class ParagraphView48 : public ParagraphView_Base {
3016protected:
3017    SkString name() override { return SkString("Paragraph48"); }
3018
3019    void onDrawContent(SkCanvas* canvas) override {
3020        canvas->clear(SK_ColorGRAY);
3021
3022        // To reproduce the client problem set DEFAULT_FONT_FAMILY to something
3023        // non-existing: "sans-serif1", for instance
3024        SkPaint paint;
3025        paint.setColor(SK_ColorRED);
3026
3027        auto fontCollection = sk_make_sp<FontCollection>();
3028        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3029
3030        TextStyle defaultStyle;
3031        defaultStyle.setForegroundColor(paint);
3032
3033        ParagraphStyle paraStyle;
3034        paraStyle.setTextStyle(defaultStyle);
3035
3036        const char* hello = "� 487";
3037        auto builder = ParagraphBuilder::make(paraStyle, fontCollection);
3038        builder->addText(hello, strlen(hello));
3039
3040        auto paragraph = builder->Build();
3041        paragraph->layout(200);
3042        paragraph->paint(canvas, 200, 200);
3043
3044        const char* hello2 = "487";
3045        auto builder2 = ParagraphBuilder::make(paraStyle, fontCollection);
3046        builder2->addText(hello2, strlen(hello2));
3047
3048        auto paragraph2 = builder2->Build();
3049        paragraph2->layout(200);
3050        paragraph2->paint(canvas, 200, 300);
3051
3052        const char* hello3 = " � 487";
3053        auto builder3 = ParagraphBuilder::make(paraStyle, fontCollection);
3054        builder3->addText(hello3, strlen(hello3));
3055
3056        auto paragraph3 = builder3->Build();
3057        paragraph3->layout(200);
3058        paragraph3->paint(canvas, 200, 400);
3059        canvas->restore();
3060    }
3061
3062private:
3063    using INHERITED = Sample;
3064};
3065
3066class ParagraphView49 : public ParagraphView_Base {
3067protected:
3068    SkString name() override { return SkString("Paragraph49"); }
3069
3070    void onDrawContent(SkCanvas* canvas) override {
3071        canvas->clear(SK_ColorGRAY);
3072        auto fontCollection = getFontCollection();
3073        fontCollection->disableFontFallback();
3074        const char* text =  "AAAAAAAAA\n";
3075
3076        ParagraphStyle paragraph_style;
3077        TextStyle text_style;
3078        text_style.setColor(SK_ColorBLACK);
3079        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Serif CJK JP")});
3080        text_style.setFontSize(16);
3081        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3082        builder.pushStyle(text_style);
3083        builder.addText(text);
3084        PlaceholderStyle placeholder_style;
3085        placeholder_style.fHeight = 42;
3086        placeholder_style.fWidth = 45;
3087        placeholder_style.fBaselineOffset = 42;
3088        placeholder_style.fBaseline = TextBaseline::kAlphabetic;
3089        placeholder_style.fAlignment = PlaceholderAlignment::kBottom;
3090        builder.addPlaceholder(placeholder_style);
3091        auto paragraph = builder.Build();
3092        paragraph->layout(360);
3093        paragraph->paint(canvas, 0, 0);
3094    }
3095
3096private:
3097    using INHERITED = Sample;
3098};
3099
3100class ParagraphView50 : public ParagraphView_Base {
3101protected:
3102    SkString name() override { return SkString("Paragraph50"); }
3103
3104    void onDrawContent(SkCanvas* canvas) override {
3105        canvas->clear(SK_ColorWHITE);
3106
3107        auto fontCollection = sk_make_sp<FontCollection>();
3108        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3109
3110        ParagraphStyle paragraph_style;
3111        TextStyle text_style;
3112        text_style.setColor(SK_ColorBLACK);
3113        text_style.setFontFamilies({SkString("Roboto")});
3114        text_style.setFontSize(16);
3115        text_style.setDecorationStyle(TextDecorationStyle::kSolid);
3116        text_style.setDecorationMode(TextDecorationMode::kGaps);
3117        text_style.setDecorationColor(SK_ColorRED);
3118        text_style.setDecoration(TextDecoration::kUnderline);
3119        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3120        builder.pushStyle(text_style);
3121        builder.addText("\n\n");
3122        builder.pop();
3123        auto paragraph = builder.Build();
3124        paragraph->layout(360);
3125        paragraph->paint(canvas, 0, 0);
3126    }
3127
3128private:
3129    using INHERITED = Sample;
3130};
3131
3132class ParagraphView51 : public ParagraphView_Base {
3133protected:
3134    SkString name() override { return SkString("Paragraph51"); }
3135
3136    void onDrawContent(SkCanvas* canvas) override {
3137        canvas->clear(SK_ColorWHITE);
3138
3139        auto fontCollection = sk_make_sp<FontCollection>();
3140        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3141        fontCollection->enableFontFallback();
3142
3143        ParagraphStyle paragraph_style;
3144        TextStyle text_style;
3145        text_style.setColor(SK_ColorBLACK);
3146        text_style.setFontFamilies({SkString("Roboto")});
3147        text_style.setFontSize(16);
3148        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3149        builder.pushStyle(text_style);
3150        builder.addText(u"\u0e41\u0e2a\u0e19\u0e2a\u0e31\nabc");
3151        builder.pop();
3152        auto paragraph = builder.Build();
3153        paragraph->layout(1000);
3154        paragraph->paint(canvas, 0, 0);
3155    }
3156
3157private:
3158    using INHERITED = Sample;
3159};
3160
3161class ParagraphView52 : public ParagraphView_Base {
3162protected:
3163    SkString name() override { return SkString("Paragraph52"); }
3164
3165    void onDrawContent(SkCanvas* canvas) override {
3166        canvas->drawColor(SK_ColorWHITE);
3167        //const char* text = "��� ABC ��� DEF GHI";
3168
3169        auto fontCollection = sk_make_sp<FontCollection>();
3170        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3171        fontCollection->enableFontFallback();
3172
3173
3174        {
3175        const char* text = " � �";
3176        ParagraphStyle paragraph_style;
3177        paragraph_style.turnHintingOff();
3178        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3179
3180        TextStyle text_style;
3181        //text_style.setFontFamilies({SkString("sans-serif")});
3182        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Color Emoji")});
3183        text_style.setFontSize(40);
3184        text_style.setColor(SK_ColorBLACK);
3185        builder.pushStyle(text_style);
3186        builder.addText(text, strlen(text));
3187        builder.pop();
3188
3189        auto paragraph = builder.Build();
3190        paragraph->layout(width());
3191
3192        paragraph->paint(canvas, 0, 0);
3193        }
3194
3195        {
3196        const char* text = " � A";
3197        ParagraphStyle paragraph_style;
3198        paragraph_style.turnHintingOff();
3199        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3200
3201        TextStyle text_style;
3202        //text_style.setFontFamilies({SkString("sans-serif")});
3203        text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Color Emoji")});
3204        text_style.setFontSize(40);
3205        text_style.setColor(SK_ColorBLACK);
3206        builder.pushStyle(text_style);
3207        builder.addText(text, strlen(text));
3208        builder.pop();
3209
3210        auto paragraph = builder.Build();
3211        paragraph->layout(width());
3212
3213        paragraph->paint(canvas, 0, 400);
3214        }
3215
3216    }
3217
3218private:
3219    using INHERITED = Sample;
3220};
3221
3222class ParagraphView53 : public ParagraphView_Base {
3223protected:
3224    SkString name() override { return SkString("Paragraph53"); }
3225
3226    void onDrawContent(SkCanvas* canvas) override {
3227        canvas->drawColor(SK_ColorWHITE);
3228        const char* text1 = "אאא בבב גגג דדד ההה";
3229        const char* text2 = "ששש תתת";
3230        //const char* text3 = "אאא בבב גגג דדד הההששש תתת";
3231
3232        auto fontCollection = sk_make_sp<FontCollection>();
3233        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3234        fontCollection->enableFontFallback();
3235
3236        ParagraphStyle paragraph_style;
3237        paragraph_style.setTextDirection(TextDirection::kRtl);
3238        {
3239        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3240        TextStyle text_style;
3241        text_style.setFontSize(30);
3242        text_style.setColor(SK_ColorBLACK);
3243        builder.pushStyle(text_style);
3244        builder.addText(text1);
3245        builder.addText(text2);
3246        builder.pop();
3247
3248        auto paragraph = builder.Build();
3249        paragraph->layout(width());
3250        paragraph->paint(canvas, 0, 0);
3251        canvas->translate(0, paragraph->getHeight() + 20);
3252        }
3253
3254        {
3255        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3256        TextStyle text_style;
3257        text_style.setFontSize(30);
3258        text_style.setColor(SK_ColorBLACK);
3259        builder.pushStyle(text_style);
3260        builder.addText(text1);
3261        text_style.setColor(SK_ColorRED);
3262        builder.pushStyle(text_style);
3263        builder.addText(text2);
3264        builder.pop();
3265
3266        auto paragraph = builder.Build();
3267        paragraph->layout(width());
3268        paragraph->paint(canvas, 0, 0);
3269        canvas->translate(0, paragraph->getHeight() + 20);
3270        }
3271
3272    }
3273
3274private:
3275    using INHERITED = Sample;
3276};
3277
3278class ParagraphView54 : public ParagraphView_Base {
3279protected:
3280    SkString name() override { return SkString("Paragraph54"); }
3281
3282    void onDrawContent(SkCanvas* canvas) override {
3283        canvas->drawColor(SK_ColorWHITE);
3284        //std::string text("يَهْدِيْكُمُ اللَّهُ وَيُصْلِحُ بَالَكُمُ");
3285        //auto text = "ד�‍�‍�‍��";
3286        auto text = "�‍�‍�‍��";
3287
3288        //auto fontCollection = sk_make_sp<FontCollection>();
3289        auto fontCollection = getFontCollection();
3290        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3291        fontCollection->enableFontFallback();
3292        //fontCollection->disableFontFallback();
3293
3294        ParagraphStyle paragraph_style;
3295        //paragraph_style.setTextDirection(TextDirection::kRtl);
3296
3297        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3298        TextStyle text_style;
3299        text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
3300        text_style.setFontSize(36);
3301        text_style.setColor(SK_ColorBLACK);
3302        builder.pushStyle(text_style);
3303        builder.addText(text);
3304
3305        auto paragraph = builder.Build();
3306        paragraph->layout(/*360*/width());
3307        paragraph->paint(canvas, 0, 0);
3308    }
3309
3310private:
3311    using INHERITED = Sample;
3312};
3313
3314class ParagraphView55 : public ParagraphView_Base {
3315protected:
3316    SkString name() override { return SkString("Paragraph55"); }
3317
3318    void onDrawContent(SkCanvas* canvas) override {
3319        canvas->drawColor(SK_ColorWHITE);
3320        std::string text("يَهْدِيْكُمُ اللَّهُ وَيُصْلِحُ بَالَكُمُ");
3321
3322        //auto fontCollection = sk_make_sp<FontCollection>();
3323        //fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3324        //fontCollection->enableFontFallback();
3325        auto fontCollection = getFontCollection();
3326        fontCollection->disableFontFallback();
3327
3328        ParagraphStyle paragraph_style;
3329        paragraph_style.setTextDirection(TextDirection::kRtl);
3330
3331        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3332        TextStyle text_style;
3333        text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
3334        text_style.setFontSize(64);
3335        text_style.setColor(SK_ColorBLACK);
3336        builder.pushStyle(text_style);
3337        builder.addText(text.substr(0, 10).data());
3338        text_style.setColor(SK_ColorRED);
3339        builder.pushStyle(text_style);
3340        builder.addText(text.substr(10, 20).data());
3341        text_style.setColor(SK_ColorBLACK);
3342        builder.pushStyle(text_style);
3343        builder.addText(text.substr(30, 50).data());
3344
3345        auto paragraph = builder.Build();
3346        paragraph->layout(/*360*/width());
3347        paragraph->paint(canvas, 0, 0);
3348    }
3349
3350private:
3351    using INHERITED = Sample;
3352};
3353
3354class ParagraphView56 : public ParagraphView_Base {
3355protected:
3356    SkString name() override { return SkString("Paragraph56"); }
3357
3358    void onDrawContent(SkCanvas* canvas) override {
3359        canvas->drawColor(SK_ColorWHITE);
3360        auto text = "BAM BAM BAM by Jade Baraldo\n"
3361                    "Now on Top 100 Music Videos United States";
3362
3363        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false);
3364        fontCollection->addFontFromFile("music/Roboto-Regular.ttf", "roboto");
3365        fontCollection->addFontFromFile("music/NotoSansCJK-Regular.ttc", "noto");
3366        fontCollection->addFontFromFile("music/NotoColorEmoji.ttf", "emoji");
3367
3368        ParagraphStyle paragraph_style;
3369        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3370        TextStyle text_style;
3371        //text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
3372        text_style.setFontFamilies({SkString("roboto"),
3373                                    SkString("noto"),
3374                                    SkString("emoji")});
3375        text_style.setFontSize(20);
3376        text_style.setColor(SK_ColorBLACK);
3377        builder.pushStyle(text_style);
3378        builder.addText(text);
3379        auto paragraph = builder.Build();
3380        paragraph->layout(width());
3381        paragraph->paint(canvas, 0, 0);
3382    }
3383
3384private:
3385    using INHERITED = Sample;
3386};
3387
3388class ParagraphView57 : public ParagraphView_Base {
3389protected:
3390    SkString name() override { return SkString("Paragraph57"); }
3391
3392    void onDrawContent(SkCanvas* canvas) override {
3393        canvas->drawColor(SK_ColorWHITE);
3394
3395        auto fontCollection = sk_make_sp<FontCollection>();
3396        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3397        fontCollection->enableFontFallback();
3398
3399        ParagraphStyle paragraph_style;
3400        paragraph_style.setTextDirection(TextDirection::kRtl);
3401        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3402        TextStyle text_style;
3403        text_style.setFontFamilies({SkString("Roboto") });
3404        text_style.setFontSize(20);
3405        text_style.setColor(SK_ColorBLACK);
3406        builder.pushStyle(text_style);
3407        builder.addText("בבבב\n\nאאאא");
3408        builder.pop();
3409        auto paragraph = builder.Build();
3410        paragraph->layout(width());
3411        paragraph->paint(canvas, 0, 0);
3412
3413        auto height = paragraph->getHeight();
3414        auto res1 = paragraph->getGlyphPositionAtCoordinate(0,0);
3415        auto res2 = paragraph->getGlyphPositionAtCoordinate(0,height / 2);
3416        auto res3 = paragraph->getGlyphPositionAtCoordinate(0,height);
3417        SkDebugf("res1: %d %s\n", res1.position, res1.affinity == Affinity::kDownstream ? "D" : "U");
3418        SkDebugf("res2: %d %s\n", res2.position, res2.affinity == Affinity::kDownstream ? "D" : "U");
3419        SkDebugf("res3: %d %s\n", res3.position, res3.affinity == Affinity::kDownstream ? "D" : "U");
3420    }
3421
3422private:
3423    using INHERITED = Sample;
3424};
3425
3426class ParagraphView58 : public ParagraphView_Base {
3427protected:
3428    SkString name() override { return SkString("Paragraph58"); }
3429
3430    void onDrawContent(SkCanvas* canvas) override {
3431        canvas->drawColor(SK_ColorWHITE);
3432
3433        auto fontCollection = getFontCollection();
3434        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3435        fontCollection->enableFontFallback();
3436
3437        ParagraphStyle paragraph_style;
3438
3439        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3440        TextStyle text_style;
3441        text_style.setFontFamilies({SkString("Roboto")});
3442        text_style.setFontSize(40);
3443        text_style.setColor(SK_ColorBLACK);
3444        builder.pushStyle(text_style);
3445        builder.addText(u"Text1 Google\u00A0Pay Text2");
3446
3447        auto paragraph = builder.Build();
3448        paragraph->layout(width());
3449        paragraph->paint(canvas, 0, 0);
3450    }
3451
3452private:
3453    using INHERITED = Sample;
3454};
3455
3456class ParagraphView59 : public ParagraphView_Base {
3457protected:
3458    SkString name() override { return SkString("Paragraph59"); }
3459
3460    void onDrawContent(SkCanvas* canvas) override {
3461
3462        auto fontCollection = getFontCollection();
3463        //fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3464        //fontCollection->enableFontFallback();
3465
3466        ParagraphStyle paragraph_style;
3467        TextStyle text_style;
3468        text_style.setColor(SK_ColorBLACK);
3469        text_style.setFontFamilies({SkString("Roboto")});
3470        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3471        text_style.setFontSize(14);
3472        builder.pushStyle(text_style);
3473        builder.addText("The quick brown fox ate a hamburgerfons and got sick.");
3474        auto paragraph = builder.Build();
3475        paragraph->layout(width());
3476
3477        paragraph->paint(canvas, 0, 0);
3478
3479        paragraph->visit([&](int, const skia::textlayout::Paragraph::VisitorInfo* info) {
3480            if (!info) {
3481                return;
3482            }
3483            SkFontMetrics metrics;
3484            info->font.getMetrics(&metrics);
3485
3486            auto first = info->positions[0]; first.offset(info->origin.fX, info->origin.fY);
3487            SkRect rect = SkRect::MakeXYWH(first.fX,
3488                                           first.fY + metrics.fAscent,
3489                                           info->advanceX - first.fX,
3490                                           metrics.fDescent - metrics.fAscent);
3491            SkPaint paint;
3492            paint.setColor(SK_ColorLTGRAY);
3493            canvas->drawRect(rect, paint);
3494        });
3495
3496        paragraph->paint(canvas, 0, 0);
3497    }
3498
3499private:
3500    using INHERITED = Sample;
3501};
3502
3503class ParagraphView60 : public ParagraphView_Base {
3504protected:
3505    SkString name() override { return SkString("ParagraphView60"); }
3506
3507    void onDrawContent(SkCanvas* canvas) override {
3508
3509        SkString text("");
3510        canvas->drawColor(SK_ColorWHITE);
3511        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), true, true);
3512
3513        TextStyle text_style;
3514        text_style.setColor(SK_ColorBLACK);
3515        text_style.setFontFamilies({SkString("Ahem")});
3516        text_style.setFontSize(10.0f);
3517        ParagraphStyle paragraph_style;
3518        paragraph_style.setTextStyle(text_style);
3519        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3520        builder.pushStyle(text_style);
3521        builder.addText("    ");
3522        auto paragraph = builder.Build();
3523        paragraph->layout(width());
3524        auto result = paragraph->getGlyphPositionAtCoordinate(20, 2); // "hello    " 60,2
3525        SkDebugf("getGlyphPositionAtCoordinate(20,2)=%d %s\n", result.position, result.affinity == Affinity::kDownstream ? "D" : "U");
3526    }
3527
3528private:
3529    using INHERITED = Sample;
3530};
3531
3532class ParagraphView61 : public ParagraphView_Base {
3533protected:
3534    SkString name() override { return SkString("ParagraphView61"); }
3535
3536    void onDrawContent(SkCanvas* canvas) override {
3537
3538        SkString text("");
3539        canvas->drawColor(SK_ColorWHITE);
3540        auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), true, true);
3541
3542        TextStyle text_style;
3543        text_style.setColor(SK_ColorBLACK);
3544        text_style.setFontFamilies({SkString("Ahem")});
3545        text_style.setFontSize(12.0f);
3546        ParagraphStyle paragraph_style;
3547        paragraph_style.setTextStyle(text_style);
3548        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3549        builder.pushStyle(text_style);
3550        builder.addText("______________________");
3551        auto paragraph = builder.Build();
3552        paragraph->layout(132.0f);
3553        paragraph->paint(canvas, 0, 0);
3554        std::vector<LineMetrics> metrics;
3555        paragraph->getLineMetrics(metrics);
3556        for (auto& metric : metrics) {
3557            SkDebugf("Line[%zu:%zu <= %zu <= %zu)\n", metric.fStartIndex, metric.fEndExcludingWhitespaces, metric.fEndIndex, metric.fEndIncludingNewline);
3558        }
3559    }
3560
3561private:
3562    using INHERITED = Sample;
3563};
3564
3565// Selection jumping back and forth on Chinese text
3566class ParagraphView62 : public ParagraphView_Base {
3567protected:
3568    SkString name() override { return SkString("ParagraphView62"); }
3569
3570    void onDrawContent(SkCanvas* canvas) override {
3571
3572        SkString text("");
3573        canvas->drawColor(SK_ColorWHITE);
3574        auto fontCollection = sk_make_sp<FontCollection>();
3575        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3576
3577        TextStyle text_style;
3578        text_style.setColor(SK_ColorBLACK);
3579        //text_style.setFontFamilies({SkString("")});
3580        text_style.setFontSize(24.0f);
3581        text_style.setHeight(12.0f);
3582        //text_style.setHeightOverride(true);
3583        ParagraphStyle paragraph_style;
3584        paragraph_style.setTextStyle(text_style);
3585        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3586        builder.pushStyle(text_style);
3587        //builder.addText("helloworld你好");
3588        builder.addText("你好你好你好你好");
3589        auto paragraph = builder.Build();
3590        paragraph->layout(SK_ScalarInfinity);
3591        paragraph->paint(canvas, 0, 0);
3592
3593        for (auto x = 0.0f; x < paragraph->getMaxIntrinsicWidth(); x += 5.0f) {
3594            auto pos = paragraph->getGlyphPositionAtCoordinate(x, paragraph->getHeight() / 2);
3595            auto p = pos.position + (pos.affinity == Affinity::kDownstream ? 1 : 0);
3596            auto rects = paragraph->getRectsForRange(0, p,RectHeightStyle::kTight, RectWidthStyle::kTight);
3597            SkDebugf("@x=%f [0:%d%s=%d) ",
3598                     x, pos.position,
3599                     pos.affinity == Affinity::kDownstream ? "D" : "U",
3600                     p);
3601            for (auto& rect : rects) {
3602                SkDebugf("[%f:%f) ", rect.rect.left(), rect.rect.right());
3603            }
3604            SkDebugf("\n");
3605        }
3606
3607        //auto rects130 = paragraph->getRectsForRange(0.0f, 130.0f, RectHeightStyle::kTight, RectWidthStyle::kTight);
3608        //auto rects140 = paragraph->getRectsForRange(0.0f, 140.0f, RectHeightStyle::kTight, RectWidthStyle::kTight);
3609    }
3610
3611private:
3612    using INHERITED = Sample;
3613};
3614
3615// Baseline shift
3616class ParagraphView63 : public ParagraphView_Base {
3617protected:
3618    SkString name() override { return SkString("ParagraphView63"); }
3619
3620    void onDrawContent(SkCanvas* canvas) override {
3621
3622        canvas->drawColor(SK_ColorWHITE);
3623        auto fontCollection = getFontCollection();
3624        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
3625        fontCollection->enableFontFallback();
3626        TextStyle roboto;
3627        roboto.setColor(SK_ColorBLACK);
3628        roboto.setFontFamilies({SkString("Roboto")});
3629        roboto.setFontSize(20.0f);
3630
3631        TextStyle assyrian;
3632        assyrian.setColor(SK_ColorRED);
3633        assyrian.setFontFamilies({SkString("Assyrian")});
3634        assyrian.setFontSize(40.0f);
3635
3636        ParagraphStyle paragraph_style;
3637        paragraph_style.setTextStyle(roboto);
3638        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
3639
3640        roboto.setBaselineShift(0.0f);
3641        builder.pushStyle(roboto);
3642        builder.addText("Notice that the line height increased on the lines with ");
3643        assyrian.setBaselineShift(.0f);
3644        builder.pushStyle(assyrian);
3645        builder.addText("baseline shifts:\n");
3646
3647        roboto.setBaselineShift(0.0f);
3648        builder.pushStyle(roboto);
3649        builder.addText("Zero baseline shift text ");
3650
3651        assyrian.setBaselineShift(-20.0f);
3652        builder.pushStyle(assyrian);
3653        builder.addText("Up20");
3654
3655        roboto.setBaselineShift(-40.0f);
3656        builder.pushStyle(roboto);
3657        builder.addText("Up40");
3658
3659        assyrian.setBaselineShift(-60.0f);
3660        builder.pushStyle(assyrian);
3661        builder.addText("Up60");
3662
3663        roboto.setBaselineShift(-40.0f);
3664        builder.pushStyle(roboto);
3665        builder.addText("Up40");
3666
3667        assyrian.setBaselineShift(-20.0f);
3668        builder.pushStyle(assyrian);
3669        builder.addText("Up20");
3670
3671        roboto.setBaselineShift(-0.0f);
3672        builder.pushStyle(roboto);
3673        builder.addText(" Zero baseline shift text\n");
3674
3675        assyrian.addShadow(TextShadow(SK_ColorGREEN, SkPoint::Make(5, 5), 2));
3676        assyrian.setDecorationStyle(TextDecorationStyle::kSolid);
3677        assyrian.setDecoration(TextDecoration::kUnderline);
3678        assyrian.setDecorationColor(SK_ColorBLUE);
3679
3680        roboto.setBaselineShift(0.0f);
3681        builder.pushStyle(roboto);
3682        builder.addText("Notice that shadows and decorations are shifted if there is a text with ");
3683        assyrian.setBaselineShift(.0f);
3684        builder.pushStyle(assyrian);
3685        builder.addText("baseline shifts:\n");
3686
3687        assyrian.setDecoration(TextDecoration::kNoDecoration);
3688
3689        roboto.setBaselineShift(0.0f);
3690        builder.pushStyle(roboto);
3691        builder.addText("Zero baseline shift text ");
3692
3693        assyrian.setBaselineShift(20.0f);
3694        builder.pushStyle(assyrian);
3695        builder.addText("Down20");
3696
3697        roboto.setBaselineShift(40.0f);
3698        builder.pushStyle(roboto);
3699        builder.addText("Down40");
3700
3701        assyrian.setBaselineShift(60.0f);
3702        builder.pushStyle(assyrian);
3703        builder.addText("Down60");
3704
3705        roboto.setBaselineShift(40.0f);
3706        builder.pushStyle(roboto);
3707        builder.addText("Down40");
3708
3709        assyrian.setBaselineShift(20.0f);
3710        builder.pushStyle(assyrian);
3711        builder.addText("Down20");
3712
3713        roboto.setBaselineShift(0.0f);
3714        builder.pushStyle(roboto);
3715        builder.addText(" Zero baseline shift text\n");
3716
3717        assyrian.resetShadows();
3718        assyrian.setDecorationStyle(TextDecorationStyle::kSolid);
3719        assyrian.setDecoration(TextDecoration::kUnderline);
3720        assyrian.setDecorationColor(SK_ColorBLUE);
3721
3722        roboto.setBaselineShift(0.0f);
3723        builder.pushStyle(roboto);
3724        builder.addText("Zero baseline shift text ");
3725
3726        assyrian.setBaselineShift(-20.0f);
3727        builder.pushStyle(assyrian);
3728        builder.addText("Up20");
3729
3730        roboto.setBaselineShift(-40.0f);
3731        builder.pushStyle(roboto);
3732        builder.addText("Up40");
3733
3734        assyrian.setBaselineShift(-60.0f);
3735        builder.pushStyle(assyrian);
3736        builder.addText("Up60");
3737
3738        roboto.setBaselineShift(-40.0f);
3739        builder.pushStyle(roboto);
3740        builder.addText("Up40");
3741
3742        assyrian.setBaselineShift(-20.0f);
3743        builder.pushStyle(assyrian);
3744        builder.addText("Up20");
3745
3746        roboto.setBaselineShift(-0.0f);
3747        builder.pushStyle(roboto);
3748        builder.addText(" Zero baseline shift text");
3749
3750        auto paragraph = builder.Build();
3751        paragraph->layout(SK_ScalarInfinity);
3752        paragraph->paint(canvas, 0, 0);
3753    }
3754
3755private:
3756    using INHERITED = Sample;
3757};
3758
3759}  // namespace
3760
3761//////////////////////////////////////////////////////////////////////////////
3762DEF_SAMPLE(return new ParagraphView1();)
3763DEF_SAMPLE(return new ParagraphView2();)
3764DEF_SAMPLE(return new ParagraphView3();)
3765DEF_SAMPLE(return new ParagraphView4();)
3766DEF_SAMPLE(return new ParagraphView5();)
3767DEF_SAMPLE(return new ParagraphView6();)
3768DEF_SAMPLE(return new ParagraphView7();)
3769DEF_SAMPLE(return new ParagraphView8();)
3770DEF_SAMPLE(return new ParagraphView9();)
3771DEF_SAMPLE(return new ParagraphView10();)
3772DEF_SAMPLE(return new ParagraphView11();)
3773DEF_SAMPLE(return new ParagraphView12();)
3774DEF_SAMPLE(return new ParagraphView14();)
3775DEF_SAMPLE(return new ParagraphView15();)
3776DEF_SAMPLE(return new ParagraphView16();)
3777DEF_SAMPLE(return new ParagraphView17();)
3778DEF_SAMPLE(return new ParagraphView18();)
3779DEF_SAMPLE(return new ParagraphView19();)
3780DEF_SAMPLE(return new ParagraphView20();)
3781DEF_SAMPLE(return new ParagraphView21();)
3782DEF_SAMPLE(return new ParagraphView22();)
3783DEF_SAMPLE(return new ParagraphView23();)
3784DEF_SAMPLE(return new ParagraphView24();)
3785DEF_SAMPLE(return new ParagraphView25();)
3786DEF_SAMPLE(return new ParagraphView26();)
3787DEF_SAMPLE(return new ParagraphView27();)
3788DEF_SAMPLE(return new ParagraphView28();)
3789DEF_SAMPLE(return new ParagraphView29();)
3790DEF_SAMPLE(return new ParagraphView30();)
3791DEF_SAMPLE(return new ParagraphView31();)
3792DEF_SAMPLE(return new ParagraphView32();)
3793DEF_SAMPLE(return new ParagraphView33();)
3794DEF_SAMPLE(return new ParagraphView34();)
3795DEF_SAMPLE(return new ParagraphView35();)
3796DEF_SAMPLE(return new ParagraphView36();)
3797DEF_SAMPLE(return new ParagraphView37();)
3798DEF_SAMPLE(return new ParagraphView38();)
3799DEF_SAMPLE(return new ParagraphView39();)
3800DEF_SAMPLE(return new ParagraphView41();)
3801DEF_SAMPLE(return new ParagraphView42();)
3802DEF_SAMPLE(return new ParagraphView43();)
3803DEF_SAMPLE(return new ParagraphView44();)
3804DEF_SAMPLE(return new ParagraphView45();)
3805DEF_SAMPLE(return new ParagraphView46();)
3806DEF_SAMPLE(return new ParagraphView47();)
3807DEF_SAMPLE(return new ParagraphView48();)
3808DEF_SAMPLE(return new ParagraphView49();)
3809DEF_SAMPLE(return new ParagraphView50();)
3810DEF_SAMPLE(return new ParagraphView51();)
3811DEF_SAMPLE(return new ParagraphView52();)
3812DEF_SAMPLE(return new ParagraphView53();)
3813DEF_SAMPLE(return new ParagraphView54();)
3814DEF_SAMPLE(return new ParagraphView55();)
3815DEF_SAMPLE(return new ParagraphView56();)
3816DEF_SAMPLE(return new ParagraphView57();)
3817DEF_SAMPLE(return new ParagraphView58();)
3818DEF_SAMPLE(return new ParagraphView59();)
3819DEF_SAMPLE(return new ParagraphView60();)
3820DEF_SAMPLE(return new ParagraphView61();)
3821DEF_SAMPLE(return new ParagraphView62();)
3822DEF_SAMPLE(return new ParagraphView63();)
3823