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 "Resources.h"
9 #include "SampleCode.h"
10 #include "sk_tool_utils.h"
11
12 #include "SkCanvas.h"
13 #include "SkFontMgr.h"
14 #include "SkRandom.h"
15 #include "SkTypeface.h"
16 #include "SkTextBlob.h"
17
18 #if SK_SUPPORT_GPU
19 #include "GrContext.h"
20 #endif
21
make_paint(SkPaint * paint,sk_sp<SkTypeface> typeface)22 static void make_paint(SkPaint* paint, sk_sp<SkTypeface> typeface) {
23 static const int kTextSize = 56;
24
25 paint->setAntiAlias(true);
26 paint->setColor(0xDE000000);
27 paint->setTypeface(typeface);
28 paint->setTextSize(kTextSize);
29 paint->setTextEncoding(SkPaint::kUTF32_TextEncoding);
30 }
31
chinese_typeface()32 static sk_sp<SkTypeface> chinese_typeface() {
33 #ifdef SK_BUILD_FOR_ANDROID
34 return MakeResourceAsTypeface("fonts/NotoSansCJK-Regular.ttc");
35 #elif defined(SK_BUILD_FOR_WIN)
36 return SkTypeface::MakeFromName("SimSun", SkFontStyle());
37 #elif defined(SK_BUILD_FOR_MAC)
38 return SkTypeface::MakeFromName("Hiragino Sans GB W3", SkFontStyle());
39 #elif defined(SK_BUILD_FOR_IOS)
40 return SkTypeface::MakeFromName("Hiragino Sans GB W3", SkFontStyle());
41 #elif defined(SK_BUILD_FOR_UNIX)
42 return SkTypeface::MakeFromName("Noto Sans CJK SC", SkFontStyle());
43 #else
44 return nullptr;
45 #endif
46 }
47
48 class ChineseFlingView : public SampleView {
49 public:
ChineseFlingView()50 ChineseFlingView() : fBlobs(kNumBlobs) {}
51
52 protected:
onQuery(SkEvent * evt)53 bool onQuery(SkEvent* evt) override {
54 if (SampleCode::TitleQ(*evt)) {
55 SampleCode::TitleR(evt, "chinese-fling");
56 return true;
57 }
58 return this->INHERITED::onQuery(evt);
59 }
60
onDrawContent(SkCanvas * canvas)61 void onDrawContent(SkCanvas* canvas) override {
62 if (!fInitialized) {
63 this->init();
64 fInitialized = true;
65 }
66
67 canvas->clear(0xFFDDDDDD);
68
69 SkPaint paint;
70 make_paint(&paint, fTypeface);
71
72 // draw a consistent run of the 'words' - one word per line
73 int index = fIndex;
74 for (SkScalar y = 0.0f; y < 1024.0f; ) {
75
76 y += -fMetrics.fAscent;
77 canvas->drawTextBlob(fBlobs[index], 0, y, paint);
78
79 y += fMetrics.fDescent + fMetrics.fLeading;
80 ++index;
81 index %= fBlobs.count();
82 }
83 // now "fling" a random amount
84 fIndex += fRand.nextRangeU(5, 20);
85 fIndex %= fBlobs.count();
86 }
87
88 private:
89 static constexpr auto kNumBlobs = 200;
90 static constexpr auto kWordLength = 16;
91
init()92 void init() {
93 fTypeface = chinese_typeface();
94
95 SkPaint paint;
96 make_paint(&paint, fTypeface);
97
98 paint.getFontMetrics(&fMetrics);
99
100 SkUnichar glyphs[kWordLength];
101 for (int32_t i = 0; i < kNumBlobs; ++i) {
102 this->createRandomWord(glyphs);
103
104 SkTextBlobBuilder builder;
105 sk_tool_utils::add_to_text_blob_w_len(&builder, (const char*) glyphs, kWordLength*4,
106 paint, 0, 0);
107
108 fBlobs.emplace_back(builder.make());
109 }
110
111 fIndex = 0;
112 }
113
114 // Construct a random kWordLength character 'word' drawing from the full Chinese set
createRandomWord(SkUnichar glyphs[kWordLength])115 void createRandomWord(SkUnichar glyphs[kWordLength]) {
116 for (int i = 0; i < kWordLength; ++i) {
117 glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0);
118 }
119 }
120
121 bool fInitialized = false;
122 sk_sp<SkTypeface> fTypeface;
123 SkPaint::FontMetrics fMetrics;
124 SkTArray<sk_sp<SkTextBlob>> fBlobs;
125 SkRandom fRand;
126 int fIndex;
127
128 typedef SkView INHERITED;
129 };
130
131 class ChineseZoomView : public SampleView {
132 public:
ChineseZoomView()133 ChineseZoomView() : fBlobs(kNumBlobs), fScale(1.0f) {}
134
135 protected:
onQuery(SkEvent * evt)136 bool onQuery(SkEvent* evt) override {
137 if (SampleCode::TitleQ(*evt)) {
138 SampleCode::TitleR(evt, "chinese-zoom");
139 return true;
140 }
141 SkUnichar uni;
142 if (SampleCode::CharQ(*evt, &uni)) {
143 if ('>' == uni) {
144 fScale += 0.125f;
145 return true;
146 }
147 if ('<' == uni) {
148 fScale -= 0.125f;
149 return true;
150 }
151 }
152 return this->INHERITED::onQuery(evt);
153 }
154
onDrawContent(SkCanvas * canvas)155 void onDrawContent(SkCanvas* canvas) override {
156 if (!fInitialized) {
157 this->init();
158 fInitialized = true;
159 }
160
161 canvas->clear(0xFFDDDDDD);
162
163 SkPaint paint;
164 paint.setAntiAlias(true);
165 paint.setColor(0xDE000000);
166 paint.setTypeface(fTypeface);
167 paint.setTextSize(11);
168 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
169
170 #if SK_SUPPORT_GPU
171 GrContext* grContext = canvas->getGrContext();
172 if (grContext) {
173 sk_sp<SkImage> image =
174 grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 0);
175 canvas->drawImageRect(image,
176 SkRect::MakeXYWH(512.0f, 10.0f, 512.0f, 512.0), &paint);
177 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 1);
178 canvas->drawImageRect(image,
179 SkRect::MakeXYWH(1024.0f, 10.0f, 512.f, 512.0f), &paint);
180 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 2);
181 canvas->drawImageRect(image,
182 SkRect::MakeXYWH(512.0f, 522.0f, 512.0f, 512.0f), &paint);
183 image = grContext->getFontAtlasImage_ForTesting(GrMaskFormat::kA8_GrMaskFormat, 3);
184 canvas->drawImageRect(image,
185 SkRect::MakeXYWH(1024.0f, 522.0f, 512.0f, 512.0f), &paint);
186 }
187 #endif
188
189 canvas->scale(fScale, fScale);
190
191 // draw a consistent run of the 'words' - one word per line
192 SkScalar y = 0;
193 for (int index = 0; index < kNumBlobs; ++index) {
194 y += -fMetrics.fAscent;
195 canvas->drawTextBlob(fBlobs[index], 0, y, paint);
196
197 y += 3*(fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading);
198 }
199 }
200
201 private:
202 static constexpr auto kNumBlobs = 8;
203 static constexpr auto kParagraphLength = 175;
204
init()205 void init() {
206 fTypeface = chinese_typeface();
207
208 SkPaint paint;
209 paint.setAntiAlias(true);
210 paint.setColor(0xDE000000);
211 paint.setTypeface(fTypeface);
212 paint.setTextSize(11);
213 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
214
215 paint.getFontMetrics(&fMetrics);
216
217 SkUnichar glyphs[45];
218 for (int32_t i = 0; i < kNumBlobs; ++i) {
219 SkTextBlobBuilder builder;
220 auto paragraphLength = kParagraphLength;
221 SkScalar y = 0;
222 while (paragraphLength - 45 > 0) {
223 auto currentLineLength = SkTMin(45, paragraphLength - 45);
224 this->createRandomLine(glyphs, currentLineLength);
225
226 sk_tool_utils::add_to_text_blob_w_len(&builder, (const char*) glyphs,
227 currentLineLength*4, paint, 0, y);
228 y += fMetrics.fDescent - fMetrics.fAscent + fMetrics.fLeading;
229 paragraphLength -= 45;
230 }
231 fBlobs.emplace_back(builder.make());
232 }
233
234 fIndex = 0;
235 }
236
237 // Construct a random kWordLength character 'word' drawing from the full Chinese set
createRandomLine(SkUnichar glyphs[45],int lineLength)238 void createRandomLine(SkUnichar glyphs[45], int lineLength) {
239 for (auto i = 0; i < lineLength; ++i) {
240 glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0);
241 }
242 }
243
244 bool fInitialized = false;
245 sk_sp<SkTypeface> fTypeface;
246 SkPaint::FontMetrics fMetrics;
247 SkTArray<sk_sp<SkTextBlob>> fBlobs;
248 SkRandom fRand;
249 SkScalar fScale;
250 int fIndex;
251
252 typedef SkView INHERITED;
253 };
254
255 //////////////////////////////////////////////////////////////////////////////
256
FlingFactory()257 static SkView* FlingFactory() { return new ChineseFlingView; }
258 static SkViewRegister regFling(FlingFactory);
259
ZoomFactory()260 static SkView* ZoomFactory() { return new ChineseZoomView; }
261 static SkViewRegister regZoom(ZoomFactory);
262