1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "samplecode/Sample.h"
9 #include "tools/Resources.h"
10 #include "tools/ToolUtils.h"
11 
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkFontMetrics.h"
14 #include "include/core/SkFontMgr.h"
15 #include "include/core/SkTextBlob.h"
16 #include "include/core/SkTypeface.h"
17 #include "include/utils/SkRandom.h"
18 
19 #if SK_SUPPORT_GPU
20 #include "include/gpu/GrDirectContext.h"
21 #include "src/gpu/GrDirectContextPriv.h"
22 #endif
23 
chinese_typeface()24 static sk_sp<SkTypeface> chinese_typeface() {
25 #ifdef SK_BUILD_FOR_ANDROID
26     return MakeResourceAsTypeface("fonts/NotoSansCJK-Regular.ttc");
27 #elif defined(SK_BUILD_FOR_WIN)
28     return SkTypeface::MakeFromName("SimSun", SkFontStyle());
29 #elif defined(SK_BUILD_FOR_MAC)
30     return SkTypeface::MakeFromName("Hiragino Sans GB W3", SkFontStyle());
31 #elif defined(SK_BUILD_FOR_IOS)
32     return SkTypeface::MakeFromName("Hiragino Sans GB W3", SkFontStyle());
33 #elif defined(SK_BUILD_FOR_UNIX)
34     return SkTypeface::MakeFromName("Noto Sans CJK SC", SkFontStyle());
35 #else
36     return nullptr;
37 #endif
38 }
39 
40 class ChineseFlingView : public Sample {
41     static constexpr int kNumBlobs = 200;
42     static constexpr int kWordLength = 16;
43 
44     sk_sp<SkTypeface>    fTypeface;
45     SkFontMetrics        fMetrics;
46     sk_sp<SkTextBlob>    fBlobs[kNumBlobs];
47     SkRandom             fRand;
48     int                  fIndex = 0;
49 
name()50     SkString name() override { return SkString("chinese-fling"); }
51 
onDrawContent(SkCanvas * canvas)52     void onDrawContent(SkCanvas* canvas) override {
53         canvas->clear(0xFFDDDDDD);
54 
55         SkPaint paint;
56         paint.setColor(0xDE000000);
57 
58         // draw a consistent run of the 'words' - one word per line
59         int index = fIndex;
60         for (SkScalar y = 0.0f; y < 1024.0f; ) {
61 
62             y += -fMetrics.fAscent;
63             canvas->drawTextBlob(fBlobs[index], 0, y, paint);
64 
65             y += fMetrics.fDescent + fMetrics.fLeading;
66             ++index;
67             index %= kNumBlobs;
68         }
69         // now "fling" a random amount
70         fIndex += fRand.nextRangeU(5, 20);
71         fIndex %= kNumBlobs;
72     }
73 
onOnceBeforeDraw()74     void onOnceBeforeDraw() override {
75         fTypeface = chinese_typeface();
76 
77         SkFont font(fTypeface, 56);
78         font.getMetrics(&fMetrics);
79 
80         SkUnichar glyphs[kWordLength];
81         for (int32_t i = 0; i < kNumBlobs; ++i) {
82             this->createRandomWord(glyphs);
83 
84             SkTextBlobBuilder builder;
85             ToolUtils::add_to_text_blob_w_len(&builder,
86                                               (const char*)glyphs,
87                                               kWordLength * 4,
88                                               SkTextEncoding::kUTF32,
89                                               font,
90                                               0,
91                                               0);
92 
93             fBlobs[i] = builder.make();
94         }
95     }
96 
97     // Construct a random kWordLength character 'word' drawing from the full Chinese set
createRandomWord(SkUnichar glyphs[kWordLength])98     void createRandomWord(SkUnichar glyphs[kWordLength]) {
99         for (int i = 0; i < kWordLength; ++i) {
100             glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0);
101         }
102     }
103 };
104 
105 class ChineseZoomView : public Sample {
106     static constexpr int kNumBlobs = 8;
107     static constexpr int kParagraphLength = 175;
108 
109     bool                 fAfterFirstFrame = false;
110     sk_sp<SkTypeface>    fTypeface;
111     SkFontMetrics        fMetrics;
112     sk_sp<SkTextBlob>    fBlobs[kNumBlobs];
113     SkRandom             fRand;
114     SkScalar             fScale = 15;
115     SkScalar             fTranslate = 0;
116 
name()117     SkString name() override { return SkString("chinese-zoom"); }
118 
onChar(SkUnichar uni)119     bool onChar(SkUnichar uni) override {
120             if ('>' == uni) {
121                 fScale += 0.125f;
122                 return true;
123             }
124             if ('<' == uni) {
125                 fScale -= 0.125f;
126                 return true;
127             }
128             return false;
129     }
130 
onDrawContent(SkCanvas * canvas)131     void onDrawContent(SkCanvas* canvas) override {
132         canvas->clear(0xFFDDDDDD);
133 
134         SkPaint paint;
135         paint.setAntiAlias(true);
136         paint.setColor(0xDE000000);
137 
138         if (fAfterFirstFrame) {
139 #if SK_SUPPORT_GPU
140             auto direct = GrAsDirectContext(canvas->recordingContext());
141             if (direct) {
142                 sk_sp<SkImage> image = direct->priv().testingOnly_getFontAtlasImage(
143                             GrMaskFormat::kA8_GrMaskFormat, 0);
144                 canvas->drawImageRect(image,
145                                       SkRect::MakeXYWH(10.0f, 10.0f, 512.0f, 512.0), &paint);
146                 image = direct->priv().testingOnly_getFontAtlasImage(
147                         GrMaskFormat::kA8_GrMaskFormat, 1);
148                 canvas->drawImageRect(image,
149                                       SkRect::MakeXYWH(522.0f, 10.0f, 512.f, 512.0f), &paint);
150                 image = direct->priv().testingOnly_getFontAtlasImage(
151                         GrMaskFormat::kA8_GrMaskFormat, 2);
152                 canvas->drawImageRect(image,
153                                       SkRect::MakeXYWH(10.0f, 522.0f, 512.0f, 512.0f), &paint);
154                 image = direct->priv().testingOnly_getFontAtlasImage(
155                         GrMaskFormat::kA8_GrMaskFormat, 3);
156                 canvas->drawImageRect(image,
157                                       SkRect::MakeXYWH(522.0f, 522.0f, 512.0f, 512.0f), &paint);
158             }
159 #endif
160         }
161 
162         canvas->scale(fScale, fScale);
163         canvas->translate(0, fTranslate);
164         fTranslate -= 0.5f;
165 
166         // draw a consistent run of the 'words' - one word per line
167         SkScalar y = 0;
168         for (int index = 0; index < kNumBlobs; ++index) {
169             y += -fMetrics.fAscent;
170             canvas->drawTextBlob(fBlobs[index], 0, y, paint);
171 
172             y += 3*(fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading);
173         }
174         if (!fAfterFirstFrame) {
175             fAfterFirstFrame = true;
176         }
177     }
178 
onOnceBeforeDraw()179     void onOnceBeforeDraw() override {
180         fTypeface = chinese_typeface();
181 
182         SkFont font(fTypeface, 11);
183         font.getMetrics(&fMetrics);
184 
185         SkPaint paint;
186         paint.setColor(0xDE000000);
187 
188         SkUnichar glyphs[45];
189         for (int32_t i = 0; i < kNumBlobs; ++i) {
190             SkTextBlobBuilder builder;
191             auto paragraphLength = kParagraphLength;
192             SkScalar y = 0;
193             while (paragraphLength - 45 > 0) {
194                 auto currentLineLength = std::min(45, paragraphLength - 45);
195                 this->createRandomLine(glyphs, currentLineLength);
196 
197                 ToolUtils::add_to_text_blob_w_len(&builder,
198                                                   (const char*)glyphs,
199                                                   currentLineLength * 4,
200                                                   SkTextEncoding::kUTF32,
201                                                   font,
202                                                   0,
203                                                   y);
204                 y += fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading;
205                 paragraphLength -= 45;
206             }
207             fBlobs[i] = builder.make();
208         }
209     }
210 
211     // Construct a random kWordLength character 'word' drawing from the full Chinese set
createRandomLine(SkUnichar glyphs[45],int lineLength)212     void createRandomLine(SkUnichar glyphs[45], int lineLength) {
213         for (auto i = 0; i < lineLength; ++i) {
214             glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0);
215         }
216     }
217 };
218 
219 //////////////////////////////////////////////////////////////////////////////
220 
221 DEF_SAMPLE( return new ChineseFlingView(); )
222 DEF_SAMPLE( return new ChineseZoomView(); )
223