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