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