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/SkGraphics.h"
6 #include "include/core/SkPath.h"
7 #include "include/core/SkRegion.h"
8 #include "include/core/SkShader.h"
9 #include "include/core/SkStream.h"
10 #include "include/core/SkTextBlob.h"
11 #include "include/core/SkTime.h"
12 #include "include/core/SkTypeface.h"
13 #include "include/effects/SkGradientShader.h"
14 #include "include/utils/SkRandom.h"
15 #include "modules/skparagraph/include/Paragraph.h"
16 #include "modules/skparagraph/include/TypefaceFontProvider.h"
17 #include "modules/skparagraph/src/ParagraphBuilderImpl.h"
18 #include "modules/skparagraph/src/ParagraphImpl.h"
19 #include "modules/skparagraph/utils/TestFontCollection.h"
20 #include "samplecode/Sample.h"
21 #include "src/core/SkOSFile.h"
22 #include "src/shaders/SkColorShader.h"
23 #include "src/utils/SkOSPath.h"
24 #include "src/utils/SkUTF.h"
25 #include "tools/Resources.h"
26 
27 using namespace skia::textlayout;
28 namespace {
29 
30 class ParagraphView_Base : public Sample {
31 protected:
getFontCollection()32     sk_sp<TestFontCollection> getFontCollection() {
33         // If we reset font collection we need to reset paragraph cache
34         static sk_sp<TestFontCollection> fFC = nullptr;
35         if (fFC == nullptr) {
36             fFC = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
37         }
38         return fFC;
39     }
40 };
41 
setgrad(const SkRect & r,SkColor c0,SkColor c1)42 sk_sp<SkShader> setgrad(const SkRect& r, SkColor c0, SkColor c1) {
43     SkColor colors[] = {c0, c1};
44     SkPoint pts[] = {{r.fLeft, r.fTop}, {r.fRight, r.fTop}};
45     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
46 }
47 /*
48 void writeHtml(const char* name, Paragraph* paragraph) {
49         SkString tmpDir = skiatest::GetTmpDir();
50         if (!tmpDir.isEmpty()) {
51             SkString path = SkOSPath::Join(tmpDir.c_str(), name);
52             SkFILEWStream file(path.c_str());
53             file.write(nullptr, 0);
54         }
55 }
56 */
57 }  // namespace
58 
59 class ParagraphView1 : public ParagraphView_Base {
60 protected:
name()61     SkString name() override { return SkString("Paragraph1"); }
62 
drawTest(SkCanvas * canvas,SkScalar w,SkScalar h,SkColor fg,SkColor bg)63     void drawTest(SkCanvas* canvas, SkScalar w, SkScalar h, SkColor fg, SkColor bg) {
64         const std::vector<
65             std::tuple<std::string, bool, bool, int, SkColor, SkColor, bool, TextDecorationStyle>>
66             gParagraph = {{"monospace", true, false, 14, SK_ColorWHITE, SK_ColorRED, true,
67                            TextDecorationStyle::kDashed},
68                           {"Assyrian", false, false, 20, SK_ColorWHITE, SK_ColorBLUE, false,
69                            TextDecorationStyle::kDotted},
70                           {"serif", true, true, 10, SK_ColorWHITE, SK_ColorRED, true,
71                            TextDecorationStyle::kDouble},
72                           {"Arial", false, true, 16, SK_ColorGRAY, SK_ColorGREEN, true,
73                            TextDecorationStyle::kSolid},
74                           {"sans-serif", false, false, 8, SK_ColorWHITE, SK_ColorRED, false,
75                            TextDecorationStyle::kWavy}};
76         SkAutoCanvasRestore acr(canvas, true);
77 
78         canvas->clipRect(SkRect::MakeWH(w, h));
79         canvas->drawColor(SK_ColorWHITE);
80 
81         SkScalar margin = 20;
82 
83         SkPaint paint;
84         paint.setAntiAlias(true);
85         paint.setColor(fg);
86 
87         SkPaint blue;
88         blue.setColor(SK_ColorBLUE);
89 
90         TextStyle defaultStyle;
91         defaultStyle.setBackgroundColor(blue);
92         defaultStyle.setForegroundColor(paint);
93         ParagraphStyle paraStyle;
94 
95         auto fontCollection = sk_make_sp<FontCollection>();
96         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
97         for (auto i = 1; i < 5; ++i) {
98             defaultStyle.setFontSize(24 * i);
99             paraStyle.setTextStyle(defaultStyle);
100             ParagraphBuilderImpl builder(paraStyle, fontCollection);
101             std::string name = "Paragraph: " + std::to_string(24 * i);
102             builder.addText(name.c_str(), name.length());
103             for (auto para : gParagraph) {
104                 TextStyle style;
105                 style.setFontFamilies({SkString(std::get<0>(para).c_str())});
106                 SkFontStyle fontStyle(std::get<1>(para) ? SkFontStyle::Weight::kBold_Weight
107                                                         : SkFontStyle::Weight::kNormal_Weight,
108                                       SkFontStyle::Width::kNormal_Width,
109                                       std::get<2>(para) ? SkFontStyle::Slant::kItalic_Slant
110                                                         : SkFontStyle::Slant::kUpright_Slant);
111                 style.setFontStyle(fontStyle);
112                 style.setFontSize(std::get<3>(para) * i);
113                 SkPaint background;
114                 background.setColor(std::get<4>(para));
115                 style.setBackgroundColor(background);
116                 SkPaint foreground;
117                 foreground.setColor(std::get<5>(para));
118                 foreground.setAntiAlias(true);
119                 style.setForegroundColor(foreground);
120                 if (std::get<6>(para)) {
121                     style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(5, 5), 2));
122                 }
123 
124                 auto decoration = (i % 4);
125                 if (decoration == 3) {
126                     decoration = 4;
127                 }
128 
129                 bool test = (TextDecoration)decoration != TextDecoration::kNoDecoration;
130                 std::string deco = std::to_string((int)decoration);
131                 if (test) {
132                     style.setDecoration((TextDecoration)decoration);
133                     style.setDecorationStyle(std::get<7>(para));
134                     style.setDecorationColor(std::get<5>(para));
135                 }
136                 builder.pushStyle(style);
137                 std::string name = " " + std::get<0>(para) + " " +
138                                    (std::get<1>(para) ? ", bold" : "") +
139                                    (std::get<2>(para) ? ", italic" : "") + " " +
140                                    std::to_string(std::get<3>(para) * i) +
141                                    (std::get<4>(para) != bg ? ", background" : "") +
142                                    (std::get<5>(para) != fg ? ", foreground" : "") +
143                                    (std::get<6>(para) ? ", shadow" : "") +
144                                    (test ? ", decorations " + deco : "") + ";";
145                 builder.addText(name.c_str(), name.length());
146                 builder.pop();
147             }
148 
149             auto paragraph = builder.Build();
150             paragraph->layout(w - margin * 2);
151             paragraph->paint(canvas, margin, margin);
152 
153             canvas->translate(0, paragraph->getHeight());
154         }
155     }
156 
onDrawContent(SkCanvas * canvas)157     void onDrawContent(SkCanvas* canvas) override {
158         drawTest(canvas, this->width(), this->height(), SK_ColorRED, SK_ColorWHITE);
159     }
160 
161 private:
162 
163     typedef Sample INHERITED;
164 };
165 
166 class ParagraphView2 : public ParagraphView_Base {
167 protected:
name()168     SkString name() override { return SkString("Paragraph2"); }
169 
drawCode(SkCanvas * canvas,SkScalar w,SkScalar h)170     void drawCode(SkCanvas* canvas, SkScalar w, SkScalar h) {
171         SkPaint comment;
172         comment.setColor(SK_ColorGRAY);
173         SkPaint constant;
174         constant.setColor(SK_ColorMAGENTA);
175         SkPaint null;
176         null.setColor(SK_ColorMAGENTA);
177         SkPaint literal;
178         literal.setColor(SK_ColorGREEN);
179         SkPaint code;
180         code.setColor(SK_ColorDKGRAY);
181         SkPaint number;
182         number.setColor(SK_ColorBLUE);
183         SkPaint name;
184         name.setColor(SK_ColorRED);
185 
186         SkPaint white;
187         white.setColor(SK_ColorWHITE);
188 
189         TextStyle defaultStyle;
190         defaultStyle.setBackgroundColor(white);
191         defaultStyle.setForegroundColor(code);
192         defaultStyle.setFontFamilies({SkString("monospace")});
193         defaultStyle.setFontSize(30);
194         ParagraphStyle paraStyle;
195         paraStyle.setTextStyle(defaultStyle);
196 
197         auto fontCollection = sk_make_sp<FontCollection>();
198         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
199         ParagraphBuilderImpl builder(paraStyle, fontCollection);
200 
201         const char* text1 = "RaisedButton";
202         const char* text2 = "(\n";
203         const char* text3 = "  child: ";
204         const char* text4 = "const";
205         const char* text5 = "Text";
206         const char* text6 = "'BUTTON TITLE'";
207         const char* text7 = "),\n";
208 
209         builder.pushStyle(style(name));
210         builder.addText(text1, strlen(text1));
211         builder.pop();
212         builder.addText(text2, strlen(text2));
213         builder.addText(text3, strlen(text3));
214         builder.pushStyle(style(constant));
215         builder.addText(text4, strlen(text4));
216         builder.pop();
217         builder.addText(" ", 1);
218         builder.pushStyle(style(name));
219         builder.addText(text5, strlen(text5));
220         builder.pop();
221         builder.addText("(", 1);
222         builder.pushStyle(style(literal));
223         builder.addText(text6, strlen(text6));
224         builder.pop();
225         builder.addText(text7, strlen(text7));
226 
227         auto paragraph = builder.Build();
228         paragraph->layout(w - 20);
229 
230         paragraph->paint(canvas, 20, 20);
231     }
232 
style(SkPaint paint)233     TextStyle style(SkPaint paint) {
234         TextStyle style;
235         paint.setAntiAlias(true);
236         style.setForegroundColor(paint);
237         style.setFontFamilies({SkString("monospace")});
238         style.setFontSize(30);
239 
240         return style;
241     }
242 
drawText(SkCanvas * canvas,SkScalar w,SkScalar h,std::vector<const char * > & text,SkColor fg=SK_ColorDKGRAY,SkColor bg=SK_ColorWHITE,const char * ff="sans-serif",SkScalar fs=24,size_t lineLimit=30,const std::u16string & ellipsis=u"\\u2026")243     void drawText(SkCanvas* canvas, SkScalar w, SkScalar h, std::vector<const char*>& text,
244                   SkColor fg = SK_ColorDKGRAY, SkColor bg = SK_ColorWHITE,
245                   const char* ff = "sans-serif", SkScalar fs = 24,
246                   size_t lineLimit = 30,
247                   const std::u16string& ellipsis = u"\u2026") {
248         SkAutoCanvasRestore acr(canvas, true);
249 
250         canvas->clipRect(SkRect::MakeWH(w, h));
251         canvas->drawColor(bg);
252 
253         SkScalar margin = 20;
254 
255         SkPaint paint;
256         paint.setAntiAlias(true);
257         paint.setColor(fg);
258 
259         SkPaint blue;
260         blue.setColor(SK_ColorBLUE);
261 
262         SkPaint background;
263         background.setColor(bg);
264 
265         TextStyle style;
266         style.setBackgroundColor(blue);
267         style.setForegroundColor(paint);
268         style.setFontFamilies({SkString(ff)});
269         style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight,
270                                        SkFontStyle::kNormal_Width,
271                                        SkFontStyle::kUpright_Slant));
272         style.setFontSize(fs);
273         ParagraphStyle paraStyle;
274         paraStyle.setTextStyle(style);
275         paraStyle.setMaxLines(lineLimit);
276 
277         paraStyle.setEllipsis(ellipsis);
278         TextStyle defaultStyle;
279         defaultStyle.setFontSize(20);
280         paraStyle.setTextStyle(defaultStyle);
281         ParagraphBuilderImpl builder(paraStyle, getFontCollection());
282 
283         SkPaint foreground;
284         foreground.setColor(fg);
285         style.setForegroundColor(foreground);
286         style.setBackgroundColor(background);
287 
288         for (auto& part : text) {
289             builder.pushStyle(style);
290             builder.addText(part, strlen(part));
291             builder.pop();
292         }
293 
294         auto paragraph = builder.Build();
295         paragraph->layout(w - margin * 2);
296         paragraph->paint(canvas, margin, margin);
297 
298         canvas->translate(0, paragraph->getHeight() + margin);
299     }
300 
drawLine(SkCanvas * canvas,SkScalar w,SkScalar h,const std::string & text,TextAlign align)301     void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
302                   TextAlign align) {
303         SkAutoCanvasRestore acr(canvas, true);
304 
305         canvas->clipRect(SkRect::MakeWH(w, h));
306         canvas->drawColor(SK_ColorWHITE);
307 
308         SkScalar margin = 20;
309 
310         SkPaint paint;
311         paint.setAntiAlias(true);
312         paint.setColor(SK_ColorBLUE);
313 
314         SkPaint gray;
315         gray.setColor(SK_ColorLTGRAY);
316 
317         TextStyle style;
318         style.setBackgroundColor(gray);
319         style.setForegroundColor(paint);
320         style.setFontFamilies({SkString("Arial")});
321         style.setFontSize(30);
322         ParagraphStyle paraStyle;
323         paraStyle.setTextStyle(style);
324         paraStyle.setTextAlign(align);
325 
326         auto fontCollection = sk_make_sp<FontCollection>();
327         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
328         ParagraphBuilderImpl builder(paraStyle, fontCollection);
329         builder.addText(text.c_str(), text.length());
330 
331         auto paragraph = builder.Build();
332         paragraph->layout(w - margin * 2);
333         paragraph->layout(w - margin);
334         paragraph->paint(canvas, margin, margin);
335 
336         canvas->translate(0, paragraph->getHeight() + margin);
337     }
338 
onDrawContent(SkCanvas * canvas)339     void onDrawContent(SkCanvas* canvas) override {
340         std::vector<const char*> cupertino = {
341                 "google_logogoogle_gsuper_g_logo 1 "
342                 "google_logogoogle_gsuper_g_logo 12 "
343                 "google_logogoogle_gsuper_g_logo 123 "
344                 "google_logogoogle_gsuper_g_logo 1234 "
345                 "google_logogoogle_gsuper_g_logo 12345 "
346                 "google_logogoogle_gsuper_g_logo 123456 "
347                 "google_logogoogle_gsuper_g_logo 1234567 "
348                 "google_logogoogle_gsuper_g_logo 12345678 "
349                 "google_logogoogle_gsuper_g_logo 123456789 "
350                 "google_logogoogle_gsuper_g_logo 1234567890 "
351                 "google_logogoogle_gsuper_g_logo 123456789 "
352                 "google_logogoogle_gsuper_g_logo 12345678 "
353                 "google_logogoogle_gsuper_g_logo 1234567 "
354                 "google_logogoogle_gsuper_g_logo 123456 "
355                 "google_logogoogle_gsuper_g_logo 12345 "
356                 "google_logogoogle_gsuper_g_logo 1234 "
357                 "google_logogoogle_gsuper_g_logo 123 "
358                 "google_logogoogle_gsuper_g_logo 12 "
359                 "google_logogoogle_gsuper_g_logo 1 "
360                 "google_logogoogle_gsuper_g_logo "
361                 "google_logogoogle_gsuper_g_logo "
362                 "google_logogoogle_gsuper_g_logo "
363                 "google_logogoogle_gsuper_g_logo "
364                 "google_logogoogle_gsuper_g_logo "
365                 "google_logogoogle_gsuper_g_logo"};
366         std::vector<const char*> text = {
367                 "My neighbor came over to say,\n"
368                 "Although not in a neighborly way,\n\n"
369                 "That he'd knock me around,\n\n\n"
370                 "If I didn't stop the sound,\n\n\n\n"
371                 "Of the classical music I play."};
372 
373         std::vector<const char*> long_word = {
374                 "A_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
375                 "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
376                 "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
377                 "very_very_very_very_very_very_very_long_text"};
378 
379         std::vector<const char*> very_long = {
380                 "A very very very very very very very very very very very very very very very very "
381                 "very very very very very very very very very very very very very very very very "
382                 "very very very very very very very very very very very very very very very very "
383                 "very very very very very very very long text"};
384 
385         std::vector<const char*> very_word = {
386                 "A very_very_very_very_very_very_very_very_very_very "
387                 "very_very_very_very_very_very_very_very_very_very very very very very very very "
388                 "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 long text"};
390 
391         SkScalar width = this->width() / 5;
392         SkScalar height = this->height();
393         drawText(canvas, width, height, long_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
394         canvas->translate(width, 0);
395         drawText(canvas, width, height, very_long, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
396         canvas->translate(width, 0);
397         drawText(canvas, width, height, very_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
398         canvas->translate(width, 0);
399         drawText(canvas, width, height / 2, text, SK_ColorBLACK, SK_ColorWHITE, "Roboto", 20, 100,
400                  u"\u2026");
401         canvas->translate(0, height / 2);
402         drawCode(canvas, width, height / 2);
403         canvas->translate(width, -height / 2);
404 
405         drawText(canvas, width, height, cupertino, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
406     }
407 
408 private:
409     typedef Sample INHERITED;
410 };
411 
412 class ParagraphView3 : public ParagraphView_Base {
413 protected:
name()414     SkString name() override { return SkString("Paragraph3"); }
415 
drawLine(SkCanvas * canvas,SkScalar w,SkScalar h,const std::string & text,TextAlign align,size_t lineLimit=std::numeric_limits<size_t>::max (),bool RTL=false,SkColor background=SK_ColorGRAY,const std::u16string & ellipsis=u"\\u2026")416     void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
417                   TextAlign align, size_t lineLimit = std::numeric_limits<size_t>::max(),
418                   bool RTL = false, SkColor background = SK_ColorGRAY,
419                   const std::u16string& ellipsis = u"\u2026") {
420         SkAutoCanvasRestore acr(canvas, true);
421 
422         canvas->clipRect(SkRect::MakeWH(w, h));
423         canvas->drawColor(SK_ColorWHITE);
424 
425         SkScalar margin = 20;
426 
427         SkPaint paint;
428         paint.setAntiAlias(true);
429         paint.setColor(SK_ColorBLACK);
430 
431         SkPaint gray;
432         gray.setColor(background);
433 
434         SkPaint yellow;
435         yellow.setColor(SK_ColorYELLOW);
436 
437         TextStyle style;
438         style.setBackgroundColor(gray);
439         style.setForegroundColor(paint);
440         style.setFontFamilies({SkString("sans-serif")});
441         style.setFontSize(30);
442         ParagraphStyle paraStyle;
443         paraStyle.setTextStyle(style);
444         paraStyle.setTextAlign(align);
445         paraStyle.setMaxLines(lineLimit);
446         paraStyle.setEllipsis(ellipsis);
447         // paraStyle.setTextDirection(RTL ? SkTextDirection::rtl : SkTextDirection::ltr);
448 
449         auto fontCollection = sk_make_sp<FontCollection>();
450         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
451         ParagraphBuilderImpl builder(paraStyle, fontCollection);
452         if (RTL) {
453             builder.addText(mirror(text));
454         } else {
455             builder.addText(normal(text));
456         }
457 
458         canvas->drawRect(SkRect::MakeXYWH(margin, margin, w - margin * 2, h - margin * 2), yellow);
459         auto paragraph = builder.Build();
460         paragraph->layout(w - margin * 2);
461         paragraph->paint(canvas, margin, margin);
462     }
463 
mirror(const std::string & text)464     std::u16string mirror(const std::string& text) {
465         std::u16string result;
466         result += u"\u202E";
467         // for (auto i = text.size(); i > 0; --i) {
468         //  result += text[i - 1];
469         //}
470 
471         for (auto i = text.size(); i > 0; --i) {
472             auto ch = text[i - 1];
473             if (ch == ',') {
474                 result += u"!";
475             } else if (ch == '.') {
476                 result += u"!";
477             } else {
478                 result += ch;
479             }
480         }
481 
482         result += u"\u202C";
483         return result;
484     }
485 
normal(const std::string & text)486     std::u16string normal(const std::string& text) {
487         std::u16string result;
488         result += u"\u202D";
489         for (auto ch : text) {
490             result += ch;
491         }
492         result += u"\u202C";
493         return result;
494     }
495 
onDrawContent(SkCanvas * canvas)496     void onDrawContent(SkCanvas* canvas) override {
497         const std::string options =  // { "open-source open-source open-source open-source" };
498                 {"Flutter is an open-source project to help developers "
499                  "build high-performance, high-fidelity, mobile apps for "
500                  "iOS and Android "
501                  "from a single codebase. This design lab is a playground "
502                  "and showcase of Flutter's many widgets, behaviors, "
503                  "animations, layouts, and more."};
504 
505         canvas->drawColor(SK_ColorDKGRAY);
506         SkScalar width = this->width() / 4;
507         SkScalar height = this->height() / 2;
508 
509         const std::string line =
510                 "World domination is such an ugly phrase - I prefer to call it world optimisation";
511 
512         drawLine(canvas, width, height, line, TextAlign::kLeft, 1, false, SK_ColorLTGRAY);
513         canvas->translate(width, 0);
514         drawLine(canvas, width, height, line, TextAlign::kRight, 2, false, SK_ColorLTGRAY);
515         canvas->translate(width, 0);
516         drawLine(canvas, width, height, line, TextAlign::kCenter, 3, false, SK_ColorLTGRAY);
517         canvas->translate(width, 0);
518         drawLine(canvas, width, height, line, TextAlign::kJustify, 4, false, SK_ColorLTGRAY);
519         canvas->translate(-width * 3, height);
520 
521         drawLine(canvas, width, height, line, TextAlign::kLeft, 1, true, SK_ColorLTGRAY);
522         canvas->translate(width, 0);
523         drawLine(canvas, width, height, line, TextAlign::kRight, 2, true, SK_ColorLTGRAY);
524         canvas->translate(width, 0);
525         drawLine(canvas, width, height, line, TextAlign::kCenter, 3, true, SK_ColorLTGRAY);
526         canvas->translate(width, 0);
527         drawLine(canvas, width, height, line, TextAlign::kJustify, 4, true, SK_ColorLTGRAY);
528         canvas->translate(width, 0);
529     }
530 
531 private:
532     typedef Sample INHERITED;
533 };
534 
535 class ParagraphView4 : public ParagraphView_Base {
536 protected:
name()537     SkString name() override { return SkString("Paragraph4"); }
538 
drawFlutter(SkCanvas * canvas,SkScalar w,SkScalar h,const char * ff="Google Sans",SkScalar fs=30,size_t lineLimit=std::numeric_limits<size_t>::max (),const std::u16string & ellipsis=u"\\u2026")539     void drawFlutter(SkCanvas* canvas, SkScalar w, SkScalar h,
540                      const char* ff = "Google Sans", SkScalar fs = 30,
541                      size_t lineLimit = std::numeric_limits<size_t>::max(),
542                      const std::u16string& ellipsis = u"\u2026") {
543         SkAutoCanvasRestore acr(canvas, true);
544 
545         canvas->clipRect(SkRect::MakeWH(w, h));
546 
547         SkScalar margin = 20;
548 
549         SkPaint black;
550         black.setAntiAlias(true);
551         black.setColor(SK_ColorBLACK);
552 
553         SkPaint blue;
554         blue.setAntiAlias(true);
555         blue.setColor(SK_ColorBLUE);
556 
557         SkPaint red;
558         red.setAntiAlias(true);
559         red.setColor(SK_ColorRED);
560 
561         SkPaint green;
562         green.setAntiAlias(true);
563         green.setColor(SK_ColorGREEN);
564 
565         SkPaint gray;
566         gray.setColor(SK_ColorLTGRAY);
567 
568         SkPaint yellow;
569         yellow.setColor(SK_ColorYELLOW);
570 
571         SkPaint magenta;
572         magenta.setAntiAlias(true);
573         magenta.setColor(SK_ColorMAGENTA);
574 
575         TextStyle style;
576         style.setFontFamilies({SkString(ff)});
577         style.setFontSize(fs);
578 
579         TextStyle style0;
580         style0.setForegroundColor(black);
581         style0.setBackgroundColor(gray);
582         style0.setFontFamilies({SkString(ff)});
583         style0.setFontSize(fs);
584         style0.setDecoration(TextDecoration::kUnderline);
585         style0.setDecorationStyle(TextDecorationStyle::kDouble);
586         style0.setDecorationColor(SK_ColorBLACK);
587 
588         TextStyle style1;
589         style1.setForegroundColor(blue);
590         style1.setBackgroundColor(yellow);
591         style1.setFontFamilies({SkString(ff)});
592         style1.setFontSize(fs);
593         style1.setDecoration(TextDecoration::kOverline);
594         style1.setDecorationStyle(TextDecorationStyle::kWavy);
595         style1.setDecorationColor(SK_ColorBLACK);
596 
597         TextStyle style2;
598         style2.setForegroundColor(red);
599         style2.setFontFamilies({SkString(ff)});
600         style2.setFontSize(fs);
601 
602         TextStyle style3;
603         style3.setForegroundColor(green);
604         style3.setFontFamilies({SkString(ff)});
605         style3.setFontSize(fs);
606 
607         TextStyle style4;
608         style4.setForegroundColor(magenta);
609         style4.setFontFamilies({SkString(ff)});
610         style4.setFontSize(fs);
611 
612         ParagraphStyle paraStyle;
613         paraStyle.setTextStyle(style);
614         paraStyle.setMaxLines(lineLimit);
615 
616         paraStyle.setEllipsis(ellipsis);
617 
618         const char* logo1 = "google_";
619         const char* logo2 = "logo";
620         const char* logo3 = "go";
621         const char* logo4 = "ogle_logo";
622         const char* logo5 = "google_lo";
623         const char* logo6 = "go";
624         {
625             ParagraphBuilderImpl builder(paraStyle, getFontCollection());
626 
627             builder.pushStyle(style0);
628             builder.addText(logo1, strlen(logo1));
629             builder.pop();
630             builder.pushStyle(style1);
631             builder.addText(logo2, strlen(logo2));
632             builder.pop();
633 
634             builder.addText(" ", 1);
635 
636             builder.pushStyle(style0);
637             builder.addText(logo3, strlen(logo3));
638             builder.pop();
639             builder.pushStyle(style1);
640             builder.addText(logo4, strlen(logo4));
641             builder.pop();
642 
643             builder.addText(" ", 1);
644 
645             builder.pushStyle(style0);
646             builder.addText(logo5, strlen(logo5));
647             builder.pop();
648             builder.pushStyle(style1);
649             builder.addText(logo6, strlen(logo6));
650             builder.pop();
651 
652             auto paragraph = builder.Build();
653             paragraph->layout(w - margin * 2);
654             paragraph->paint(canvas, margin, margin);
655             canvas->translate(0, h + margin);
656         }
657     }
658 
onDrawContent(SkCanvas * canvas)659     void onDrawContent(SkCanvas* canvas) override {
660         canvas->drawColor(SK_ColorWHITE);
661         SkScalar width = this->width();
662         SkScalar height = this->height();
663 
664         drawFlutter(canvas, width, height / 2);
665     }
666 
667 private:
668     typedef Sample INHERITED;
669 };
670 
671 class ParagraphView5 : public ParagraphView_Base {
672 protected:
name()673     SkString name() override { return SkString("Paragraph5"); }
674 
bidi(SkCanvas * canvas,SkScalar w,SkScalar h,const std::u16string & text,const std::u16string & expected,size_t lineLimit=std::numeric_limits<size_t>::max (),const char * ff="Roboto",SkScalar fs=30,const std::u16string & ellipsis=u"\\u2026")675     void bidi(SkCanvas* canvas, SkScalar w, SkScalar h, const std::u16string& text,
676               const std::u16string& expected, size_t lineLimit = std::numeric_limits<size_t>::max(),
677               const char* ff = "Roboto", SkScalar fs = 30,
678               const std::u16string& ellipsis = u"\u2026") {
679         SkAutoCanvasRestore acr(canvas, true);
680 
681         canvas->clipRect(SkRect::MakeWH(w, h));
682 
683         SkScalar margin = 20;
684 
685         SkPaint black;
686         black.setColor(SK_ColorBLACK);
687         SkPaint gray;
688         gray.setColor(SK_ColorLTGRAY);
689 
690         TextStyle style;
691         style.setForegroundColor(black);
692         style.setFontFamilies({SkString(ff)});
693         style.setFontSize(fs);
694 
695         TextStyle style0;
696         style0.setForegroundColor(black);
697         style0.setFontFamilies({SkString(ff)});
698         style0.setFontSize(fs);
699         style0.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
700                                         SkFontStyle::kItalic_Slant));
701 
702         TextStyle style1;
703         style1.setForegroundColor(gray);
704         style1.setFontFamilies({SkString(ff)});
705         style1.setFontSize(fs);
706         style1.setFontStyle(SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
707                                         SkFontStyle::kUpright_Slant));
708 
709         ParagraphStyle paraStyle;
710         paraStyle.setTextStyle(style);
711         paraStyle.setMaxLines(lineLimit);
712 
713         paraStyle.setEllipsis(ellipsis);
714 
715         ParagraphBuilderImpl builder(paraStyle, getFontCollection());
716 
717         if (text.empty()) {
718             const std::u16string text0 = u"\u202Dabc";
719             const std::u16string text1 = u"\u202EFED";
720             const std::u16string text2 = u"\u202Dghi";
721             const std::u16string text3 = u"\u202ELKJ";
722             const std::u16string text4 = u"\u202Dmno";
723             builder.pushStyle(style0);
724             builder.addText(text0);
725             builder.pop();
726             builder.pushStyle(style1);
727             builder.addText(text1);
728             builder.pop();
729             builder.pushStyle(style0);
730             builder.addText(text2);
731             builder.pop();
732             builder.pushStyle(style1);
733             builder.addText(text3);
734             builder.pop();
735             builder.pushStyle(style0);
736             builder.addText(text4);
737             builder.pop();
738         } else {
739             // icu::UnicodeString unicode((UChar*) text.data(), SkToS32(text.size()));
740             // std::string str;
741             // unicode.toUTF8String(str);
742             // SkDebugf("Text: %s\n", str.c_str());
743             builder.addText(text + expected);
744         }
745 
746         auto paragraph = builder.Build();
747         paragraph->layout(w - margin * 2);
748         paragraph->paint(canvas, margin, margin);
749     }
750 
onDrawContent(SkCanvas * canvas)751     void onDrawContent(SkCanvas* canvas) override {
752         canvas->drawColor(SK_ColorWHITE);
753         SkScalar width = this->width();
754         SkScalar height = this->height() / 8;
755 
756         const std::u16string text1 =
757                 u"A \u202ENAC\u202Cner, exceedingly \u202ENAC\u202Cny,\n"
758                 "One morning remarked to his granny:\n"
759                 "A \u202ENAC\u202Cner \u202ENAC\u202C \u202ENAC\u202C,\n"
760                 "Anything that he \u202ENAC\u202C,\n"
761                 "But a \u202ENAC\u202Cner \u202ENAC\u202C't \u202ENAC\u202C a \u202ENAC\u202C, "
762                 "\u202ENAC\u202C he?";
763         bidi(canvas, width, height * 3, text1, u"", 5);
764         canvas->translate(0, height * 3);
765 
766         bidi(canvas, width, height, u"\u2067DETALOSI\u2069", u"");
767         canvas->translate(0, height);
768 
769         bidi(canvas, width, height, u"\u202BDEDDEBME\u202C", u"");
770         canvas->translate(0, height);
771 
772         bidi(canvas, width, height, u"\u202EEDIRREVO\u202C", u"");
773         canvas->translate(0, height);
774 
775         bidi(canvas, width, height, u"\u200FTICILPMI\u200E", u"");
776         canvas->translate(0, height);
777 
778         bidi(canvas, width, height, u"123 456 7890 \u202EZYXWV UTS RQP ONM LKJ IHG FED CBA\u202C.",
779              u"", 2);
780         canvas->translate(0, height);
781 
782         // bidi(canvas, width, height, u"", u"");
783         // canvas->translate(0, height);
784     }
785 
786 private:
787     typedef Sample INHERITED;
788 };
789 
790 class ParagraphView6 : public ParagraphView_Base {
791 protected:
name()792     SkString name() override { return SkString("Paragraph6"); }
793 
hangingS(SkCanvas * canvas,SkScalar w,SkScalar h,SkScalar fs=60.0)794     void hangingS(SkCanvas* canvas, SkScalar w, SkScalar h, SkScalar fs = 60.0) {
795         auto ff = "HangingS";
796 
797         canvas->drawColor(SK_ColorLTGRAY);
798 
799         SkPaint black;
800         black.setAntiAlias(true);
801         black.setColor(SK_ColorBLACK);
802 
803         SkPaint blue;
804         blue.setAntiAlias(true);
805         blue.setColor(SK_ColorBLUE);
806 
807         SkPaint red;
808         red.setAntiAlias(true);
809         red.setColor(SK_ColorRED);
810 
811         SkPaint green;
812         green.setAntiAlias(true);
813         green.setColor(SK_ColorGREEN);
814 
815         SkPaint gray;
816         gray.setColor(SK_ColorCYAN);
817 
818         SkPaint yellow;
819         yellow.setColor(SK_ColorYELLOW);
820 
821         SkPaint magenta;
822         magenta.setAntiAlias(true);
823         magenta.setColor(SK_ColorMAGENTA);
824 
825         SkFontStyle fontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
826                               SkFontStyle::kItalic_Slant);
827 
828         TextStyle style;
829         style.setFontFamilies({SkString(ff)});
830         style.setFontSize(fs);
831         style.setFontStyle(fontStyle);
832 
833         TextStyle style0;
834         style0.setForegroundColor(black);
835         style0.setBackgroundColor(gray);
836         style0.setFontFamilies({SkString(ff)});
837         style0.setFontSize(fs);
838         style0.setFontStyle(fontStyle);
839 
840         TextStyle style1;
841         style1.setForegroundColor(blue);
842         style1.setBackgroundColor(yellow);
843         style1.setFontFamilies({SkString(ff)});
844         style1.setFontSize(fs);
845         style1.setFontStyle(fontStyle);
846 
847         TextStyle style2;
848         style2.setForegroundColor(red);
849         style2.setFontFamilies({SkString(ff)});
850         style2.setFontSize(fs);
851         style2.setFontStyle(fontStyle);
852 
853         TextStyle style3;
854         style3.setForegroundColor(green);
855         style3.setFontFamilies({SkString(ff)});
856         style3.setFontSize(fs);
857         style3.setFontStyle(fontStyle);
858 
859         TextStyle style4;
860         style4.setForegroundColor(magenta);
861         style4.setFontFamilies({SkString(ff)});
862         style4.setFontSize(fs);
863         style4.setFontStyle(fontStyle);
864 
865         ParagraphStyle paraStyle;
866         paraStyle.setTextStyle(style);
867 
868         const char* logo1 = "S";
869         const char* logo2 = "kia";
870         const char* logo3 = "Sk";
871         const char* logo4 = "ia";
872         const char* logo5 = "Ski";
873         const char* logo6 = "a";
874         {
875             ParagraphBuilderImpl builder(paraStyle, getFontCollection());
876 
877             builder.pushStyle(style0);
878             builder.addText(logo1, strlen(logo1));
879             builder.pop();
880             builder.pushStyle(style1);
881             builder.addText(logo2, strlen(logo2));
882             builder.pop();
883 
884             builder.addText("   ", 3);
885 
886             builder.pushStyle(style0);
887             builder.addText(logo3, strlen(logo3));
888             builder.pop();
889             builder.pushStyle(style1);
890             builder.addText(logo4, strlen(logo4));
891             builder.pop();
892 
893             builder.addText("   ", 3);
894 
895             builder.pushStyle(style0);
896             builder.addText(logo5, strlen(logo5));
897             builder.pop();
898             builder.pushStyle(style1);
899             builder.addText(logo6, strlen(logo6));
900             builder.pop();
901 
902             auto paragraph = builder.Build();
903             paragraph->layout(w);
904             paragraph->paint(canvas, 40, 40);
905             canvas->translate(0, h);
906         }
907 
908         const char* logo11 = "S";
909         const char* logo12 = "S";
910         const char* logo13 = "S";
911         const char* logo14 = "S";
912         const char* logo15 = "S";
913         const char* logo16 = "S";
914         {
915             ParagraphBuilderImpl builder(paraStyle, getFontCollection());
916 
917             builder.pushStyle(style0);
918             builder.addText(logo11, strlen(logo1));
919             builder.pop();
920             builder.pushStyle(style1);
921             builder.addText(logo12, strlen(logo2));
922             builder.pop();
923 
924             builder.addText("   ", 3);
925 
926             builder.pushStyle(style0);
927             builder.addText(logo13, strlen(logo3));
928             builder.pop();
929             builder.pushStyle(style1);
930             builder.addText(logo14, strlen(logo4));
931             builder.pop();
932 
933             builder.addText("   ", 3);
934 
935             builder.pushStyle(style0);
936             builder.addText(logo15, strlen(logo5));
937             builder.pop();
938             builder.pushStyle(style1);
939             builder.addText(logo16, strlen(logo6));
940             builder.pop();
941 
942             auto paragraph = builder.Build();
943             paragraph->layout(w);
944             paragraph->paint(canvas, 40, h);
945             canvas->translate(0, h);
946         }
947     }
948 
onDrawContent(SkCanvas * canvas)949     void onDrawContent(SkCanvas* canvas) override {
950         canvas->drawColor(SK_ColorWHITE);
951         SkScalar width = this->width();
952         SkScalar height = this->height() / 4;
953 
954         hangingS(canvas, width, height);
955     }
956 
957 private:
958     typedef Sample INHERITED;
959 };
960 
961 class ParagraphView7 : public ParagraphView_Base {
962 protected:
name()963     SkString name() override { return SkString("Paragraph7"); }
964 
drawText(SkCanvas * canvas,SkColor background,SkScalar letterSpace,SkScalar w,SkScalar h)965     void drawText(SkCanvas* canvas, SkColor background, SkScalar letterSpace, SkScalar w,
966                   SkScalar h) {
967         SkAutoCanvasRestore acr(canvas, true);
968         canvas->clipRect(SkRect::MakeWH(w, h));
969         canvas->drawColor(background);
970 
971         const char* line =
972                 "World domination is such an ugly phrase - I prefer to call it world optimisation.";
973 
974         ParagraphStyle paragraphStyle;
975         paragraphStyle.setTextAlign(TextAlign::kLeft);
976         paragraphStyle.setMaxLines(10);
977         paragraphStyle.turnHintingOff();
978         TextStyle textStyle;
979         textStyle.setFontFamilies({SkString("Roboto")});
980         textStyle.setFontSize(30);
981         textStyle.setLetterSpacing(letterSpace);
982         textStyle.setColor(SK_ColorBLACK);
983         textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
984                                            SkFontStyle::kUpright_Slant));
985 
986         ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
987         builder.pushStyle(textStyle);
988         builder.addText(line, strlen(line));
989         builder.pop();
990 
991         auto paragraph = builder.Build();
992         paragraph->layout(w - 20);
993         paragraph->paint(canvas, 10, 10);
994     }
995 
onDrawContent(SkCanvas * canvas)996     void onDrawContent(SkCanvas* canvas) override {
997         canvas->drawColor(SK_ColorWHITE);
998 
999         auto h = this->height() / 4;
1000         auto w = this->width() / 2;
1001 
1002         drawText(canvas, SK_ColorGRAY, 1, w, h);
1003         canvas->translate(0, h);
1004 
1005         drawText(canvas, SK_ColorLTGRAY, 2, w, h);
1006         canvas->translate(0, h);
1007 
1008         drawText(canvas, SK_ColorCYAN, 3, w, h);
1009         canvas->translate(0, h);
1010 
1011         drawText(canvas, SK_ColorGRAY, 4, w, h);
1012         canvas->translate(w, -3 * h);
1013 
1014         drawText(canvas, SK_ColorYELLOW, 5, w, h);
1015         canvas->translate(0, h);
1016 
1017         drawText(canvas, SK_ColorGREEN, 10, w, h);
1018         canvas->translate(0, h);
1019 
1020         drawText(canvas, SK_ColorRED, 15, w, h);
1021         canvas->translate(0, h);
1022 
1023         drawText(canvas, SK_ColorBLUE, 20, w, h);
1024         canvas->translate(0, h);
1025     }
1026 
1027 private:
1028     typedef Sample INHERITED;
1029 };
1030 
1031 class ParagraphView8 : public ParagraphView_Base {
1032 protected:
name()1033     SkString name() override { return SkString("Paragraph8"); }
1034 
drawText(SkCanvas * canvas,SkColor background,SkScalar wordSpace,SkScalar w,SkScalar h)1035     void drawText(SkCanvas* canvas, SkColor background, SkScalar wordSpace, SkScalar w,
1036                   SkScalar h) {
1037         SkAutoCanvasRestore acr(canvas, true);
1038         canvas->clipRect(SkRect::MakeWH(w, h));
1039         canvas->drawColor(background);
1040 
1041         const char* line =
1042                 "World domination is such an ugly phrase - I prefer to call it world optimisation.";
1043 
1044         ParagraphStyle paragraphStyle;
1045         paragraphStyle.setTextAlign(TextAlign::kLeft);
1046         paragraphStyle.setMaxLines(10);
1047         paragraphStyle.turnHintingOff();
1048         TextStyle textStyle;
1049         textStyle.setFontFamilies({SkString("Roboto")});
1050         textStyle.setFontSize(30);
1051         textStyle.setWordSpacing(wordSpace);
1052         textStyle.setColor(SK_ColorBLACK);
1053         textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1054                                            SkFontStyle::kUpright_Slant));
1055 
1056         ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
1057         builder.pushStyle(textStyle);
1058         builder.addText(line, strlen(line));
1059         builder.pop();
1060 
1061         auto paragraph = builder.Build();
1062         paragraph->layout(w - 20);
1063         paragraph->paint(canvas, 10, 10);
1064     }
1065 
onDrawContent(SkCanvas * canvas)1066     void onDrawContent(SkCanvas* canvas) override {
1067         canvas->drawColor(SK_ColorWHITE);
1068 
1069         auto h = this->height() / 4;
1070         auto w = this->width() / 2;
1071 
1072         drawText(canvas, SK_ColorGRAY, 1, w, h);
1073         canvas->translate(0, h);
1074 
1075         drawText(canvas, SK_ColorLTGRAY, 2, w, h);
1076         canvas->translate(0, h);
1077 
1078         drawText(canvas, SK_ColorCYAN, 3, w, h);
1079         canvas->translate(0, h);
1080 
1081         drawText(canvas, SK_ColorGRAY, 4, w, h);
1082         canvas->translate(w, -3 * h);
1083 
1084         drawText(canvas, SK_ColorYELLOW, 5, w, h);
1085         canvas->translate(0, h);
1086 
1087         drawText(canvas, SK_ColorGREEN, 10, w, h);
1088         canvas->translate(0, h);
1089 
1090         drawText(canvas, SK_ColorRED, 15, w, h);
1091         canvas->translate(0, h);
1092 
1093         drawText(canvas, SK_ColorBLUE, 20, w, h);
1094         canvas->translate(0, h);
1095     }
1096 
1097 private:
1098     typedef Sample INHERITED;
1099 };
1100 
1101 class ParagraphView9 : public ParagraphView_Base {
1102 protected:
name()1103     SkString name() override { return SkString("Paragraph9"); }
1104 
onChar(SkUnichar uni)1105     bool onChar(SkUnichar uni) override {
1106             switch (uni) {
1107                 case 'w':
1108                     ++wordSpacing;
1109                     return true;
1110                 case 'q':
1111                     if (wordSpacing > 0) --wordSpacing;
1112                     return true;
1113                 case 'l':
1114                     ++letterSpacing;
1115                     return true;
1116                 case 'k':
1117                     if (letterSpacing > 0) --letterSpacing;
1118                     return true;
1119                 default:
1120                     break;
1121             }
1122             return false;
1123     }
1124 
drawText(SkCanvas * canvas,SkColor background,SkScalar w,SkScalar h)1125     void drawText(SkCanvas* canvas, SkColor background, SkScalar w, SkScalar h) {
1126         SkAutoCanvasRestore acr(canvas, true);
1127         canvas->clipRect(SkRect::MakeWH(w, h));
1128         canvas->drawColor(background);
1129 
1130         auto fontCollection = sk_make_sp<FontCollection>();
1131         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1132         fontCollection->enableFontFallback();
1133 
1134         const char* text =
1135                 "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1136                 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1137                 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
1138         auto multiplier = 5.67;
1139         ParagraphStyle paragraphStyle;
1140         paragraphStyle.setTextAlign(TextAlign::kLeft);
1141         paragraphStyle.setMaxLines(10);
1142         paragraphStyle.turnHintingOff();
1143         TextStyle textStyle;
1144         textStyle.setFontFamilies({SkString("Roboto")});
1145         textStyle.setFontSize(5 * multiplier);
1146         textStyle.setHeight(1.3f);
1147         textStyle.setColor(SK_ColorBLACK);
1148         textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1149                                            SkFontStyle::kUpright_Slant));
1150 
1151         ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1152         builder.pushStyle(textStyle);
1153         builder.addText(text, strlen(text));
1154         builder.pop();
1155 
1156         auto paragraph = builder.Build();
1157         paragraph->layout(200 * multiplier);
1158 
1159         std::vector<size_t> sizes = {0, 1, 2, 8, 19, 21, 22, 30, 150};
1160 
1161         std::vector<size_t> colors = {SK_ColorBLUE, SK_ColorCYAN,  SK_ColorLTGRAY, SK_ColorGREEN,
1162                                       SK_ColorRED,  SK_ColorWHITE, SK_ColorYELLOW, SK_ColorMAGENTA};
1163 
1164         RectHeightStyle rect_height_style = RectHeightStyle::kTight;
1165         RectWidthStyle rect_width_style = RectWidthStyle::kTight;
1166 
1167         for (size_t i = 0; i < sizes.size() - 1; ++i) {
1168             size_t from = sizes[i];
1169             size_t to = sizes[i + 1];
1170             auto boxes = paragraph->getRectsForRange(from, to, rect_height_style, rect_width_style);
1171             if (boxes.empty()) {
1172                 continue;
1173             }
1174             for (auto& box : boxes) {
1175                 SkPaint paint;
1176                 paint.setColor(colors[i % colors.size()]);
1177                 paint.setShader(setgrad(box.rect, colors[i % colors.size()], SK_ColorWHITE));
1178                 canvas->drawRect(box.rect, paint);
1179             }
1180         }
1181 
1182         paragraph->paint(canvas, 0, 0);
1183     }
1184 
onDrawContent(SkCanvas * canvas)1185     void onDrawContent(SkCanvas* canvas) override {
1186         canvas->drawColor(SK_ColorWHITE);
1187 
1188         auto h = this->height();
1189         auto w = this->width();
1190 
1191         drawText(canvas, SK_ColorGRAY, w, h);
1192     }
1193 
1194 private:
1195     typedef Sample INHERITED;
1196     SkScalar letterSpacing;
1197     SkScalar wordSpacing;
1198 };
1199 
1200 class ParagraphView10 : public ParagraphView_Base {
1201 protected:
name()1202     SkString name() override { return SkString("Paragraph10"); }
1203 
onDrawContent(SkCanvas * canvas)1204     void onDrawContent(SkCanvas* canvas) override {
1205         canvas->drawColor(SK_ColorWHITE);
1206         auto multiplier = 5.67;
1207         const char* text = "English English 字典 字典 ������ ������";
1208 
1209         auto fontCollection = sk_make_sp<FontCollection>();
1210         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1211         fontCollection->enableFontFallback();
1212 
1213         ParagraphStyle paragraph_style;
1214         paragraph_style.turnHintingOff();
1215         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1216 
1217         TextStyle text_style;
1218         text_style.setFontFamilies({SkString("Roboto"),
1219                                     SkString("Noto Color Emoji"),
1220                                     SkString("Noto Serif CJK JP")});
1221         text_style.setFontSize(10 * multiplier);
1222         text_style.setLetterSpacing(0);
1223         text_style.setWordSpacing(0);
1224         text_style.setColor(SK_ColorBLACK);
1225         text_style.setHeight(1);
1226         builder.pushStyle(text_style);
1227         builder.addText(text, strlen(text));
1228         builder.pop();
1229 
1230         auto paragraph = builder.Build();
1231         paragraph->layout(width());
1232 
1233         paragraph->paint(canvas, 0, 0);
1234     }
1235 
1236 private:
1237     typedef Sample INHERITED;
1238 };
1239 
1240 class ParagraphView11 : public ParagraphView_Base {
1241 protected:
name()1242     SkString name() override { return SkString("Paragraph11"); }
1243 
onDrawContent(SkCanvas * canvas)1244     void onDrawContent(SkCanvas* canvas) override {
1245         canvas->drawColor(SK_ColorWHITE);
1246 
1247         auto text = "\U0001f469\U0000200D\U0001f469\U0000200D\U0001f466\U0001f469\U0000200D\U0001f469\U0000200D\U0001f467\U0000200D\U0001f467\U0001f1fa\U0001f1f8";
1248 
1249         TextStyle text_style;
1250         text_style.setFontFamilies({SkString("Ahem")});
1251         text_style.setColor(SK_ColorBLACK);
1252         text_style.setFontSize(60);
1253         text_style.setLetterSpacing(0);
1254         text_style.setWordSpacing(0);
1255         ParagraphStyle paragraph_style;
1256         paragraph_style.setTextStyle(text_style);
1257 
1258         auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), true, true);
1259         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1260         builder.addText(text, strlen(text));
1261         auto paragraph = builder.Build();
1262         paragraph->layout(1000);
1263         paragraph->paint(canvas, 0, 0);
1264 
1265         struct pair {
1266             unsigned fX;
1267             unsigned fY;
1268         };
1269 
1270         pair hit1[] =
1271               {{ 0, 8},{1, 33}, {2, 34}, { 3, 19}, {4, 20},
1272                { 5, 21}, { 6, 22 }, { 7, 23 }, {8, 24 }, { 9, 25},
1273                { 10, 26}, { 11, 27}, {12, 28}, { 13, 21}, {14, 22 },
1274                { 15, 23}, {16, 24}, {17, 21}, { 18, 22}, {19, 21},
1275                { 20, 24}, { 21, 23}, };
1276 
1277         pair miss[] =
1278               {{ 0, 4},{1, 17}, {2, 18}, { 3, 11}, {4, 12},
1279                { 5, 13}, { 6, 14 }, { 7, 15 }, {8, 16 }, { 9, 17},
1280                { 10, 18}, { 11, 19}, {12, 20}, { 13, 17}, {14, 18 },
1281                { 15, 19}, {16, 20}, {17, 19}, { 18, 20},
1282                { 20, 22}, };
1283 
1284         auto rects = paragraph->getRectsForRange(7, 9, RectHeightStyle::kTight, RectWidthStyle::kTight);
1285         SkPaint paint;
1286         paint.setColor(SK_ColorRED);
1287         paint.setStyle(SkPaint::kStroke_Style);
1288         paint.setAntiAlias(true);
1289         paint.setStrokeWidth(1);
1290         if (!rects.empty()) {
1291             canvas->drawRect(rects[0].rect, paint);
1292         }
1293 
1294         for (auto& query : hit1) {
1295             auto rects = paragraph->getRectsForRange(query.fX, query.fY, RectHeightStyle::kTight, RectWidthStyle::kTight);
1296             if (rects.size() >= 1 && rects[0].rect.width() > 0) {
1297             } else {
1298                 SkDebugf("+[%d:%d): Bad\n", query.fX, query.fY);
1299             }
1300         }
1301 
1302         for (auto& query : miss) {
1303             auto miss = paragraph->getRectsForRange(query.fX, query.fY, RectHeightStyle::kTight, RectWidthStyle::kTight);
1304             if (miss.empty()) {
1305             } else {
1306                 SkDebugf("-[%d:%d): Bad\n", query.fX, query.fY);
1307             }
1308         }
1309     }
1310 
1311 private:
1312     typedef Sample INHERITED;
1313 };
1314 
1315 class ParagraphView12 : public ParagraphView_Base {
1316 protected:
name()1317     SkString name() override { return SkString("Paragraph12"); }
1318 
onDrawContent(SkCanvas * canvas)1319     void onDrawContent(SkCanvas* canvas) override {
1320         canvas->drawColor(SK_ColorWHITE);
1321 
1322         const char* text = "Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges";
1323         TextStyle text_style;
1324         text_style.setFontFamilies({SkString("Ahem")});
1325         text_style.setColor(SK_ColorBLACK);
1326         text_style.setFontSize(16);
1327         //text_style.setLetterSpacing(-0.41);
1328         StrutStyle strut_style;
1329         strut_style.setStrutEnabled(false);
1330         ParagraphStyle paragraph_style;
1331         paragraph_style.setStrutStyle(strut_style);
1332         paragraph_style.setTextStyle(text_style);
1333         ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1334         builder.addText(text);
1335         auto paragraph = builder.Build();
1336         paragraph->layout(1095.000000);
1337         auto result = paragraph->getRectsForRange(65, 66, RectHeightStyle::kTight, RectWidthStyle::kTight);
1338         paragraph->paint(canvas, 0, 0);
1339 
1340         SkPaint paint;
1341         paint.setColor(SK_ColorRED);
1342         paint.setStyle(SkPaint::kStroke_Style);
1343         paint.setAntiAlias(true);
1344         paint.setStrokeWidth(1);
1345         canvas->drawRect(result.front().rect, paint);
1346     }
1347 
1348 private:
1349     typedef Sample INHERITED;
1350 };
1351 
1352 class ParagraphView14 : public ParagraphView_Base {
1353 protected:
name()1354     SkString name() override { return SkString("Paragraph14"); }
1355 
onDrawContent(SkCanvas * canvas)1356     void onDrawContent(SkCanvas* canvas) override {
1357         canvas->drawColor(SK_ColorWHITE);
1358         TextStyle text_style;
1359         text_style.setFontFamilies({SkString("Ahem")});
1360         text_style.setColor(SK_ColorBLACK);
1361         text_style.setFontSize(25);
1362         text_style.setDecoration((TextDecoration)(TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
1363         text_style.setDecorationColor(SK_ColorBLUE);
1364         text_style.setDecorationStyle(TextDecorationStyle::kWavy);
1365         text_style.setDecorationThicknessMultiplier(4.0f);
1366         ParagraphStyle paragraph_style;
1367         paragraph_style.setTextStyle(text_style);
1368         paragraph_style.setTextDirection(TextDirection::kRtl);
1369         ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1370         builder.pushStyle(text_style);
1371         builder.addText("Hello, wor!\nabcd.");
1372         auto paragraph = builder.Build();
1373         paragraph->layout(300);
1374         paragraph->paint(canvas, 0, 0);
1375         SkPaint paint;
1376         paint.setColor(SK_ColorRED);
1377         paint.setStyle(SkPaint::kStroke_Style);
1378         paint.setAntiAlias(true);
1379         paint.setStrokeWidth(1);
1380         canvas->drawRect(SkRect::MakeXYWH(0, 0, 300, 100), paint);
1381     }
1382 
1383 private:
1384     typedef Sample INHERITED;
1385 };
1386 
1387 class ParagraphView15 : public ParagraphView_Base {
1388 protected:
name()1389     SkString name() override { return SkString("Paragraph15"); }
1390 
onDrawContent(SkCanvas * canvas)1391     void onDrawContent(SkCanvas* canvas) override {
1392         canvas->drawColor(SK_ColorWHITE);
1393 
1394         TextStyle text_style;
1395         text_style.setFontFamilies({SkString("abc.ttf")});
1396         text_style.setFontSize(50);
1397 
1398         auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false);
1399 
1400         fontCollection->addFontFromFile("abc/abc.ttf", "abc");
1401         fontCollection->addFontFromFile("abc/abc+grave.ttf", "abc+grave");
1402         fontCollection->addFontFromFile("abc/abc+agrave.ttf", "abc+agrave");
1403 
1404         ParagraphStyle paragraph_style;
1405         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1406 
1407         text_style.setFontFamilies({SkString("abc"), SkString("abc+grave")});
1408         text_style.setColor(SK_ColorBLUE);
1409         builder.pushStyle(text_style);
1410         builder.addText(u"a\u0300");
1411         text_style.setColor(SK_ColorMAGENTA);
1412         builder.pushStyle(text_style);
1413         builder.addText(u"à");
1414 
1415         text_style.setFontFamilies({SkString("abc"), SkString("abc+agrave")});
1416 
1417         text_style.setColor(SK_ColorRED);
1418         builder.pushStyle(text_style);
1419         builder.addText(u"a\u0300");
1420         text_style.setColor(SK_ColorGREEN);
1421         builder.pushStyle(text_style);
1422         builder.addText(u"à");
1423 
1424         auto paragraph = builder.Build();
1425         paragraph->layout(800);
1426         paragraph->paint(canvas, 50, 50);
1427 
1428     }
1429 
1430 private:
1431     typedef Sample INHERITED;
1432 };
1433 
1434 class ParagraphView16 : public ParagraphView_Base {
1435 protected:
name()1436     SkString name() override { return SkString("Paragraph16"); }
1437 
onDrawContent(SkCanvas * canvas)1438     void onDrawContent(SkCanvas* canvas) override {
1439         canvas->drawColor(SK_ColorWHITE);
1440 
1441         const char* text = "content";
1442 
1443         ParagraphStyle paragraph_style;
1444         paragraph_style.setMaxLines(1);
1445         paragraph_style.setEllipsis(u"\u2026");
1446         //auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
1447         auto fontCollection = sk_make_sp<FontCollection>();
1448         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1449         fontCollection->enableFontFallback();
1450         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1451 
1452         TextStyle text_style;
1453         text_style.setFontFamilies({SkString(".SF Pro Text")});
1454         text_style.setColor(SK_ColorBLACK);
1455         text_style.setFontSize(17.0f * 99.0f);
1456         text_style.setLetterSpacing(0.41f);
1457         builder.pushStyle(text_style);
1458         builder.addText(text);
1459 
1460         auto paragraph = builder.Build();
1461         paragraph->layout(800);
1462         paragraph->paint(canvas, 0, 0);
1463     }
1464 
1465 private:
1466     typedef Sample INHERITED;
1467 };
1468 
1469 class ParagraphView17 : public ParagraphView_Base {
1470 protected:
name()1471     SkString name() override { return SkString("Paragraph17"); }
1472 
onDrawContent(SkCanvas * canvas)1473     void onDrawContent(SkCanvas* canvas) override {
1474         canvas->drawColor(SK_ColorWHITE);
1475 
1476         auto fontCollection = sk_make_sp<FontCollection>();
1477         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1478         fontCollection->enableFontFallback();
1479         auto navy = SkColorSetRGB(0, 0, 139);
1480         auto ltgray = SkColorSetRGB(211, 211, 211);
1481         auto multiplier = 5.67;
1482 
1483         const char* text = ">Sͬ͑̀͐̈͒̈́̋̎ͮͩ̽̓ͬ̂̆̔͗́̓ͣͧ͊ͫ͛̉͌̐̑ͪ͗̚͝҉̴͉͢k̡̊̓ͫͭͩ͂͊ͨͪͬ̑ͫ̍̌̄͛̌̂̑̂̋̊̔ͫ͛̽̑ͨ̍ͭ̓̀ͪͪ̉͐͗̌̓̃̚͟͝҉̢͏̫̞̙͇͖̮͕̗̟͕͇͚̻͈̣̻̪͉̰̲̣̫ͅͅP̴̅̍͒̿͗͗̇ͩ̃͆͌̀̽͏̧̡͕͖̝̖̼̺̰̣̬͔͖͔̼͙̞̦̫͓̘͜a̸̴̸̴̢̢̨̨̫͍͓̥̼̭̼̻̤̯̙̤̻̠͚̍̌͋̂ͦͨ̽̇͌͌͆̀̽̎͒̄ͪ̐ͦ̈ͫ͐͗̓̚̚͜ͅr͐͐ͤͫ̐ͥ͂̈́̿́ͮ̃͗̓̏ͫ̀̿͏̸̵̧́͘̕͟͝͠͞͠҉̷̧͚͢͟a̓̽̎̄͗̔͛̄̐͊͛ͫ͂͌̂̂̈̈̓̔̅̅̄͊̉́ͪ̑̄͆ͬ̍͆ͭ͋̐ͬ͏̷̵̨̢̩̹̖͓̥̳̰͔̱̬͖̙͓̙͇̀̀̕͜͟͟͢͟͜͠͡g̨̅̇ͦ͋̂ͦͨͭ̓͐͆̏̂͛̉ͧ̑ͫ̐̒͛ͫ̍̒͛́̚҉̷̨̛̛̀͜͢͞҉̩̘̲͍͎̯̹̝̭̗̱͇͉̲̱͔̯̠̹̥̻͉̲̜̤̰̪̗̺̖̺r̷͌̓̇̅ͭ̀̐̃̃ͭ͑͗̉̈̇̈́ͥ̓ͣ́ͤ͂ͤ͂̏͌̆̚҉̴̸̧̢̢̛̫͉̦̥̤̙͈͉͈͉͓̙̗̟̳̜͈̗̺̟̠̠͖͓̖̪͕̠̕̕͝ͅả̸̴̡̡̧͠͞͡͞҉̛̕͟͏̷̘̪̱͈̲͉̞̠̞̪̫͎̲̬̖̀̀͟͝͞͞͠p̛͂̈͐̚͠҉̵̸̡̢̢̩̹͙̯͖̙̙̮̥̙͚̠͔̥̭̮̞̣̪̬̥̠̖̝̥̪͎́̀̕͜͡͡ͅͅh̵̷̵̡̛ͤ̂͌̐̓̐̋̋͊̒̆̽́̀̀̀͢͠͞͞҉̷̸̢̕҉͚̯͖̫̜̞̟̠̱͉̝̲̹̼͉̟͉̩̮͔̤͖̞̭̙̹̬ͅ<";
1484 
1485         ParagraphStyle paragraph_style;
1486         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1487         SkPaint paint;
1488         paint.setColor(ltgray);
1489         TextStyle text_style;
1490         text_style.setBackgroundColor(paint);
1491         text_style.setColor(navy);
1492         text_style.setFontFamilies({SkString("Roboto")});
1493         text_style.setFontSize(20 * multiplier);
1494         builder.pushStyle(text_style);
1495         builder.addText(text);
1496         auto paragraph = builder.Build();
1497         paragraph->layout(10000);
1498         paragraph->paint(canvas, 0, 0);
1499     }
1500 
1501 private:
1502     typedef Sample INHERITED;
1503 };
1504 
1505 class Zalgo {
1506     private:
1507     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";
1508     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";
1509     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";
1510 
randomMarks(std::u16string & combiningMarks)1511     std::u16string randomMarks(std::u16string& combiningMarks) {
1512         std::u16string result;
1513         auto num = std::rand() % (combiningMarks.size() / 1);
1514         for (size_t i = 0; i < num; ++i) {
1515             auto index = std::rand() % combiningMarks.size();
1516             result += combiningMarks[index];
1517         }
1518         return result;
1519     }
1520 
1521 public:
zalgo(std::string victim)1522     std::u16string zalgo(std::string victim) {
1523         std::u16string result;
1524         for (auto& c : victim) {
1525             result += c;
1526             result += randomMarks(COMBINING_UP);
1527             result += randomMarks(COMBINING_MIDDLE);
1528             result += randomMarks(COMBINING_DOWN);
1529         }
1530         return result;
1531     }
1532 };
1533 
1534 class ParagraphView18 : public ParagraphView_Base {
1535 protected:
name()1536     SkString name() override { return SkString("Paragraph18"); }
1537 
onChar(SkUnichar uni)1538     bool onChar(SkUnichar uni) override {
1539             switch (uni) {
1540                 case ' ':
1541                     fLimit = 400;
1542                     return true;
1543                 case 's':
1544                     fLimit += 10;
1545                     return true;
1546                 case 'f':
1547                     if (fLimit > 10) {
1548                         fLimit -= 10;
1549                     }
1550                     return true;
1551                 default:
1552                     break;
1553             }
1554             return false;
1555     }
1556 
onAnimate(double nanos)1557     bool onAnimate(double nanos) override {
1558         if (++fIndex > fLimit) {
1559             fRedraw = true;
1560             fIndex = 0;
1561         } else {
1562             fRepeat = true;
1563         }
1564         return true;
1565     }
1566 
onDrawContent(SkCanvas * canvas)1567     void onDrawContent(SkCanvas* canvas) override {
1568         canvas->drawColor(SK_ColorWHITE);
1569 
1570         auto navy = SkColorSetRGB(0, 0, 139);
1571         auto ltgray = SkColorSetRGB(211, 211, 211);
1572 
1573         auto multiplier = 5.67;
1574         auto fontCollection = sk_make_sp<FontCollection>();
1575         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1576         fontCollection->enableFontFallback();
1577 
1578         ParagraphStyle paragraph_style;
1579         TextStyle text_style;
1580         text_style.setFontFamilies({SkString("Roboto")});
1581         text_style.setFontSize(20 * multiplier);
1582         text_style.setColor(navy);
1583         SkPaint paint;
1584         paint.setColor(ltgray);
1585         text_style.setBackgroundColor(paint);
1586 
1587         Zalgo zalgo;
1588 
1589         if (fRedraw || fRepeat) {
1590 
1591             if (fRedraw || fParagraph.get() == nullptr) {
1592                 ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1593                 builder.pushStyle(text_style);
1594                 auto utf16text = zalgo.zalgo("SkParagraph");
1595                 icu::UnicodeString unicode((UChar*)utf16text.data(), SkToS32(utf16text.size()));
1596                 std::string str;
1597                 unicode.toUTF8String(str);
1598                 SkDebugf("Text:>%s<\n", str.data());
1599                 builder.addText(utf16text);
1600                 fParagraph = builder.Build();
1601             }
1602 
1603             auto impl = static_cast<ParagraphImpl*>(fParagraph.get());
1604             impl->setState(InternalState::kUnknown);
1605             fParagraph->layout(1000);
1606             fParagraph->paint(canvas, 300, 200);
1607 
1608             for (auto& run : impl->runs()) {
1609                 SkString fontFamily("unresolved");
1610                 if (run.font().getTypeface() != nullptr) {
1611                     run.font().getTypeface()->getFamilyName(&fontFamily);
1612                 }
1613                 if (run.font().getTypeface() != nullptr) {
1614                     for (size_t i = 0; i < run.size(); ++i) {
1615                         auto glyph = run.glyphs().begin() + i;
1616                         if (*glyph == 0) {
1617                             SkDebugf("Run[%d] @pos=%d\n", run.index(), i);
1618                             SkASSERT(false);
1619                         }
1620                     }
1621                 } else {
1622                     SkDebugf("Run[%d]: %s\n", run.index(), fontFamily.c_str());
1623                     SkASSERT(false);
1624                 }
1625             }
1626             fRedraw = false;
1627             fRepeat = false;
1628         }
1629     }
1630 
1631 private:
1632     bool fRedraw = true;
1633     bool fRepeat = false;
1634     size_t fIndex = 0;
1635     size_t fLimit = 20;
1636     std::unique_ptr<Paragraph> fParagraph;
1637     typedef Sample INHERITED;
1638 };
1639 
1640 class ParagraphView19 : public ParagraphView_Base {
1641 protected:
name()1642     SkString name() override { return SkString("Paragraph19"); }
1643 
onDrawContent(SkCanvas * canvas)1644     void onDrawContent(SkCanvas* canvas) override {
1645         canvas->drawColor(SK_ColorWHITE);
1646 
1647         auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
1648 
1649         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";
1650         ParagraphStyle paragraph_style;
1651         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1652         TextStyle text_style;
1653         text_style.setColor(SK_ColorBLACK);
1654         text_style.setFontFamilies({SkString("Roboto")});
1655         text_style.setFontSize(20);
1656         builder.pushStyle(text_style);
1657         builder.addText(text);
1658         auto paragraph = builder.Build();
1659         paragraph->layout(this->width());
1660         paragraph->paint(canvas, 0, 0);
1661     }
1662 
1663 private:
1664     typedef Sample INHERITED;
1665 };
1666 
1667 class ParagraphView20 : public ParagraphView_Base {
1668 protected:
name()1669     SkString name() override { return SkString("Paragraph20"); }
1670 
onDrawContent(SkCanvas * canvas)1671     void onDrawContent(SkCanvas* canvas) override {
1672         canvas->drawColor(SK_ColorWHITE);
1673 
1674         auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
1675 
1676         const char* text =  "Manage your google account";
1677         ParagraphStyle paragraph_style;
1678         paragraph_style.setEllipsis(u"\u2026");
1679         paragraph_style.setMaxLines(1);
1680         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1681         TextStyle text_style;
1682         text_style.setColor(SK_ColorBLACK);
1683         text_style.setFontFamilies({SkString("Roboto")});
1684         text_style.setFontSize(50);
1685         builder.pushStyle(text_style);
1686         builder.addText(text);
1687         auto paragraph = builder.Build();
1688         paragraph->layout(this->width());
1689         paragraph->paint(canvas, 0, 0);
1690     }
1691 
1692 private:
1693     typedef Sample INHERITED;
1694 };
1695 
1696 class ParagraphView21 : public ParagraphView_Base {
1697 protected:
name()1698     SkString name() override { return SkString("Paragraph21"); }
1699 
onDrawContent(SkCanvas * canvas)1700     void onDrawContent(SkCanvas* canvas) override {
1701         canvas->drawColor(SK_ColorWHITE);
1702 
1703         const char* text =  "Referral Code";
1704         ParagraphStyle paragraph_style;
1705         ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1706         TextStyle text_style;
1707         text_style.setColor(SK_ColorBLACK);
1708         text_style.setFontFamilies({SkString("Google Sans")});
1709         text_style.setFontSize(24);
1710         builder.pushStyle(text_style);
1711         builder.addText(text);
1712         auto paragraph = builder.Build();
1713         paragraph->layout(0);
1714         paragraph->paint(canvas, 0, 0);
1715     }
1716 
1717 private:
1718     typedef Sample INHERITED;
1719 };
1720 
1721 class ParagraphView22 : public ParagraphView_Base {
1722 protected:
name()1723     SkString name() override { return SkString("Paragraph22"); }
1724 
onChar(SkUnichar uni)1725     bool onChar(SkUnichar uni) override {
1726             switch (uni) {
1727                 case 'l':
1728                     direction = true;
1729                     return true;
1730                 case 'r':
1731                     direction = false;
1732                     return true;
1733                 default:
1734                     break;
1735             }
1736             return false;
1737     }
1738 
onDrawContent(SkCanvas * canvas)1739     void onDrawContent(SkCanvas* canvas) override {
1740 
1741         canvas->drawColor(SK_ColorWHITE);
1742         ParagraphStyle paragraph_style;
1743         paragraph_style.setTextDirection(direction ? TextDirection::kLtr : TextDirection::kRtl);
1744         auto collection = getFontCollection();
1745         ParagraphBuilderImpl builder(paragraph_style, collection);
1746         collection->getParagraphCache()->reset();
1747         collection->getParagraphCache()->turnOn(false);
1748         TextStyle text_style;
1749         text_style.setColor(SK_ColorBLACK);
1750         text_style.setFontFamilies({SkString("Roboto")});
1751         text_style.setFontSize(12);
1752         builder.pushStyle(text_style);
1753         builder.addText("I have got a ");
1754         text_style.setFontStyle(SkFontStyle::Bold());
1755         builder.pushStyle(text_style);
1756         builder.addText("lovely bunch");
1757         text_style.setFontStyle(SkFontStyle::Normal());
1758         builder.pushStyle(text_style);
1759         builder.addText(" of coconuts.");
1760         auto paragraph = builder.Build();
1761         paragraph->layout(this->width());
1762         paragraph->paint(canvas, 0, 0);
1763         collection->getParagraphCache()->turnOn(true);
1764     }
1765 
1766 private:
1767     typedef Sample INHERITED;
1768     bool direction;
1769 };
1770 
1771 class ParagraphView23 : public ParagraphView_Base {
1772 protected:
name()1773     SkString name() override { return SkString("Paragraph23"); }
1774 
onDrawContent(SkCanvas * canvas)1775     void onDrawContent(SkCanvas* canvas) override {
1776         canvas->drawColor(SK_ColorWHITE);
1777 
1778         const char* text =  "Text with shadow";
1779         ParagraphStyle paragraph_style;
1780         TextStyle text_style;
1781         text_style.setColor(SK_ColorBLACK);
1782         text_style.setFontFamilies({SkString("Google Sans")});
1783         text_style.setFontSize(24);
1784 
1785         auto draw = [&](SkScalar h, SkScalar v, SkScalar b) {
1786             text_style.resetShadows();
1787             text_style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(h, v), b));
1788             ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1789             builder.pushStyle(text_style);
1790             builder.addText(text);
1791             auto paragraph = builder.Build();
1792             paragraph->layout(300);
1793             paragraph->paint(canvas, 0, 0);
1794 
1795             auto rect = SkRect::MakeXYWH(0, 0, paragraph->getMaxWidth(), paragraph->getHeight());
1796             SkPaint paint;
1797             paint.setColor(SK_ColorRED);
1798             paint.setStyle(SkPaint::kStroke_Style);
1799             paint.setAntiAlias(true);
1800             paint.setStrokeWidth(1);
1801             canvas->drawRect(rect, paint);
1802         };
1803 
1804         draw(10, 10, 5);
1805         canvas->translate(0, 100);
1806 
1807         draw(10, -10, 5);
1808         canvas->translate(0, 100);
1809 
1810         draw(-10, -10, 5);
1811         canvas->translate(0, 100);
1812 
1813         draw(-10, 10, 5);
1814         canvas->translate(0, 100);
1815     }
1816 
1817 private:
1818     typedef Sample INHERITED;
1819 };
1820 
1821 class ParagraphView24 : public ParagraphView_Base {
1822 protected:
name()1823     SkString name() override { return SkString("Paragraph24"); }
1824 
onDrawContent(SkCanvas * canvas)1825     void onDrawContent(SkCanvas* canvas) override {
1826         canvas->drawColor(SK_ColorWHITE);
1827 
1828         ParagraphStyle paragraph_style;
1829         paragraph_style.setTextDirection(TextDirection::kRtl);
1830         TextStyle text_style;
1831         text_style.setColor(SK_ColorBLACK);
1832         text_style.setFontFamilies({SkString("Google Sans")});
1833         text_style.setFontSize(24);
1834         {
1835             ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1836             builder.pushStyle(text_style);
1837             builder.addText("Right_to_left:");
1838             auto paragraph = builder.Build();
1839             paragraph->layout(this->width());
1840             paragraph->paint(canvas, 0, 0);
1841         }
1842         canvas->translate(0, 200);
1843         {
1844             ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1845             builder.pushStyle(text_style);
1846             builder.addText("Right_to_left+");
1847             auto paragraph = builder.Build();
1848             paragraph->layout(this->width());
1849             paragraph->paint(canvas, 0, 0);
1850         }
1851         canvas->translate(0, 200);
1852         {
1853             ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1854             builder.pushStyle(text_style);
1855             builder.addText("Right_to_left.");
1856             auto paragraph = builder.Build();
1857             paragraph->layout(this->width());
1858             paragraph->paint(canvas, 0, 0);
1859         }
1860     }
1861 
1862 private:
1863     typedef Sample INHERITED;
1864 };
1865 
1866 class ParagraphView25 : public ParagraphView_Base {
1867 protected:
name()1868     SkString name() override { return SkString("Paragraph25"); }
1869 
onDrawContent(SkCanvas * canvas)1870     void onDrawContent(SkCanvas* canvas) override {
1871         canvas->drawColor(SK_ColorWHITE);
1872 /*
1873  * Shell: ParagraphStyle: 1.000000 1
1874 Shell: Strut enabled: 0 1.000000 14.000000 400 5 0
1875 Shell: Font Families: 0
1876 Shell: DefaultTextStyle: 16.000000 500 5 0
1877 Shell: Font Families: 1 Roboto
1878 Shell: Font Features: 0
1879 Shell: TextStyle#0: [0:22) 16.000000 500 5 0
1880 Shell: Font Families: 1 Roboto
1881 Shell: Font Features: 0
1882 Shell: TextStyle#1: [25:49) 16.000000 500 5 0
1883 Shell: Font Families: 1 Roboto
1884 Shell: Font Features: 0
1885 Shell: Placeholder#0: [22:25) 32.000000 32.000000 32.000000 0 5
1886 Shell: Placeholder#1: [49:52) 19.000000 41.000000 19.000000 0 4
1887 Shell: Placeholder#2: [52:52) 0.000000 0.000000 0.000000 0 5
1888 Shell: layout('Go to device settings  and set up a passcode. ', 280.000000): 280.000000 * 38.000000
1889  */
1890         auto fontCollection = getFontCollection();
1891         //fontCollection->getParagraphCache()->turnOn(false);
1892         const char* text1 =  "Go to device settings ";
1893         const char* text2 = "and set up a passcode.";
1894         ParagraphStyle paragraph_style;
1895         StrutStyle strut_style;
1896         strut_style.setStrutEnabled(false);
1897         strut_style.setFontSize(14);
1898         strut_style.setForceStrutHeight(false);
1899         strut_style.setHeight(14);
1900         paragraph_style.setStrutStyle(strut_style);
1901         TextStyle text_style;
1902         text_style.setColor(SK_ColorBLACK);
1903         text_style.setFontFamilies({SkString("Roboto")});
1904         text_style.setFontSize(16);
1905         PlaceholderStyle placeholder_style;
1906         {
1907             ParagraphBuilderImpl builder(paragraph_style, fontCollection);
1908             builder.pushStyle(text_style);
1909             builder.addText(text1);
1910             placeholder_style.fHeight = 32;
1911             placeholder_style.fWidth = 32;
1912             placeholder_style.fBaselineOffset = 32;
1913             placeholder_style.fBaseline = TextBaseline::kAlphabetic;
1914             placeholder_style.fAlignment = PlaceholderAlignment::kMiddle;
1915             builder.addPlaceholder(placeholder_style);
1916             builder.addText(text2);
1917             placeholder_style.fHeight = 19;
1918             placeholder_style.fWidth = 41;
1919             placeholder_style.fBaselineOffset = 19;
1920             placeholder_style.fBaseline = TextBaseline::kAlphabetic;
1921             placeholder_style.fAlignment = PlaceholderAlignment::kTop;
1922             builder.addPlaceholder(placeholder_style);
1923             auto paragraph = builder.Build();
1924             paragraph->layout(280);
1925             paragraph->paint(canvas, 0, 0);
1926         }
1927     }
1928 
1929 private:
1930     typedef Sample INHERITED;
1931 };
1932 
1933 class ParagraphView26 : public ParagraphView_Base {
1934 protected:
name()1935     SkString name() override { return SkString("Paragraph26"); }
1936 
onDrawContent(SkCanvas * canvas)1937     void onDrawContent(SkCanvas* canvas) override {
1938         auto fontCollection = sk_make_sp<FontCollection>();
1939         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1940         //fontCollection->enableFontFallback();
1941 
1942         canvas->clear(SK_ColorWHITE);
1943 
1944         SkPaint paint;
1945         paint.setAntiAlias(true);
1946         paint.setColor(SK_ColorBLACK);
1947 
1948         TextStyle textStyle;
1949         textStyle.setForegroundColor(paint);
1950         textStyle.setFontFamilies({ SkString("Roboto") });
1951         textStyle.setFontSize(42.0f);
1952         textStyle.setLetterSpacing(-0.05f);
1953         textStyle.setHeightOverride(true);
1954 
1955         ParagraphStyle paragraphStyle;
1956         paragraphStyle.setTextStyle(textStyle);
1957         paragraphStyle.setTextAlign(TextAlign::kLeft);
1958 
1959         ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
1960         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");
1961 
1962         auto paragraph = builder.Build();
1963         paragraph->layout(this->width() / 2);
1964 
1965         std::vector<LineMetrics> lines;
1966         paragraph->getLineMetrics(lines); // <-- error happens here
1967 
1968         canvas->translate(10, 10);
1969         paragraph->paint(canvas, 0, 0);
1970     }
1971 
1972 private:
1973     typedef Sample INHERITED;
1974 };
1975 
1976 class ParagraphView27 : public ParagraphView_Base {
1977 protected:
name()1978     SkString name() override { return SkString("Paragraph27"); }
1979 
onDrawContent(SkCanvas * canvas)1980     void onDrawContent(SkCanvas* canvas) override {
1981         auto fontCollection = sk_make_sp<FontCollection>();
1982         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
1983         fontCollection->enableFontFallback();
1984         fontCollection->getParagraphCache()->turnOn(false);
1985 
1986         SkPaint red;
1987         red.setColor(SK_ColorRED);
1988         red.setStyle(SkPaint::kStroke_Style);
1989         red.setAntiAlias(true);
1990         red.setStrokeWidth(1);
1991 
1992         SkPaint blue;
1993         blue.setColor(SK_ColorRED);
1994         blue.setStyle(SkPaint::kStroke_Style);
1995         blue.setAntiAlias(true);
1996         blue.setStrokeWidth(1);
1997 
1998         SkPaint black;
1999         black.setColor(SK_ColorBLACK);
2000         black.setStyle(SkPaint::kStroke_Style);
2001         black.setAntiAlias(true);
2002         black.setStrokeWidth(1);
2003 
2004         SkPaint whiteSpaces;
2005         whiteSpaces.setColor(SK_ColorLTGRAY);
2006 
2007         SkPaint breakingSpace;
2008         breakingSpace.setColor(SK_ColorYELLOW);
2009 
2010         SkPaint text;
2011         text.setColor(SK_ColorWHITE);
2012 
2013         ParagraphStyle paragraph_style;
2014         paragraph_style.setTextAlign(TextAlign::kRight);
2015         TextStyle text_style;
2016         text_style.setColor(SK_ColorBLACK);
2017         text_style.setFontFamilies({SkString("Roboto")});
2018 
2019         // RTL + right align + arabic
2020         // RTL + right align + latin
2021         // LTR + right align + arabic
2022         // LTR + right align + latin
2023         // RTL + left align + arabic
2024         // RTL + left align + latin
2025         // arabic and latin should not differ at all
2026         // check: line breaking and trailing spaces
2027 
2028         canvas->drawColor(SK_ColorWHITE);
2029         auto h = 60;
2030         auto w = 300;
2031 
2032         auto draw = [&](SkScalar width, SkScalar height, TextDirection td, TextAlign ta, const char* t) {
2033             SkDebugf("draw '%s' dir:%s align:%s\n", t,
2034                     td == TextDirection::kLtr ? "left" : "right",
2035                     ta == TextAlign::kLeft ? "left" : "right");
2036             paragraph_style.setTextDirection(td);
2037             paragraph_style.setTextAlign(ta);
2038             text_style.setFontSize(20);
2039             ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2040             text_style.setBackgroundColor(whiteSpaces);
2041             builder.pushStyle(text_style);
2042             builder.addText("   ");
2043             text_style.setBackgroundColor(text);
2044             builder.pushStyle(text_style);
2045             builder.addText(t);
2046             text_style.setBackgroundColor(breakingSpace);
2047             builder.pushStyle(text_style);
2048             builder.addText(" ");
2049             text_style.setBackgroundColor(text);
2050             builder.pushStyle(text_style);
2051             builder.addText(t);
2052             text_style.setBackgroundColor(whiteSpaces);
2053             builder.pushStyle(text_style);
2054             builder.addText("   ");
2055             auto paragraph = builder.Build();
2056             paragraph->layout(width);
2057             paragraph->paint(canvas, 0, 0);
2058             auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2059             for (auto& line : impl->lines()) {
2060                 SkDebugf("line[%d]: %f + %f\n", &line - impl->lines().begin(), line.offset().fX, line.shift());
2061                 line.iterateThroughVisualRuns(true,
2062                     [&](const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width) {
2063                     *width = line.measureTextInsideOneRun(textRange, run, runOffset, 0, true, false).clip.width();
2064                     SkDebugf("%d[%d: %d) @%f + %f %s\n", run->index(),
2065                             textRange.start, textRange.end, runOffset, *width, run->leftToRight() ? "left" : "right");
2066                     return true;
2067                 });
2068             }
2069             auto boxes = paragraph->getRectsForRange(0, 100, RectHeightStyle::kTight, RectWidthStyle::kTight);
2070             bool even = true;
2071             for (auto& box : boxes) {
2072                 SkDebugf("[%f:%f,%f:%f] %s\n",
2073                         box.rect.fLeft, box.rect.fRight, box.rect.fTop, box.rect.fBottom,
2074                         box.direction == TextDirection::kLtr ? "left" : "right");
2075                 canvas->drawRect(box.rect, even ? red : blue);
2076                 even = !even;
2077             }
2078             canvas->translate(0, height);
2079         };
2080 
2081         canvas->drawRect(SkRect::MakeXYWH(0, 0, w, h * 8), black);
2082 
2083         draw(w, h, TextDirection::kRtl, TextAlign::kRight, "RTL+RIGHT#1234567890");
2084         draw(w, h, TextDirection::kRtl, TextAlign::kRight, "قففغغغغقففغغغغقففغغغ");
2085 
2086         draw(w, h, TextDirection::kLtr, TextAlign::kRight, "LTR+RIGHT#1234567890");
2087         draw(w, h, TextDirection::kLtr, TextAlign::kRight, "قففغغغغقففغغغغقففغغغ");
2088 
2089         draw(w, h, TextDirection::kRtl, TextAlign::kLeft, "RTL+LEFT##1234567890");
2090         draw(w, h, TextDirection::kRtl, TextAlign::kLeft, "قففغغغغقففغغغغقففغغغ");
2091 
2092         draw(w, h, TextDirection::kLtr, TextAlign::kLeft, "LTR+LEFT##1234567890");
2093         draw(w, h, TextDirection::kLtr, TextAlign::kLeft, "قففغغغغقففغغغغقففغغغ");
2094     }
2095 
2096 private:
2097     typedef Sample INHERITED;
2098 };
2099 
2100 class ParagraphView28 : public ParagraphView_Base {
2101 protected:
name()2102     SkString name() override { return SkString("Paragraph28"); }
2103 
onDrawContent(SkCanvas * canvas)2104     void onDrawContent(SkCanvas* canvas) override {
2105 
2106         const char* text = "AAAAA BBBBB CCCCC DDDDD EEEEE FFFFF GGGGG HHHHH IIIII JJJJJ KKKKK LLLLL MMMMM NNNNN OOOOO PPPPP QQQQQ";
2107 
2108         canvas->drawColor(SK_ColorWHITE);
2109         ParagraphStyle paragraph_style;
2110         paragraph_style.setTextAlign(TextAlign::kJustify);
2111         auto collection = getFontCollection();
2112         ParagraphBuilderImpl builder(paragraph_style, collection);
2113         TextStyle text_style;
2114         text_style.setColor(SK_ColorBLACK);
2115         text_style.setFontFamilies({SkString("Roboto")});
2116         text_style.setFontSize(40);
2117         builder.pushStyle(text_style);
2118         builder.addText(text);
2119         auto paragraph = builder.Build();
2120         auto s = 186;
2121         paragraph->layout(360 - s);
2122         paragraph->paint(canvas, 0, 0);
2123         /*
2124         paragraph->layout(360);
2125         paragraph->paint(canvas, 0, 0);
2126         canvas->translate(0, 400);
2127         paragraph->layout(354.333);
2128         paragraph->paint(canvas, 0, 0);
2129         */
2130     }
2131 
2132 private:
2133     typedef Sample INHERITED;
2134 };
2135 
2136 class ParagraphView29 : public ParagraphView_Base {
2137 protected:
name()2138     SkString name() override { return SkString("Paragraph29"); }
2139 
onDrawContent(SkCanvas * canvas)2140     void onDrawContent(SkCanvas* canvas) override {
2141 
2142         const char* text = "ffi";
2143         canvas->drawColor(SK_ColorWHITE);
2144 
2145         auto collection = getFontCollection();
2146 
2147         ParagraphStyle paragraph_style;
2148         ParagraphBuilderImpl builder(paragraph_style, collection);
2149         TextStyle text_style;
2150         text_style.setColor(SK_ColorBLACK);
2151         text_style.setFontFamilies({SkString("Roboto")});
2152         text_style.setFontSize(60);
2153         builder.pushStyle(text_style);
2154         builder.addText(text);
2155         auto paragraph = builder.Build();
2156         paragraph->layout(width());
2157         paragraph->paint(canvas, 0, 0);
2158         auto width = paragraph->getLongestLine();
2159         auto height = paragraph->getHeight();
2160 
2161         auto f1 = paragraph->getGlyphPositionAtCoordinate(width/6, height/2);
2162         auto f2 = paragraph->getGlyphPositionAtCoordinate(width/2, height/2);
2163         auto i = paragraph->getGlyphPositionAtCoordinate(width*5/6, height/2);
2164 
2165         SkDebugf("%d(%s) %d(%s) %d(%s)\n",
2166                 f1.position, f1.affinity == Affinity::kUpstream ? "up" : "down",
2167                 f2.position, f2.affinity == Affinity::kUpstream ? "up" : "down",
2168                 i.position, i.affinity == Affinity::kUpstream ? "up" : "down");
2169 
2170         auto rf1 = paragraph->getRectsForRange(0, 1, RectHeightStyle::kTight, RectWidthStyle::kTight)[0];
2171         auto rf2 = paragraph->getRectsForRange(1, 2, RectHeightStyle::kTight, RectWidthStyle::kTight)[0];
2172         auto rfi = paragraph->getRectsForRange(2, 3, RectHeightStyle::kTight, RectWidthStyle::kTight)[0];
2173 
2174         SkDebugf("f1: [%f:%f] %s\n",
2175                 rf1.rect.fLeft, rf1.rect.fRight, rf1.direction == TextDirection::kRtl ? "rtl" : "ltr");
2176         SkDebugf("f2: [%f:%f] %s\n",
2177                 rf2.rect.fLeft, rf2.rect.fRight, rf2.direction == TextDirection::kRtl ? "rtl" : "ltr");
2178         SkDebugf("i:  [%f:%f] %s\n",
2179                 rfi.rect.fLeft, rfi.rect.fRight, rfi.direction == TextDirection::kRtl ? "rtl" : "ltr");
2180     }
2181 
2182 private:
2183     typedef Sample INHERITED;
2184 };
2185 
2186 class ParagraphView30 : public ParagraphView_Base {
2187 protected:
name()2188     SkString name() override { return SkString("Paragraph30"); }
2189 
onDrawContent(SkCanvas * canvas)2190     void onDrawContent(SkCanvas* canvas) override {
2191 
2192         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";
2193         canvas->drawColor(SK_ColorWHITE);
2194 
2195         auto fontCollection = sk_make_sp<FontCollection>();
2196         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2197         fontCollection->enableFontFallback();
2198 
2199         ParagraphStyle paragraph_style;
2200         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2201         TextStyle text_style;
2202         text_style.setColor(SK_ColorBLACK);
2203         text_style.setFontFamilies({SkString("Noto Color Emoji")});
2204         text_style.setFontSize(60);
2205         builder.pushStyle(text_style);
2206         builder.addText(text);
2207         auto paragraph = builder.Build();
2208         paragraph->layout(width());
2209 
2210 
2211         SkColor colors[] = {
2212             SK_ColorRED,
2213             SK_ColorGREEN,
2214             SK_ColorBLUE,
2215             SK_ColorMAGENTA,
2216             SK_ColorYELLOW
2217         };
2218         SkPaint paint;
2219         size_t color = 0;
2220         for (size_t i = 0; i < text.size(); ++i) {
2221             auto result = paragraph->getRectsForRange(i, i + 1, RectHeightStyle::kTight, RectWidthStyle::kTight);
2222             if (result.empty()) {
2223                 SkDebugf("empty [%d:%d)\n", i, i + 1);
2224                 continue;
2225             }
2226             auto rect = result[0].rect;
2227             paint.setColor(colors[color++ % 5]);
2228             canvas->drawRect(rect, paint);
2229             SkDebugf("rect [%d:%d): %f:%f\n", i, i + 1, rect.fLeft, rect.fRight);
2230         }
2231         paragraph->paint(canvas, 0, 0);
2232     }
2233 
2234 private:
2235     typedef Sample INHERITED;
2236 };
2237 
2238 class ParagraphView31 : public ParagraphView_Base {
2239 protected:
name()2240     SkString name() override { return SkString("Paragraph31"); }
2241 
onDrawContent(SkCanvas * canvas)2242     void onDrawContent(SkCanvas* canvas) override {
2243 
2244         canvas->drawColor(SK_ColorWHITE);
2245 
2246         auto fontCollection = sk_make_sp<FontCollection>();
2247         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2248         fontCollection->enableFontFallback();
2249 
2250         ParagraphStyle paragraph_style;
2251         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2252         TextStyle text_style;
2253         text_style.setColor(SK_ColorBLACK);
2254         text_style.setFontFamilies({SkString("Roboto")});
2255         text_style.setFontSize(40);
2256         builder.pushStyle(text_style);
2257         auto s = u"েن েূথ";
2258         builder.addText(s);
2259         auto paragraph = builder.Build();
2260         paragraph->layout(width());
2261         paragraph->paint(canvas, 0, 0);
2262     }
2263 
2264 private:
2265     typedef Sample INHERITED;
2266 };
2267 
2268 class ParagraphView32 : public ParagraphView_Base {
2269 protected:
name()2270     SkString name() override { return SkString("Paragraph32"); }
2271 
onDrawContent(SkCanvas * canvas)2272     void onDrawContent(SkCanvas* canvas) override {
2273 
2274         canvas->drawColor(SK_ColorWHITE);
2275 
2276         auto fontCollection = sk_make_sp<FontCollection>();
2277         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2278         fontCollection->enableFontFallback();
2279 
2280         ParagraphStyle paragraph_style;
2281         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2282         TextStyle text_style;
2283         text_style.setColor(SK_ColorBLACK);
2284         text_style.setFontFamilies({SkString("Roboto")});
2285         text_style.setFontSize(40);
2286         text_style.setLocale(SkString("ko"));
2287         builder.pushStyle(text_style);
2288         builder.addText(u"\u904d ko ");
2289         text_style.setLocale(SkString("zh_Hant"));
2290         builder.pushStyle(text_style);
2291         builder.addText(u"\u904d zh-Hant ");
2292         text_style.setLocale(SkString("zh_Hans"));
2293         builder.pushStyle(text_style);
2294         builder.addText(u"\u904d zh-Hans ");
2295         text_style.setLocale(SkString("zh_HK"));
2296         builder.pushStyle(text_style);
2297         builder.addText(u"\u904d zh-HK ");
2298         auto paragraph = builder.Build();
2299         paragraph->layout(width());
2300         paragraph->paint(canvas, 0, 0);
2301     }
2302 
2303 private:
2304     typedef Sample INHERITED;
2305 };
2306 
2307 class ParagraphView33 : public ParagraphView_Base {
2308 protected:
name()2309     SkString name() override { return SkString("Paragraph33"); }
2310 
onDrawContent(SkCanvas * canvas)2311     void onDrawContent(SkCanvas* canvas) override {
2312 
2313         canvas->drawColor(SK_ColorWHITE);
2314 
2315         auto fontCollection = sk_make_sp<FontCollection>();
2316         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2317         fontCollection->enableFontFallback();
2318 
2319         ParagraphStyle paragraph_style;
2320         paragraph_style.setTextAlign(TextAlign::kJustify);
2321         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2322         TextStyle text_style;
2323         text_style.setColor(SK_ColorBLACK);
2324         text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Color Emoji")});
2325         text_style.setFontSize(36);
2326         builder.pushStyle(text_style);
2327         builder.addText(u"AAAAA \U0001f600 BBBBB CCCCC DDDDD EEEEE");
2328         auto paragraph = builder.Build();
2329         paragraph->layout(width() / 2);
2330         SkPaint paint;
2331         paint.setColor(SK_ColorLTGRAY);
2332         canvas->drawRect(SkRect::MakeXYWH(0, 0, width()/2, paragraph->getHeight()), paint);
2333         paragraph->paint(canvas, 0, 0);
2334     }
2335 
2336 private:
2337     typedef Sample INHERITED;
2338 };
2339 
2340 class ParagraphView34 : public ParagraphView_Base {
2341 protected:
name()2342     SkString name() override { return SkString("Paragraph34"); }
2343 
onDrawContent(SkCanvas * canvas)2344     void onDrawContent(SkCanvas* canvas) override {
2345 
2346         canvas->drawColor(SK_ColorWHITE);
2347         auto text = "ضخمة ص ،������ضضض ؤ،،��������شسي،������ؤرى،��������ببب،����������ثيلااتن";
2348         //auto text = "ى،��������بب";
2349         //auto text1 = "World domination is such an ugly phrase - I prefer to call it world optimisation";
2350         auto fontCollection = sk_make_sp<FontCollection>();
2351         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2352         fontCollection->enableFontFallback();
2353 
2354         ParagraphStyle paragraph_style;
2355         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2356         TextStyle text_style;
2357         text_style.setColor(SK_ColorBLACK);
2358         text_style.setFontFamilies({SkString("Noto Color Emoji")});
2359         text_style.setFontSize(50);
2360         builder.pushStyle(text_style);
2361         builder.addText(text);
2362         auto paragraph = builder.Build();
2363         paragraph->layout(1041); // 1041
2364 
2365         SkColor colors[] = {SK_ColorBLUE, SK_ColorCYAN,  SK_ColorLTGRAY, SK_ColorGREEN,
2366                             SK_ColorRED,  SK_ColorWHITE, SK_ColorYELLOW, SK_ColorMAGENTA };
2367         SkPaint paint;
2368         size_t wordPos = 0;
2369         size_t index = 0;
2370         while (wordPos < 72) {
2371             auto res2 = paragraph->getWordBoundary(wordPos);
2372             if (res2.width() == 0) {
2373                 break;
2374             }
2375             wordPos = res2.end;
2376             auto res3 = paragraph->getRectsForRange(
2377                     res2.start, res2.end,
2378                     RectHeightStyle::kTight, RectWidthStyle::kTight);
2379             paint.setColor(colors[index % 8]);
2380             ++index;
2381             if (!res3.empty()) {
2382                 canvas->drawRect(res3[0].rect, paint);
2383             }
2384         }
2385         paragraph->paint(canvas, 0, 0);
2386     }
2387 
2388 private:
2389     typedef Sample INHERITED;
2390 };
2391 
2392 class ParagraphView35 : public ParagraphView_Base {
2393 protected:
name()2394     SkString name() override { return SkString("Paragraph35"); }
2395 
onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey modi)2396     Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
2397         return new Click;
2398     }
2399 
onClick(Click * click)2400     bool onClick(Click* click) override {
2401         fPoint = click->fCurr;
2402         return true;
2403     }
2404 
onDrawContent(SkCanvas * canvas)2405     void onDrawContent(SkCanvas* canvas) override {
2406 
2407         canvas->drawColor(SK_ColorWHITE);
2408 
2409         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";
2410         auto fontCollection = sk_make_sp<FontCollection>();
2411         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2412         fontCollection->enableFontFallback();
2413 
2414         ParagraphStyle paragraph_style;
2415         //paragraph_style.setTextAlign(TextAlign::kJustify);
2416         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2417         TextStyle text_style;
2418         text_style.setColor(SK_ColorBLACK);
2419         text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Color Emoji")});
2420         text_style.setFontSize(40);
2421         builder.pushStyle(text_style);
2422         builder.addText(text);
2423         auto paragraph = builder.Build();
2424         paragraph->layout(width());//758
2425 
2426         //auto res1 = paragraph->getGlyphPositionAtCoordinate(line.width() + line.spacesWidth() / 2, line.offset().fY + 10);
2427         //auto res2 = paragraph->getWordBoundary(res1.position);
2428         auto res1 = paragraph->getRectsForRange(360, 361, RectHeightStyle::kTight, RectWidthStyle::kTight);
2429         auto res2 = paragraph->getRectsForRange(359, 360, RectHeightStyle::kTight, RectWidthStyle::kTight);
2430         auto res3 = paragraph->getRectsForRange(358, 359, RectHeightStyle::kTight, RectWidthStyle::kTight);
2431 
2432         auto draw = [&](std::vector<TextBox> res, SkColor color) {
2433             SkPaint paint;
2434             paint.setColor(color);
2435             for (auto& r : res) {
2436                 canvas->drawRect(r.rect, paint);
2437             }
2438         };
2439 
2440         draw(res1, SK_ColorRED);
2441         draw(res2, SK_ColorGREEN);
2442         draw(res3, SK_ColorBLUE);
2443 
2444         paragraph->paint(canvas, 0, 0);
2445     }
2446 
2447 private:
2448     typedef Sample INHERITED;
2449     SkPoint fPoint;
2450 };
2451 
2452 class ParagraphView36 : public ParagraphView_Base {
2453 protected:
name()2454     SkString name() override { return SkString("Paragraph36"); }
2455 
onDrawContent(SkCanvas * canvas)2456     void onDrawContent(SkCanvas* canvas) override {
2457 
2458         canvas->drawColor(SK_ColorWHITE);
2459 
2460         auto text = "其实就是要 English 却又无法预览 English 功能强大起来 English 了我觉得自己也 English 可以的时候我们";
2461         auto fontCollection = sk_make_sp<FontCollection>();
2462         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2463         fontCollection->enableFontFallback();
2464 
2465         ParagraphStyle paragraph_style;
2466         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2467         TextStyle text_style;
2468         text_style.setColor(SK_ColorBLACK);
2469         text_style.setFontFamilies({SkString("Roboto"), SkString("Noto Serif CJK JP")});
2470         text_style.setFontSize(10);
2471         builder.pushStyle(text_style);
2472         builder.addText(text);
2473         auto paragraph = builder.Build();
2474         paragraph->layout(width());
2475 
2476         auto res1 = paragraph->getRectsForRange(63, 64, RectHeightStyle::kTight, RectWidthStyle::kTight);
2477         auto rect = res1[0].rect;
2478         auto res2 = paragraph->getGlyphPositionAtCoordinate(rect.fLeft + rect.width() / 2, rect.height());
2479         auto res3 = paragraph->getWordBoundary(res2.position);
2480         SkDebugf("[%d:%d)\n", res3.start, res3.end);
2481 
2482         paragraph->paint(canvas, 0, 0);
2483     }
2484 
2485 private:
2486     typedef Sample INHERITED;
2487 };
2488 
2489 class ParagraphView37 : public ParagraphView_Base {
2490 protected:
name()2491     SkString name() override { return SkString("Paragraph37"); }
2492 
onDrawContent(SkCanvas * canvas)2493     void onDrawContent(SkCanvas* canvas) override {
2494         const char* text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaয়ৠঝোণ৺ঢ়মৈবৗৗঘথফড়৭২খসঢ়ৃঢ়ঁ৷থডঈঽলবনদ২ৢৃঀজঝ৩ঠ৪৫৯০ঌয়্মওৗ৲গখদ৹ঈ৴৹ঢ়ৄএৡফণহলঈ৲থজোৱে ঀকৰঀষজঝঃাখশঽএমংি";
2495                 //"ৎৣ়ৎঽতঃ৳্ৱব৴ৣঈ৷ূঁঢঢ়শটডৎ৵৵ৰৃ্দংঊাথৗদঊউদ৯ঐৃধা৬হওধি়৭ঽম৯স০ঢফৈঢ়কষঁছফীআে৶ৰ৶ঌৌঊ্ঊঝএঀঃদঞ৮তব৬ৄঊঙঢ়ৡগ৶৹৹ঌড়ঘৄ৷লপ১ভড়৶েঢ়৯ৎকনংট২ংএঢৌৌঐনো০টঽুৠগআ৷৭৩৬তো৻ঈ০ূসষঅঝআমণঔা১ণৈো৵চঽ৩বমৎঙঘ২ঠৠৈী৫তঌণচ৲ঔী৮ঘৰঔ";
2496          canvas->drawColor(SK_ColorWHITE);
2497 
2498         auto fontCollection = sk_make_sp<FontCollection>();
2499         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
2500         fontCollection->enableFontFallback();
2501 
2502         ParagraphStyle paragraph_style;
2503         ParagraphBuilderImpl builder(paragraph_style, fontCollection);
2504         TextStyle text_style;
2505         text_style.setColor(SK_ColorBLACK);
2506         text_style.setFontFamilies({SkString("Roboto")});
2507         text_style.setFontSize(20);
2508         builder.pushStyle(text_style);
2509         builder.addText(text);
2510         auto paragraph = builder.Build();
2511         auto w = width() / 2;
2512         paragraph->layout(w);
2513         auto impl = static_cast<ParagraphImpl*>(paragraph.get());
2514 
2515         auto clusters = impl->clusters();
2516         size_t c = 0;
2517         SkDebugf("clusters\n");
2518         for (auto& cluster: clusters) {
2519           SkDebugf(""
2520                    "%d: [%d:%d) %s\n", c++,
2521               cluster.textRange().start, cluster.textRange().end,
2522               cluster.isSoftBreak() ? "soft" :
2523                 cluster.isHardBreak() ? "hard" :
2524                   cluster.isWhitespaces() ? "spaces" : ""
2525               );
2526         }
2527         auto lines = impl->lines();
2528         size_t i = 0;
2529         SkDebugf("lines\n");
2530         for (auto& line : lines) {
2531           SkDebugf("%d: [%d:%d)\n", i++, line.trimmedText().start, line.trimmedText().end);
2532         }
2533 
2534         paragraph->paint(canvas, 0, 0);
2535     }
2536 
2537 private:
2538     typedef Sample INHERITED;
2539 };
2540 
2541 //////////////////////////////////////////////////////////////////////////////
2542 DEF_SAMPLE(return new ParagraphView1();)
2543 DEF_SAMPLE(return new ParagraphView2();)
2544 DEF_SAMPLE(return new ParagraphView3();)
2545 DEF_SAMPLE(return new ParagraphView4();)
2546 DEF_SAMPLE(return new ParagraphView5();)
2547 DEF_SAMPLE(return new ParagraphView6();)
2548 DEF_SAMPLE(return new ParagraphView7();)
2549 DEF_SAMPLE(return new ParagraphView8();)
2550 DEF_SAMPLE(return new ParagraphView9();)
2551 DEF_SAMPLE(return new ParagraphView10();)
2552 DEF_SAMPLE(return new ParagraphView11();)
2553 DEF_SAMPLE(return new ParagraphView12();)
2554 DEF_SAMPLE(return new ParagraphView14();)
2555 DEF_SAMPLE(return new ParagraphView15();)
2556 DEF_SAMPLE(return new ParagraphView16();)
2557 DEF_SAMPLE(return new ParagraphView17();)
2558 DEF_SAMPLE(return new ParagraphView18();)
2559 DEF_SAMPLE(return new ParagraphView19();)
2560 DEF_SAMPLE(return new ParagraphView20();)
2561 DEF_SAMPLE(return new ParagraphView21();)
2562 DEF_SAMPLE(return new ParagraphView22();)
2563 DEF_SAMPLE(return new ParagraphView23();)
2564 DEF_SAMPLE(return new ParagraphView24();)
2565 DEF_SAMPLE(return new ParagraphView25();)
2566 DEF_SAMPLE(return new ParagraphView26();)
2567 DEF_SAMPLE(return new ParagraphView27();)
2568 DEF_SAMPLE(return new ParagraphView28();)
2569 DEF_SAMPLE(return new ParagraphView29();)
2570 DEF_SAMPLE(return new ParagraphView30();)
2571 DEF_SAMPLE(return new ParagraphView31();)
2572 DEF_SAMPLE(return new ParagraphView32();)
2573 DEF_SAMPLE(return new ParagraphView33();)
2574 DEF_SAMPLE(return new ParagraphView34();)
2575 DEF_SAMPLE(return new ParagraphView35();)
2576 DEF_SAMPLE(return new ParagraphView36();)
2577 DEF_SAMPLE(return new ParagraphView37();)
2578