• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 #include "include/core/SkCanvas.h"
3 #include "include/core/SkColorFilter.h"
4 #include "include/core/SkColorPriv.h"
5 #include "include/core/SkGraphics.h"
6 #include "include/core/SkPath.h"
7 #include "include/core/SkRegion.h"
8 #include "include/core/SkShader.h"
9 #include "include/core/SkStream.h"
10 #include "include/core/SkTextBlob.h"
11 #include "include/core/SkTime.h"
12 #include "include/core/SkTypeface.h"
13 #include "include/effects/SkBlurMaskFilter.h"
14 #include "include/effects/SkGradientShader.h"
15 #include "include/utils/SkRandom.h"
16 #include "modules/skparagraph/include/Paragraph.h"
17 #include "modules/skparagraph/include/TypefaceFontProvider.h"
18 #include "modules/skparagraph/src/ParagraphBuilderImpl.h"
19 #include "modules/skparagraph/src/ParagraphImpl.h"
20 #include "modules/skparagraph/utils/TestFontCollection.h"
21 #include "samplecode/Sample.h"
22 #include "src/core/SkOSFile.h"
23 #include "src/shaders/SkColorShader.h"
24 #include "src/utils/SkUTF.h"
25 #include "tools/Resources.h"
26 
27 using namespace skia::textlayout;
28 namespace {
29 
30 class ParagraphView_Base : public Sample {
31 protected:
getFontCollection()32     sk_sp<TestFontCollection> getFontCollection() {
33         // If we reset font collection we need to reset paragraph cache
34         static sk_sp<TestFontCollection> fFC = nullptr;
35         if (fFC == nullptr) {
36             fFC = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str());
37         }
38         return fFC;
39     }
40 };
41 
setgrad(const SkRect & r,SkColor c0,SkColor c1)42 sk_sp<SkShader> setgrad(const SkRect& r, SkColor c0, SkColor c1) {
43     SkColor colors[] = {c0, c1};
44     SkPoint pts[] = {{r.fLeft, r.fTop}, {r.fRight, r.fTop}};
45     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
46 }
47 
48 const char* gText =
49         "This is a very long sentence to test if the text will properly wrap "
50         "around and go to the next line. Sometimes, short sentence. Longer "
51         "sentences are okay too because they are nessecary. Very short. "
52         "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
53         "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
54         "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
55         "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
56         "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
57         "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
58         "mollit anim id est laborum. "
59         "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
60         "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
61         "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
62         "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
63         "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
64         "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
65         "mollit anim id est laborum.";
66 
67 }  // namespace
68 
69 class ParagraphView1 : public ParagraphView_Base {
70 protected:
name()71     SkString name() override { return SkString("Paragraph1"); }
72 
drawTest(SkCanvas * canvas,SkScalar w,SkScalar h,SkColor fg,SkColor bg)73     void drawTest(SkCanvas* canvas, SkScalar w, SkScalar h, SkColor fg, SkColor bg) {
74         const std::vector<
75             std::tuple<std::string, bool, bool, int, SkColor, SkColor, bool, TextDecorationStyle>>
76             gParagraph = {{"monospace", true, false, 14, SK_ColorWHITE, SK_ColorRED, true,
77                            TextDecorationStyle::kDashed},
78                           {"Assyrian", false, false, 20, SK_ColorWHITE, SK_ColorBLUE, false,
79                            TextDecorationStyle::kDotted},
80                           {"serif", true, true, 10, SK_ColorWHITE, SK_ColorRED, true,
81                            TextDecorationStyle::kDouble},
82                           {"Arial", false, true, 16, SK_ColorGRAY, SK_ColorGREEN, true,
83                            TextDecorationStyle::kSolid},
84                           {"sans-serif", false, false, 8, SK_ColorWHITE, SK_ColorRED, false,
85                            TextDecorationStyle::kWavy}};
86         SkAutoCanvasRestore acr(canvas, true);
87 
88         canvas->clipRect(SkRect::MakeWH(w, h));
89         canvas->drawColor(SK_ColorWHITE);
90 
91         SkScalar margin = 20;
92 
93         SkPaint paint;
94         paint.setAntiAlias(true);
95         paint.setColor(fg);
96 
97         SkPaint blue;
98         blue.setColor(SK_ColorBLUE);
99 
100         TextStyle defaultStyle;
101         defaultStyle.setBackgroundColor(blue);
102         defaultStyle.setForegroundColor(paint);
103         ParagraphStyle paraStyle;
104 
105         auto fontCollection = sk_make_sp<FontCollection>();
106         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
107         for (auto i = 1; i < 5; ++i) {
108             defaultStyle.setFontSize(24 * i);
109             paraStyle.setTextStyle(defaultStyle);
110             ParagraphBuilderImpl builder(paraStyle, fontCollection);
111             std::string name = "Paragraph: " + std::to_string(24 * i);
112             builder.addText(name.c_str());
113             for (auto para : gParagraph) {
114                 TextStyle style;
115                 style.setFontFamilies({SkString(std::get<0>(para).c_str())});
116                 SkFontStyle fontStyle(std::get<1>(para) ? SkFontStyle::Weight::kBold_Weight
117                                                         : SkFontStyle::Weight::kNormal_Weight,
118                                       SkFontStyle::Width::kNormal_Width,
119                                       std::get<2>(para) ? SkFontStyle::Slant::kItalic_Slant
120                                                         : SkFontStyle::Slant::kUpright_Slant);
121                 style.setFontStyle(fontStyle);
122                 style.setFontSize(std::get<3>(para) * i);
123                 SkPaint background;
124                 background.setColor(std::get<4>(para));
125                 style.setBackgroundColor(background);
126                 SkPaint foreground;
127                 foreground.setColor(std::get<5>(para));
128                 foreground.setAntiAlias(true);
129                 style.setForegroundColor(foreground);
130                 if (std::get<6>(para)) {
131                     style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(5, 5), 2));
132                 }
133 
134                 auto decoration = (i % 4);
135                 if (decoration == 3) {
136                     decoration = 4;
137                 }
138 
139                 bool test = (TextDecoration)decoration != TextDecoration::kNoDecoration;
140                 std::string deco = std::to_string((int)decoration);
141                 if (test) {
142                     style.setDecoration((TextDecoration)decoration);
143                     style.setDecorationStyle(std::get<7>(para));
144                     style.setDecorationColor(std::get<5>(para));
145                 }
146                 builder.pushStyle(style);
147                 std::string name = " " + std::get<0>(para) + " " +
148                                    (std::get<1>(para) ? ", bold" : "") +
149                                    (std::get<2>(para) ? ", italic" : "") + " " +
150                                    std::to_string(std::get<3>(para) * i) +
151                                    (std::get<4>(para) != bg ? ", background" : "") +
152                                    (std::get<5>(para) != fg ? ", foreground" : "") +
153                                    (std::get<6>(para) ? ", shadow" : "") +
154                                    (test ? ", decorations " + deco : "") + ";";
155                 builder.addText(name.c_str());
156                 builder.pop();
157             }
158 
159             auto paragraph = builder.Build();
160             paragraph->layout(w - margin * 2);
161             paragraph->paint(canvas, margin, margin);
162 
163             canvas->translate(0, paragraph->getHeight());
164         }
165     }
166 
onDrawContent(SkCanvas * canvas)167     void onDrawContent(SkCanvas* canvas) override {
168         drawTest(canvas, this->width(), this->height(), SK_ColorRED, SK_ColorWHITE);
169     }
170 
171 private:
172 
173     typedef Sample INHERITED;
174 };
175 
176 class ParagraphView2 : public ParagraphView_Base {
177 protected:
name()178     SkString name() override { return SkString("Paragraph2"); }
179 
drawCode(SkCanvas * canvas,SkScalar w,SkScalar h)180     void drawCode(SkCanvas* canvas, SkScalar w, SkScalar h) {
181         SkPaint comment;
182         comment.setColor(SK_ColorGRAY);
183         SkPaint constant;
184         constant.setColor(SK_ColorMAGENTA);
185         SkPaint null;
186         null.setColor(SK_ColorMAGENTA);
187         SkPaint literal;
188         literal.setColor(SK_ColorGREEN);
189         SkPaint code;
190         code.setColor(SK_ColorDKGRAY);
191         SkPaint number;
192         number.setColor(SK_ColorBLUE);
193         SkPaint name;
194         name.setColor(SK_ColorRED);
195 
196         SkPaint white;
197         white.setColor(SK_ColorWHITE);
198 
199         TextStyle defaultStyle;
200         defaultStyle.setBackgroundColor(white);
201         defaultStyle.setForegroundColor(code);
202         defaultStyle.setFontFamilies({SkString("monospace")});
203         defaultStyle.setFontSize(30);
204         ParagraphStyle paraStyle;
205         paraStyle.setTextStyle(defaultStyle);
206 
207         auto fontCollection = sk_make_sp<FontCollection>();
208         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
209         ParagraphBuilderImpl builder(paraStyle, fontCollection);
210 
211         builder.pushStyle(style(name));
212         builder.addText("RaisedButton");
213         builder.pop();
214         builder.addText("(\n");
215         builder.addText("  child: ");
216         builder.pushStyle(style(constant));
217         builder.addText("const");
218         builder.pop();
219         builder.addText(" ");
220         builder.pushStyle(style(name));
221         builder.addText("Text");
222         builder.pop();
223         builder.addText("(");
224         builder.pushStyle(style(literal));
225         builder.addText("'BUTTON TITLE'");
226         builder.pop();
227         builder.addText("),\n");
228 
229         auto paragraph = builder.Build();
230         paragraph->layout(w - 20);
231 
232         paragraph->paint(canvas, 20, 20);
233     }
234 
style(SkPaint paint)235     TextStyle style(SkPaint paint) {
236         TextStyle style;
237         paint.setAntiAlias(true);
238         style.setForegroundColor(paint);
239         style.setFontFamilies({SkString("monospace")});
240         style.setFontSize(30);
241 
242         return style;
243     }
244 
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")245     void drawText(SkCanvas* canvas, SkScalar w, SkScalar h, std::vector<const char*>& text,
246                   SkColor fg = SK_ColorDKGRAY, SkColor bg = SK_ColorWHITE,
247                   const char* ff = "sans-serif", SkScalar fs = 24,
248                   size_t lineLimit = 30,
249                   const std::u16string& ellipsis = u"\u2026") {
250         SkAutoCanvasRestore acr(canvas, true);
251 
252         canvas->clipRect(SkRect::MakeWH(w, h));
253         canvas->drawColor(bg);
254 
255         SkScalar margin = 20;
256 
257         SkPaint paint;
258         paint.setAntiAlias(true);
259         paint.setColor(fg);
260 
261         SkPaint blue;
262         blue.setColor(SK_ColorBLUE);
263 
264         SkPaint background;
265         background.setColor(bg);
266 
267         TextStyle style;
268         style.setBackgroundColor(blue);
269         style.setForegroundColor(paint);
270         style.setFontFamilies({SkString(ff)});
271         style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight,
272                                        SkFontStyle::kNormal_Width,
273                                        SkFontStyle::kUpright_Slant));
274         style.setFontSize(fs);
275         ParagraphStyle paraStyle;
276         paraStyle.setTextStyle(style);
277         paraStyle.setMaxLines(lineLimit);
278 
279         paraStyle.setEllipsis(ellipsis);
280         TextStyle defaultStyle;
281         defaultStyle.setFontSize(20);
282         paraStyle.setTextStyle(defaultStyle);
283         ParagraphBuilderImpl builder(paraStyle, getFontCollection());
284 
285         SkPaint foreground;
286         foreground.setColor(fg);
287         style.setForegroundColor(foreground);
288         style.setBackgroundColor(background);
289 
290         for (auto& part : text) {
291             builder.pushStyle(style);
292             builder.addText(part);
293             builder.pop();
294         }
295 
296         auto paragraph = builder.Build();
297         paragraph->layout(w - margin * 2);
298         paragraph->paint(canvas, margin, margin);
299 
300         canvas->translate(0, paragraph->getHeight() + margin);
301     }
302 
drawLine(SkCanvas * canvas,SkScalar w,SkScalar h,const std::string & text,TextAlign align)303     void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
304                   TextAlign align) {
305         SkAutoCanvasRestore acr(canvas, true);
306 
307         canvas->clipRect(SkRect::MakeWH(w, h));
308         canvas->drawColor(SK_ColorWHITE);
309 
310         SkScalar margin = 20;
311 
312         SkPaint paint;
313         paint.setAntiAlias(true);
314         paint.setColor(SK_ColorBLUE);
315 
316         SkPaint gray;
317         gray.setColor(SK_ColorLTGRAY);
318 
319         TextStyle style;
320         style.setBackgroundColor(gray);
321         style.setForegroundColor(paint);
322         style.setFontFamilies({SkString("Arial")});
323         style.setFontSize(30);
324         ParagraphStyle paraStyle;
325         paraStyle.setTextStyle(style);
326         paraStyle.setTextAlign(align);
327 
328         auto fontCollection = sk_make_sp<FontCollection>();
329         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
330         ParagraphBuilderImpl builder(paraStyle, fontCollection);
331         builder.addText(text.c_str());
332 
333         auto paragraph = builder.Build();
334         paragraph->layout(w - margin * 2);
335         paragraph->layout(w - margin);
336         paragraph->paint(canvas, margin, margin);
337 
338         canvas->translate(0, paragraph->getHeight() + margin);
339     }
340 
onDrawContent(SkCanvas * canvas)341     void onDrawContent(SkCanvas* canvas) override {
342         std::vector<const char*> cupertino = {
343                 "google_logogoogle_gsuper_g_logo 1 "
344                 "google_logogoogle_gsuper_g_logo 12 "
345                 "google_logogoogle_gsuper_g_logo 123 "
346                 "google_logogoogle_gsuper_g_logo 1234 "
347                 "google_logogoogle_gsuper_g_logo 12345 "
348                 "google_logogoogle_gsuper_g_logo 123456 "
349                 "google_logogoogle_gsuper_g_logo 1234567 "
350                 "google_logogoogle_gsuper_g_logo 12345678 "
351                 "google_logogoogle_gsuper_g_logo 123456789 "
352                 "google_logogoogle_gsuper_g_logo 1234567890 "
353                 "google_logogoogle_gsuper_g_logo 123456789 "
354                 "google_logogoogle_gsuper_g_logo 12345678 "
355                 "google_logogoogle_gsuper_g_logo 1234567 "
356                 "google_logogoogle_gsuper_g_logo 123456 "
357                 "google_logogoogle_gsuper_g_logo 12345 "
358                 "google_logogoogle_gsuper_g_logo 1234 "
359                 "google_logogoogle_gsuper_g_logo 123 "
360                 "google_logogoogle_gsuper_g_logo 12 "
361                 "google_logogoogle_gsuper_g_logo 1 "
362                 "google_logogoogle_gsuper_g_logo "
363                 "google_logogoogle_gsuper_g_logo "
364                 "google_logogoogle_gsuper_g_logo "
365                 "google_logogoogle_gsuper_g_logo "
366                 "google_logogoogle_gsuper_g_logo "
367                 "google_logogoogle_gsuper_g_logo"};
368         std::vector<const char*> text = {
369                 "My neighbor came over to say,\n"
370                 "Although not in a neighborly way,\n\n"
371                 "That he'd knock me around,\n\n\n"
372                 "If I didn't stop the sound,\n\n\n\n"
373                 "Of the classical music I play."};
374 
375         std::vector<const char*> long_word = {
376                 "A_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
377                 "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
378                 "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
379                 "very_very_very_very_very_very_very_long_text"};
380 
381         std::vector<const char*> very_long = {
382                 "A very very very very very very very very very very very very very very very very "
383                 "very very very very very very very very very very very very very very very very "
384                 "very very very very very very very very very very very very very very very very "
385                 "very very very very very very very long text"};
386 
387         std::vector<const char*> very_word = {
388                 "A very_very_very_very_very_very_very_very_very_very "
389                 "very_very_very_very_very_very_very_very_very_very very very very very very very "
390                 "very very very very very very very very very very very very very very very very "
391                 "very very very very very very very very very very very very very long text"};
392 
393         SkScalar width = this->width() / 5;
394         SkScalar height = this->height();
395         drawText(canvas, width, height, long_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
396         canvas->translate(width, 0);
397         drawText(canvas, width, height, very_long, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
398         canvas->translate(width, 0);
399         drawText(canvas, width, height, very_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
400         canvas->translate(width, 0);
401 
402         drawText(canvas, width, height / 2, text, SK_ColorBLACK, SK_ColorWHITE, "Roboto", 20, 100,
403                  u"\u2026");
404         canvas->translate(0, height / 2);
405         drawCode(canvas, width, height / 2);
406         canvas->translate(width, -height / 2);
407 
408         drawText(canvas, width, height, cupertino, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
409     }
410 
411 private:
412     typedef Sample INHERITED;
413 };
414 
415 class ParagraphView3 : public ParagraphView_Base {
416 protected:
name()417     SkString name() override { return SkString("Paragraph3"); }
418 
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")419     void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
420                   TextAlign align, size_t lineLimit = std::numeric_limits<size_t>::max(),
421                   bool RTL = false, SkColor background = SK_ColorGRAY,
422                   const std::u16string& ellipsis = u"\u2026") {
423         SkAutoCanvasRestore acr(canvas, true);
424 
425         canvas->clipRect(SkRect::MakeWH(w, h));
426         canvas->drawColor(SK_ColorWHITE);
427 
428         SkScalar margin = 20;
429 
430         SkPaint paint;
431         paint.setAntiAlias(true);
432         paint.setColor(SK_ColorBLACK);
433 
434         SkPaint gray;
435         gray.setColor(background);
436 
437         SkPaint yellow;
438         yellow.setColor(SK_ColorYELLOW);
439 
440         TextStyle style;
441         style.setBackgroundColor(gray);
442         style.setForegroundColor(paint);
443         style.setFontFamilies({SkString("sans-serif")});
444         style.setFontSize(30);
445         ParagraphStyle paraStyle;
446         paraStyle.setTextStyle(style);
447         paraStyle.setTextAlign(align);
448         paraStyle.setMaxLines(lineLimit);
449         paraStyle.setEllipsis(ellipsis);
450         // paraStyle.setTextDirection(RTL ? SkTextDirection::rtl : SkTextDirection::ltr);
451 
452         auto fontCollection = sk_make_sp<FontCollection>();
453         fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
454         ParagraphBuilderImpl builder(paraStyle, fontCollection);
455         if (RTL) {
456             builder.addText(mirror(text));
457         } else {
458             builder.addText(normal(text));
459         }
460 
461         canvas->drawRect(SkRect::MakeXYWH(margin, margin, w - margin * 2, h - margin * 2), yellow);
462         auto paragraph = builder.Build();
463         paragraph->layout(w - margin * 2);
464         paragraph->paint(canvas, margin, margin);
465     }
466 
mirror(const std::string & text)467     std::u16string mirror(const std::string& text) {
468         std::u16string result;
469         result += u"\u202E";
470         // for (auto i = text.size(); i > 0; --i) {
471         //  result += text[i - 1];
472         //}
473 
474         for (auto i = text.size(); i > 0; --i) {
475             auto ch = text[i - 1];
476             if (ch == ',') {
477                 result += u"!";
478             } else if (ch == '.') {
479                 result += u"!";
480             } else {
481                 result += ch;
482             }
483         }
484 
485         result += u"\u202C";
486         return result;
487     }
488 
normal(const std::string & text)489     std::u16string normal(const std::string& text) {
490         std::u16string result;
491         result += u"\u202D";
492         for (auto ch : text) {
493             result += ch;
494         }
495         result += u"\u202C";
496         return result;
497     }
498 
onDrawContent(SkCanvas * canvas)499     void onDrawContent(SkCanvas* canvas) override {
500         const std::string options =  // { "open-source open-source open-source open-source" };
501                 {"Flutter is an open-source project to help developers "
502                  "build high-performance, high-fidelity, mobile apps for "
503                  "iOS and Android "
504                  "from a single codebase. This design lab is a playground "
505                  "and showcase of Flutter's many widgets, behaviors, "
506                  "animations, layouts, and more."};
507 
508         canvas->drawColor(SK_ColorDKGRAY);
509         SkScalar width = this->width() / 4;
510         SkScalar height = this->height() / 2;
511 
512         const std::string line =
513                 "World domination is such an ugly phrase - I prefer to call it world optimisation";
514 
515         drawLine(canvas, width, height, line, TextAlign::kLeft, 1, false, SK_ColorLTGRAY);
516         canvas->translate(width, 0);
517         drawLine(canvas, width, height, line, TextAlign::kRight, 2, false, SK_ColorLTGRAY);
518         canvas->translate(width, 0);
519         drawLine(canvas, width, height, line, TextAlign::kCenter, 3, false, SK_ColorLTGRAY);
520         canvas->translate(width, 0);
521         drawLine(canvas, width, height, line, TextAlign::kJustify, 4, false, SK_ColorLTGRAY);
522         canvas->translate(-width * 3, height);
523 
524         drawLine(canvas, width, height, line, TextAlign::kLeft, 1, true, SK_ColorLTGRAY);
525         canvas->translate(width, 0);
526         drawLine(canvas, width, height, line, TextAlign::kRight, 2, true, SK_ColorLTGRAY);
527         canvas->translate(width, 0);
528         drawLine(canvas, width, height, line, TextAlign::kCenter, 3, true, SK_ColorLTGRAY);
529         canvas->translate(width, 0);
530         drawLine(canvas, width, height, line, TextAlign::kJustify, 4, true, SK_ColorLTGRAY);
531         canvas->translate(width, 0);
532     }
533 
534 private:
535     typedef Sample INHERITED;
536 };
537 
538 class ParagraphView4 : public ParagraphView_Base {
539 protected:
name()540     SkString name() override { return SkString("Paragraph4"); }
541 
drawFlutter(SkCanvas * canvas,SkScalar w,SkScalar h,const char * ff="Google Sans",SkScalar fs=30,size_t lineLimit=std::numeric_limits<size_t>::max (),const std::u16string & ellipsis=u"\\u2026")542     void drawFlutter(SkCanvas* canvas, SkScalar w, SkScalar h,
543                      const char* ff = "Google Sans", SkScalar fs = 30,
544                      size_t lineLimit = std::numeric_limits<size_t>::max(),
545                      const std::u16string& ellipsis = u"\u2026") {
546         SkAutoCanvasRestore acr(canvas, true);
547 
548         canvas->clipRect(SkRect::MakeWH(w, h));
549 
550         SkScalar margin = 20;
551 
552         SkPaint black;
553         black.setAntiAlias(true);
554         black.setColor(SK_ColorBLACK);
555 
556         SkPaint blue;
557         blue.setAntiAlias(true);
558         blue.setColor(SK_ColorBLUE);
559 
560         SkPaint red;
561         red.setAntiAlias(true);
562         red.setColor(SK_ColorRED);
563 
564         SkPaint green;
565         green.setAntiAlias(true);
566         green.setColor(SK_ColorGREEN);
567 
568         SkPaint gray;
569         gray.setColor(SK_ColorLTGRAY);
570 
571         SkPaint yellow;
572         yellow.setColor(SK_ColorYELLOW);
573 
574         SkPaint magenta;
575         magenta.setAntiAlias(true);
576         magenta.setColor(SK_ColorMAGENTA);
577 
578         TextStyle style;
579         style.setFontFamilies({SkString(ff)});
580         style.setFontSize(fs);
581 
582         TextStyle style0;
583         style0.setForegroundColor(black);
584         style0.setBackgroundColor(gray);
585         style0.setFontFamilies({SkString(ff)});
586         style0.setFontSize(fs);
587         style0.setDecoration(TextDecoration::kUnderline);
588         style0.setDecorationStyle(TextDecorationStyle::kDouble);
589         style0.setDecorationColor(SK_ColorBLACK);
590 
591         TextStyle style1;
592         style1.setForegroundColor(blue);
593         style1.setBackgroundColor(yellow);
594         style1.setFontFamilies({SkString(ff)});
595         style1.setFontSize(fs);
596         style1.setDecoration(TextDecoration::kOverline);
597         style1.setDecorationStyle(TextDecorationStyle::kWavy);
598         style1.setDecorationColor(SK_ColorBLACK);
599 
600         TextStyle style2;
601         style2.setForegroundColor(red);
602         style2.setFontFamilies({SkString(ff)});
603         style2.setFontSize(fs);
604 
605         TextStyle style3;
606         style3.setForegroundColor(green);
607         style3.setFontFamilies({SkString(ff)});
608         style3.setFontSize(fs);
609 
610         TextStyle style4;
611         style4.setForegroundColor(magenta);
612         style4.setFontFamilies({SkString(ff)});
613         style4.setFontSize(fs);
614 
615         ParagraphStyle paraStyle;
616         paraStyle.setTextStyle(style);
617         paraStyle.setMaxLines(lineLimit);
618 
619         paraStyle.setEllipsis(ellipsis);
620 
621         const char* logo1 = "google_";
622         const char* logo2 = "logo";
623         const char* logo3 = "go";
624         const char* logo4 = "ogle_logo";
625         const char* logo5 = "google_lo";
626         const char* logo6 = "go";
627         {
628             ParagraphBuilderImpl builder(paraStyle, getFontCollection());
629 
630             builder.pushStyle(style0);
631             builder.addText(logo1);
632             builder.pop();
633             builder.pushStyle(style1);
634             builder.addText(logo2);
635             builder.pop();
636 
637             builder.addText(" ");
638 
639             builder.pushStyle(style0);
640             builder.addText(logo3);
641             builder.pop();
642             builder.pushStyle(style1);
643             builder.addText(logo4);
644             builder.pop();
645 
646             builder.addText(" ");
647 
648             builder.pushStyle(style0);
649             builder.addText(logo5);
650             builder.pop();
651             builder.pushStyle(style1);
652             builder.addText(logo6);
653             builder.pop();
654 
655             auto paragraph = builder.Build();
656             paragraph->layout(w - margin * 2);
657             paragraph->paint(canvas, margin, margin);
658             canvas->translate(0, h + margin);
659         }
660     }
661 
onDrawContent(SkCanvas * canvas)662     void onDrawContent(SkCanvas* canvas) override {
663         canvas->drawColor(SK_ColorWHITE);
664         SkScalar width = this->width();
665         SkScalar height = this->height();
666 
667         drawFlutter(canvas, width, height / 2);
668     }
669 
670 private:
671     typedef Sample INHERITED;
672 };
673 
674 class ParagraphView5 : public ParagraphView_Base {
675 protected:
name()676     SkString name() override { return SkString("Paragraph5"); }
677 
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")678     void bidi(SkCanvas* canvas, SkScalar w, SkScalar h, const std::u16string& text,
679               const std::u16string& expected, size_t lineLimit = std::numeric_limits<size_t>::max(),
680               const char* ff = "Roboto", SkScalar fs = 30,
681               const std::u16string& ellipsis = u"\u2026") {
682         SkAutoCanvasRestore acr(canvas, true);
683 
684         canvas->clipRect(SkRect::MakeWH(w, h));
685 
686         SkScalar margin = 20;
687 
688         SkPaint black;
689         black.setColor(SK_ColorBLACK);
690         SkPaint gray;
691         gray.setColor(SK_ColorLTGRAY);
692 
693         TextStyle style;
694         style.setForegroundColor(black);
695         style.setFontFamilies({SkString(ff)});
696         style.setFontSize(fs);
697 
698         TextStyle style0;
699         style0.setForegroundColor(black);
700         style0.setFontFamilies({SkString(ff)});
701         style0.setFontSize(fs);
702         style0.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
703                                         SkFontStyle::kItalic_Slant));
704 
705         TextStyle style1;
706         style1.setForegroundColor(gray);
707         style1.setFontFamilies({SkString(ff)});
708         style1.setFontSize(fs);
709         style1.setFontStyle(SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
710                                         SkFontStyle::kUpright_Slant));
711 
712         ParagraphStyle paraStyle;
713         paraStyle.setTextStyle(style);
714         paraStyle.setMaxLines(lineLimit);
715 
716         paraStyle.setEllipsis(ellipsis);
717 
718         ParagraphBuilderImpl builder(paraStyle, getFontCollection());
719 
720         if (text.empty()) {
721             const std::u16string text0 = u"\u202Dabc";
722             const std::u16string text1 = u"\u202EFED";
723             const std::u16string text2 = u"\u202Dghi";
724             const std::u16string text3 = u"\u202ELKJ";
725             const std::u16string text4 = u"\u202Dmno";
726             builder.pushStyle(style0);
727             builder.addText(text0);
728             builder.pop();
729             builder.pushStyle(style1);
730             builder.addText(text1);
731             builder.pop();
732             builder.pushStyle(style0);
733             builder.addText(text2);
734             builder.pop();
735             builder.pushStyle(style1);
736             builder.addText(text3);
737             builder.pop();
738             builder.pushStyle(style0);
739             builder.addText(text4);
740             builder.pop();
741         } else {
742             // icu::UnicodeString unicode((UChar*) text.data(), SkToS32(text.size()));
743             // std::string str;
744             // unicode.toUTF8String(str);
745             // SkDebugf("Text: %s\n", str.c_str());
746             builder.addText(text + expected);
747         }
748 
749         auto paragraph = builder.Build();
750         paragraph->layout(w - margin * 2);
751         paragraph->paint(canvas, margin, margin);
752     }
753 
onDrawContent(SkCanvas * canvas)754     void onDrawContent(SkCanvas* canvas) override {
755         canvas->drawColor(SK_ColorWHITE);
756         SkScalar width = this->width();
757         SkScalar height = this->height() / 8;
758 
759         const std::u16string text1 =
760                 u"A \u202ENAC\u202Cner, exceedingly \u202ENAC\u202Cny,\n"
761                 "One morning remarked to his granny:\n"
762                 "A \u202ENAC\u202Cner \u202ENAC\u202C \u202ENAC\u202C,\n"
763                 "Anything that he \u202ENAC\u202C,\n"
764                 "But a \u202ENAC\u202Cner \u202ENAC\u202C't \u202ENAC\u202C a \u202ENAC\u202C, "
765                 "\u202ENAC\u202C he?";
766         bidi(canvas, width, height * 3, text1, u"", 5);
767         canvas->translate(0, height * 3);
768 
769         bidi(canvas, width, height, u"\u2067DETALOSI\u2069", u"");
770         canvas->translate(0, height);
771 
772         bidi(canvas, width, height, u"\u202BDEDDEBME\u202C", u"");
773         canvas->translate(0, height);
774 
775         bidi(canvas, width, height, u"\u202EEDIRREVO\u202C", u"");
776         canvas->translate(0, height);
777 
778         bidi(canvas, width, height, u"\u200FTICILPMI\u200E", u"");
779         canvas->translate(0, height);
780 
781         bidi(canvas, width, height, u"123 456 7890 \u202EZYXWV UTS RQP ONM LKJ IHG FED CBA\u202C.",
782              u"", 2);
783         canvas->translate(0, height);
784 
785         // bidi(canvas, width, height, u"", u"");
786         // canvas->translate(0, height);
787     }
788 
789 private:
790     typedef Sample INHERITED;
791 };
792 
793 class ParagraphView6 : public ParagraphView_Base {
794 protected:
name()795     SkString name() override { return SkString("Paragraph6"); }
796 
hangingS(SkCanvas * canvas,SkScalar w,SkScalar h,SkScalar fs=60.0)797     void hangingS(SkCanvas* canvas, SkScalar w, SkScalar h, SkScalar fs = 60.0) {
798         auto ff = "HangingS";
799 
800         canvas->drawColor(SK_ColorLTGRAY);
801 
802         SkPaint black;
803         black.setAntiAlias(true);
804         black.setColor(SK_ColorBLACK);
805 
806         SkPaint blue;
807         blue.setAntiAlias(true);
808         blue.setColor(SK_ColorBLUE);
809 
810         SkPaint red;
811         red.setAntiAlias(true);
812         red.setColor(SK_ColorRED);
813 
814         SkPaint green;
815         green.setAntiAlias(true);
816         green.setColor(SK_ColorGREEN);
817 
818         SkPaint gray;
819         gray.setColor(SK_ColorCYAN);
820 
821         SkPaint yellow;
822         yellow.setColor(SK_ColorYELLOW);
823 
824         SkPaint magenta;
825         magenta.setAntiAlias(true);
826         magenta.setColor(SK_ColorMAGENTA);
827 
828         SkFontStyle fontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
829                               SkFontStyle::kItalic_Slant);
830 
831         TextStyle style;
832         style.setFontFamilies({SkString(ff)});
833         style.setFontSize(fs);
834         style.setFontStyle(fontStyle);
835 
836         TextStyle style0;
837         style0.setForegroundColor(black);
838         style0.setBackgroundColor(gray);
839         style0.setFontFamilies({SkString(ff)});
840         style0.setFontSize(fs);
841         style0.setFontStyle(fontStyle);
842 
843         TextStyle style1;
844         style1.setForegroundColor(blue);
845         style1.setBackgroundColor(yellow);
846         style1.setFontFamilies({SkString(ff)});
847         style1.setFontSize(fs);
848         style1.setFontStyle(fontStyle);
849 
850         TextStyle style2;
851         style2.setForegroundColor(red);
852         style2.setFontFamilies({SkString(ff)});
853         style2.setFontSize(fs);
854         style2.setFontStyle(fontStyle);
855 
856         TextStyle style3;
857         style3.setForegroundColor(green);
858         style3.setFontFamilies({SkString(ff)});
859         style3.setFontSize(fs);
860         style3.setFontStyle(fontStyle);
861 
862         TextStyle style4;
863         style4.setForegroundColor(magenta);
864         style4.setFontFamilies({SkString(ff)});
865         style4.setFontSize(fs);
866         style4.setFontStyle(fontStyle);
867 
868         ParagraphStyle paraStyle;
869         paraStyle.setTextStyle(style);
870 
871         const char* logo1 = "S";
872         const char* logo2 = "kia";
873         const char* logo3 = "Sk";
874         const char* logo4 = "ia";
875         const char* logo5 = "Ski";
876         const char* logo6 = "a";
877         {
878             ParagraphBuilderImpl builder(paraStyle, getFontCollection());
879 
880             builder.pushStyle(style0);
881             builder.addText(logo1);
882             builder.pop();
883             builder.pushStyle(style1);
884             builder.addText(logo2);
885             builder.pop();
886 
887             builder.addText("   ");
888 
889             builder.pushStyle(style0);
890             builder.addText(logo3);
891             builder.pop();
892             builder.pushStyle(style1);
893             builder.addText(logo4);
894             builder.pop();
895 
896             builder.addText("   ");
897 
898             builder.pushStyle(style0);
899             builder.addText(logo5);
900             builder.pop();
901             builder.pushStyle(style1);
902             builder.addText(logo6);
903             builder.pop();
904 
905             auto paragraph = builder.Build();
906             paragraph->layout(w);
907             paragraph->paint(canvas, 40, 40);
908             canvas->translate(0, h);
909         }
910 
911         const char* logo11 = "S";
912         const char* logo12 = "S";
913         const char* logo13 = "S";
914         const char* logo14 = "S";
915         const char* logo15 = "S";
916         const char* logo16 = "S";
917         {
918             ParagraphBuilderImpl builder(paraStyle, getFontCollection());
919 
920             builder.pushStyle(style0);
921             builder.addText(logo11);
922             builder.pop();
923             builder.pushStyle(style1);
924             builder.addText(logo12);
925             builder.pop();
926 
927             builder.addText("   ");
928 
929             builder.pushStyle(style0);
930             builder.addText(logo13);
931             builder.pop();
932             builder.pushStyle(style1);
933             builder.addText(logo14);
934             builder.pop();
935 
936             builder.addText("   ");
937 
938             builder.pushStyle(style0);
939             builder.addText(logo15);
940             builder.pop();
941             builder.pushStyle(style1);
942             builder.addText(logo16);
943             builder.pop();
944 
945             auto paragraph = builder.Build();
946             paragraph->layout(w);
947             paragraph->paint(canvas, 40, h);
948             canvas->translate(0, h);
949         }
950     }
951 
onDrawContent(SkCanvas * canvas)952     void onDrawContent(SkCanvas* canvas) override {
953         canvas->drawColor(SK_ColorWHITE);
954         SkScalar width = this->width();
955         SkScalar height = this->height() / 4;
956 
957         hangingS(canvas, width, height);
958     }
959 
960 private:
961     typedef Sample INHERITED;
962 };
963 
964 class ParagraphView7 : public ParagraphView_Base {
965 protected:
name()966     SkString name() override { return SkString("Paragraph7"); }
967 
drawText(SkCanvas * canvas,SkColor background,SkScalar letterSpace,SkScalar w,SkScalar h)968     void drawText(SkCanvas* canvas, SkColor background, SkScalar letterSpace, SkScalar w,
969                   SkScalar h) {
970         SkAutoCanvasRestore acr(canvas, true);
971         canvas->clipRect(SkRect::MakeWH(w, h));
972         canvas->drawColor(background);
973 
974         const char* line =
975                 "World domination is such an ugly phrase - I prefer to call it world optimisation.";
976 
977         ParagraphStyle paragraphStyle;
978         paragraphStyle.setTextAlign(TextAlign::kLeft);
979         paragraphStyle.setMaxLines(10);
980         paragraphStyle.turnHintingOff();
981         TextStyle textStyle;
982         textStyle.setFontFamilies({SkString("Roboto")});
983         textStyle.setFontSize(30);
984         textStyle.setLetterSpacing(letterSpace);
985         textStyle.setColor(SK_ColorBLACK);
986         textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
987                                            SkFontStyle::kUpright_Slant));
988 
989         ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
990         builder.pushStyle(textStyle);
991         builder.addText(line);
992         builder.pop();
993 
994         auto paragraph = builder.Build();
995         paragraph->layout(w - 20);
996         paragraph->paint(canvas, 10, 10);
997     }
998 
onDrawContent(SkCanvas * canvas)999     void onDrawContent(SkCanvas* canvas) override {
1000         canvas->drawColor(SK_ColorWHITE);
1001 
1002         auto h = this->height() / 4;
1003         auto w = this->width() / 2;
1004 
1005         drawText(canvas, SK_ColorGRAY, 1, w, h);
1006         canvas->translate(0, h);
1007 
1008         drawText(canvas, SK_ColorLTGRAY, 2, w, h);
1009         canvas->translate(0, h);
1010 
1011         drawText(canvas, SK_ColorCYAN, 3, w, h);
1012         canvas->translate(0, h);
1013 
1014         drawText(canvas, SK_ColorGRAY, 4, w, h);
1015         canvas->translate(w, -3 * h);
1016 
1017         drawText(canvas, SK_ColorYELLOW, 5, w, h);
1018         canvas->translate(0, h);
1019 
1020         drawText(canvas, SK_ColorGREEN, 10, w, h);
1021         canvas->translate(0, h);
1022 
1023         drawText(canvas, SK_ColorRED, 15, w, h);
1024         canvas->translate(0, h);
1025 
1026         drawText(canvas, SK_ColorBLUE, 20, w, h);
1027         canvas->translate(0, h);
1028     }
1029 
1030 private:
1031     typedef Sample INHERITED;
1032 };
1033 
1034 class ParagraphView8 : public ParagraphView_Base {
1035 protected:
name()1036     SkString name() override { return SkString("Paragraph8"); }
1037 
drawText(SkCanvas * canvas,SkColor background,SkScalar wordSpace,SkScalar w,SkScalar h)1038     void drawText(SkCanvas* canvas, SkColor background, SkScalar wordSpace, SkScalar w,
1039                   SkScalar h) {
1040         SkAutoCanvasRestore acr(canvas, true);
1041         canvas->clipRect(SkRect::MakeWH(w, h));
1042         canvas->drawColor(background);
1043 
1044         const char* line =
1045                 "World domination is such an ugly phrase - I prefer to call it world optimisation.";
1046 
1047         ParagraphStyle paragraphStyle;
1048         paragraphStyle.setTextAlign(TextAlign::kLeft);
1049         paragraphStyle.setMaxLines(10);
1050         paragraphStyle.turnHintingOff();
1051         TextStyle textStyle;
1052         textStyle.setFontFamilies({SkString("Roboto")});
1053         textStyle.setFontSize(30);
1054         textStyle.setWordSpacing(wordSpace);
1055         textStyle.setColor(SK_ColorBLACK);
1056         textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1057                                            SkFontStyle::kUpright_Slant));
1058 
1059         ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
1060         builder.pushStyle(textStyle);
1061         builder.addText(line);
1062         builder.pop();
1063 
1064         auto paragraph = builder.Build();
1065         paragraph->layout(w - 20);
1066         paragraph->paint(canvas, 10, 10);
1067     }
1068 
onDrawContent(SkCanvas * canvas)1069     void onDrawContent(SkCanvas* canvas) override {
1070         canvas->drawColor(SK_ColorWHITE);
1071 
1072         auto h = this->height() / 4;
1073         auto w = this->width() / 2;
1074 
1075         drawText(canvas, SK_ColorGRAY, 1, w, h);
1076         canvas->translate(0, h);
1077 
1078         drawText(canvas, SK_ColorLTGRAY, 2, w, h);
1079         canvas->translate(0, h);
1080 
1081         drawText(canvas, SK_ColorCYAN, 3, w, h);
1082         canvas->translate(0, h);
1083 
1084         drawText(canvas, SK_ColorGRAY, 4, w, h);
1085         canvas->translate(w, -3 * h);
1086 
1087         drawText(canvas, SK_ColorYELLOW, 5, w, h);
1088         canvas->translate(0, h);
1089 
1090         drawText(canvas, SK_ColorGREEN, 10, w, h);
1091         canvas->translate(0, h);
1092 
1093         drawText(canvas, SK_ColorRED, 15, w, h);
1094         canvas->translate(0, h);
1095 
1096         drawText(canvas, SK_ColorBLUE, 20, w, h);
1097         canvas->translate(0, h);
1098     }
1099 
1100 private:
1101     typedef Sample INHERITED;
1102 };
1103 
1104 class ParagraphView9 : public ParagraphView_Base {
1105 protected:
name()1106     SkString name() override { return SkString("Paragraph9"); }
1107 
onChar(SkUnichar uni)1108     bool onChar(SkUnichar uni) override {
1109             switch (uni) {
1110                 case 'w':
1111                     ++wordSpacing;
1112                     return true;
1113                 case 'q':
1114                     if (wordSpacing > 0) --wordSpacing;
1115                     return true;
1116                 case 'l':
1117                     ++letterSpacing;
1118                     return true;
1119                 case 'k':
1120                     if (letterSpacing > 0) --letterSpacing;
1121                     return true;
1122                 default:
1123                     break;
1124             }
1125             return false;
1126     }
1127 
drawText(SkCanvas * canvas,SkColor background,SkScalar w,SkScalar h)1128     void drawText(SkCanvas* canvas, SkColor background, SkScalar w, SkScalar h) {
1129         SkAutoCanvasRestore acr(canvas, true);
1130         canvas->clipRect(SkRect::MakeWH(w, h));
1131         canvas->drawColor(background);
1132 
1133         const char* text =
1134                 "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1135                 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
1136                 " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
1137 
1138         ParagraphStyle paragraphStyle;
1139         paragraphStyle.setTextAlign(TextAlign::kLeft);
1140         paragraphStyle.setMaxLines(10);
1141         paragraphStyle.turnHintingOff();
1142         TextStyle textStyle;
1143         textStyle.setFontFamilies({SkString("Roboto")});
1144         textStyle.setFontSize(50);
1145         textStyle.setHeight(1.3f);
1146         textStyle.setColor(SK_ColorBLACK);
1147         textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
1148                                            SkFontStyle::kUpright_Slant));
1149 
1150         ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
1151         builder.pushStyle(textStyle);
1152         builder.addText(text);
1153         builder.pop();
1154 
1155         auto paragraph = builder.Build();
1156         paragraph->layout(550);
1157 
1158         std::vector<size_t> sizes = {0, 1, 2, 8, 19, 21, 22, 30, 150};
1159 
1160         std::vector<size_t> colors = {SK_ColorBLUE, SK_ColorCYAN,  SK_ColorLTGRAY, SK_ColorGREEN,
1161                                       SK_ColorRED,  SK_ColorWHITE, SK_ColorYELLOW, SK_ColorMAGENTA};
1162 
1163         RectHeightStyle rect_height_style = RectHeightStyle::kTight;
1164         RectWidthStyle rect_width_style = RectWidthStyle::kTight;
1165 
1166         for (size_t i = 0; i < sizes.size() - 1; ++i) {
1167             size_t from = (i == 0 ? 0 : 1) + sizes[i];
1168             size_t to = sizes[i + 1];
1169             auto boxes = paragraph->getRectsForRange(from, to, rect_height_style, rect_width_style);
1170             if (boxes.empty()) {
1171                 continue;
1172             }
1173             for (auto& box : boxes) {
1174                 SkPaint paint;
1175                 paint.setColor(colors[i % colors.size()]);
1176                 paint.setShader(setgrad(box.rect, colors[i % colors.size()], SK_ColorWHITE));
1177                 canvas->drawRect(box.rect, paint);
1178             }
1179         }
1180 
1181         paragraph->paint(canvas, 0, 0);
1182     }
1183 
onDrawContent(SkCanvas * canvas)1184     void onDrawContent(SkCanvas* canvas) override {
1185         canvas->drawColor(SK_ColorWHITE);
1186 
1187         auto h = this->height();
1188         auto w = this->width();
1189 
1190         drawText(canvas, SK_ColorGRAY, w, h);
1191     }
1192 
1193 private:
1194     typedef Sample INHERITED;
1195     SkScalar letterSpacing;
1196     SkScalar wordSpacing;
1197 };
1198 
1199 class ParagraphView10 : public ParagraphView_Base {
1200 protected:
name()1201     SkString name() override { return SkString("Paragraph10"); }
1202 
onDrawContent(SkCanvas * canvas)1203     void onDrawContent(SkCanvas* canvas) override {
1204         canvas->drawColor(SK_ColorWHITE);
1205 
1206         const char* text = "English English 字典 字典 ������ ������";
1207         ParagraphStyle paragraph_style;
1208         paragraph_style.turnHintingOff();
1209         ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1210 
1211         TextStyle text_style;
1212         text_style.setFontFamilies({SkString("Roboto"),
1213                                     SkString("Noto Color Emoji"),
1214                                     SkString("Source Han Serif CN")});
1215         text_style.setColor(SK_ColorRED);
1216         text_style.setFontSize(60);
1217         text_style.setLetterSpacing(0);
1218         text_style.setWordSpacing(0);
1219         text_style.setColor(SK_ColorBLACK);
1220         text_style.setHeight(1);
1221         builder.pushStyle(text_style);
1222         builder.addText(text);
1223         builder.pop();
1224 
1225         auto paragraph = builder.Build();
1226         paragraph->layout(width());
1227 
1228         paragraph->paint(canvas, 0, 0);
1229         SkDEBUGCODE(auto impl = reinterpret_cast<ParagraphImpl*>(paragraph.get()));
1230         SkASSERT(impl->runs().size() == 3);
1231         SkASSERT(impl->runs()[0].textRange().end == impl->runs()[1].textRange().start);
1232         SkASSERT(impl->runs()[1].textRange().end == impl->runs()[2].textRange().start);
1233     }
1234 
1235 private:
1236     typedef Sample INHERITED;
1237 };
1238 
1239 class ParagraphView11 : public ParagraphView_Base {
1240 protected:
name()1241     SkString name() override { return SkString("Paragraph11"); }
1242 
onDrawContent(SkCanvas * canvas)1243     void onDrawContent(SkCanvas* canvas) override {
1244         canvas->drawColor(SK_ColorWHITE);
1245         const char* text = "The same text many times";
1246 
1247         for (size_t i = 0; i < 10; i++) {
1248             ParagraphStyle paragraph_style;
1249             ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1250             TextStyle text_style;
1251             text_style.setFontFamilies({SkString("Roboto")});
1252             text_style.setColor(SK_ColorBLACK);
1253             text_style.setFontSize(10 + 2 * (i % 10));
1254             builder.pushStyle(text_style);
1255             builder.addText(text);
1256             builder.pop();
1257             auto paragraph = builder.Build();
1258             paragraph->layout(500);
1259             paragraph->paint(canvas, 0, 40 * (i % 10));
1260         }
1261     }
1262 
1263 private:
1264     typedef Sample INHERITED;
1265 };
1266 
1267 // Measure different stages of layout/paint
1268 class ParagraphView12 : public ParagraphView_Base {
1269 protected:
name()1270     SkString name() override { return SkString("Paragraph12"); }
1271 
onDrawContent(SkCanvas * canvas)1272     void onDrawContent(SkCanvas* canvas) override {
1273         ParagraphStyle paragraph_style;
1274         paragraph_style.setMaxLines(14);
1275         paragraph_style.setTextAlign(TextAlign::kLeft);
1276         paragraph_style.turnHintingOff();
1277         ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
1278 
1279         TextStyle text_style;
1280         text_style.setFontFamilies({SkString("Roboto")});
1281         text_style.setFontSize(26);
1282         text_style.setColor(SK_ColorBLACK);
1283         text_style.setHeight(1);
1284         text_style.setDecoration(TextDecoration::kUnderline);
1285         text_style.setDecorationColor(SK_ColorBLACK);
1286         builder.pushStyle(text_style);
1287         builder.addText(gText);
1288         builder.pop();
1289 
1290         auto paragraph = builder.Build();
1291         auto impl = reinterpret_cast<ParagraphImpl*>(paragraph.get());
1292 
1293         for (auto i = 0; i < 1000; ++i) {
1294             impl->setState(kUnknown);
1295             impl->shapeTextIntoEndlessLine();
1296             impl->setState(kShaped);
1297         }
1298 
1299         for (auto i = 0; i < 1000; ++i) {
1300             impl->setState(kShaped);
1301             impl->buildClusterTable();
1302             impl->markLineBreaks();
1303             impl->setState(kMarked);
1304         }
1305 
1306         for (auto i = 0; i < 1000; ++i) {
1307             impl->setState(kMarked);
1308             impl->breakShapedTextIntoLines(1000);
1309             impl->setState(kLineBroken);
1310         }
1311 
1312         for (auto i = 0; i < 1000; ++i) {
1313             impl->setState(kLineBroken);
1314             impl->formatLines(1000);
1315             impl->setState(kFormatted);
1316         }
1317 
1318         for (auto i = 0; i < 1000; ++i) {
1319             impl->setState(kFormatted);
1320             impl->paintLinesIntoPicture();
1321             impl->setState(kDrawn);
1322         }
1323 
1324         auto picture = impl->getPicture();
1325         SkMatrix matrix = SkMatrix::MakeTrans(0, 0);
1326         for (auto i = 0; i < 1000; ++i) {
1327             canvas->drawPicture(picture, &matrix, nullptr);
1328         }
1329 
1330     }
1331 
1332 private:
1333     typedef Sample INHERITED;
1334 };
1335 //////////////////////////////////////////////////////////////////////////////
1336 
1337 DEF_SAMPLE(return new ParagraphView1();)
1338 DEF_SAMPLE(return new ParagraphView2();)
1339 DEF_SAMPLE(return new ParagraphView3();)
1340 DEF_SAMPLE(return new ParagraphView4();)
1341 DEF_SAMPLE(return new ParagraphView5();)
1342 DEF_SAMPLE(return new ParagraphView6();)
1343 DEF_SAMPLE(return new ParagraphView7();)
1344 DEF_SAMPLE(return new ParagraphView8();)
1345 DEF_SAMPLE(return new ParagraphView9();)
1346 DEF_SAMPLE(return new ParagraphView10();)
1347 DEF_SAMPLE(return new ParagraphView11();)
1348 DEF_SAMPLE(return new ParagraphView12();)
1349