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