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
22static 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
32static 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
48class ChineseFlingView : public SampleView {
49public:
50    ChineseFlingView() : fBlobs(kNumBlobs) {}
51
52protected:
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
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
88private:
89    static constexpr auto kNumBlobs = 200;
90    static constexpr auto kWordLength = 16;
91
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
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
131class ChineseZoomView : public SampleView {
132public:
133    ChineseZoomView() : fBlobs(kNumBlobs), fScale(1.0f) {}
134
135protected:
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
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
201private:
202    static constexpr auto kNumBlobs = 8;
203    static constexpr auto kParagraphLength = 175;
204
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
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
257static SkView* FlingFactory() { return new ChineseFlingView; }
258static SkViewRegister regFling(FlingFactory);
259
260static SkView* ZoomFactory() { return new ChineseZoomView; }
261static SkViewRegister regZoom(ZoomFactory);
262