1/*
2 * Copyright 2011 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#include "gm.h"
8#include "Resources.h"
9#include "SkCanvas.h"
10#include "SkStream.h"
11#include "SkSurface.h"
12#include "SkTypeface.h"
13
14class DFTextGM : public skiagm::GM {
15public:
16    DFTextGM() {
17        this->setBGColor(0xFFFFFFFF);
18    }
19
20protected:
21    void onOnceBeforeDraw() override {
22        sk_tool_utils::emoji_typeface(&fEmojiTypeface);
23        fEmojiText = sk_tool_utils::emoji_sample_text();
24    }
25
26    SkString onShortName() override {
27        SkString name("dftext");
28        name.append(sk_tool_utils::platform_os_emoji());
29        return name;
30    }
31
32    SkISize onISize() override {
33        return SkISize::Make(1024, 768);
34    }
35
36    static void rotate_about(SkCanvas* canvas,
37        SkScalar degrees,
38        SkScalar px, SkScalar py) {
39        canvas->translate(px, py);
40        canvas->rotate(degrees);
41        canvas->translate(-px, -py);
42    }
43
44    virtual void onDraw(SkCanvas* inputCanvas) override {
45        SkScalar textSizes[] = { 9.0f, 9.0f*2.0f, 9.0f*5.0f, 9.0f*2.0f*5.0f };
46        SkScalar scales[] = { 2.0f*5.0f, 5.0f, 2.0f, 1.0f };
47
48        // set up offscreen rendering with distance field text
49#if SK_SUPPORT_GPU
50        GrContext* ctx = inputCanvas->getGrContext();
51        SkImageInfo info = SkImageInfo::MakeN32Premul(onISize());
52        SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
53                             SkSurfaceProps::kLegacyFontHost_InitType);
54        SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, SkBudgeted::kNo,
55                                                                   info, 0, &props));
56        SkCanvas* canvas = surface.get() ? surface->getCanvas() : inputCanvas;
57        // init our new canvas with the old canvas's matrix
58        canvas->setMatrix(inputCanvas->getTotalMatrix());
59#else
60        SkCanvas* canvas = inputCanvas;
61#endif
62        // apply global scale to test glyph positioning
63        canvas->scale(1.05f, 1.05f);
64        canvas->clear(0xffffffff);
65
66        SkPaint paint;
67        paint.setAntiAlias(true);
68        paint.setSubpixelText(true);
69
70        sk_tool_utils::set_portable_typeface(&paint, "serif", SkTypeface::kNormal);
71
72        const char* text = "Hamburgefons";
73        const size_t textLen = strlen(text);
74
75        // check scaling up
76        SkScalar x = SkIntToScalar(0);
77        SkScalar y = SkIntToScalar(78);
78        for (size_t i = 0; i < SK_ARRAY_COUNT(textSizes); ++i) {
79            SkAutoCanvasRestore acr(canvas, true);
80            canvas->translate(x, y);
81            canvas->scale(scales[i], scales[i]);
82            paint.setTextSize(textSizes[i]);
83            canvas->drawText(text, textLen, 0, 0, paint);
84            y += paint.getFontMetrics(nullptr)*scales[i];
85        }
86
87        // check rotation
88        for (size_t i = 0; i < 5; ++i) {
89            SkScalar rotX = SkIntToScalar(10);
90            SkScalar rotY = y;
91
92            SkAutoCanvasRestore acr(canvas, true);
93            canvas->translate(SkIntToScalar(10 + i * 200), -80);
94            rotate_about(canvas, SkIntToScalar(i * 5), rotX, rotY);
95            for (int ps = 6; ps <= 32; ps += 3) {
96                paint.setTextSize(SkIntToScalar(ps));
97                canvas->drawText(text, textLen, rotX, rotY, paint);
98                rotY += paint.getFontMetrics(nullptr);
99            }
100        }
101
102        // check scaling down
103        paint.setLCDRenderText(true);
104        x = SkIntToScalar(680);
105        y = SkIntToScalar(20);
106        size_t arraySize = SK_ARRAY_COUNT(textSizes);
107        for (size_t i = 0; i < arraySize; ++i) {
108            SkAutoCanvasRestore acr(canvas, true);
109            canvas->translate(x, y);
110            SkScalar scaleFactor = SkScalarInvert(scales[arraySize - i - 1]);
111            canvas->scale(scaleFactor, scaleFactor);
112            paint.setTextSize(textSizes[i]);
113            canvas->drawText(text, textLen, 0, 0, paint);
114            y += paint.getFontMetrics(nullptr)*scaleFactor;
115        }
116
117        // check pos text
118        {
119            SkAutoCanvasRestore acr(canvas, true);
120
121            canvas->scale(2.0f, 2.0f);
122
123            SkAutoTArray<SkPoint>  pos(SkToInt(textLen));
124            SkAutoTArray<SkScalar> widths(SkToInt(textLen));
125            paint.setTextSize(textSizes[0]);
126
127            paint.getTextWidths(text, textLen, &widths[0]);
128
129            SkScalar x = SkIntToScalar(340);
130            SkScalar y = SkIntToScalar(75);
131            for (unsigned int i = 0; i < textLen; ++i) {
132                pos[i].set(x, y);
133                x += widths[i];
134            }
135
136            canvas->drawPosText(text, textLen, &pos[0], paint);
137        }
138
139
140        // check gamma-corrected blending
141        const SkColor fg[] = {
142            0xFFFFFFFF,
143            0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
144            0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
145            0xFF000000,
146        };
147
148        paint.setColor(0xFFF7F3F7);
149        SkRect r = SkRect::MakeLTRB(670, 215, 820, 397);
150        canvas->drawRect(r, paint);
151
152        x = SkIntToScalar(680);
153        y = SkIntToScalar(235);
154        paint.setTextSize(SkIntToScalar(19));
155        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
156            paint.setColor(fg[i]);
157
158            canvas->drawText(text, textLen, x, y, paint);
159            y += paint.getFontMetrics(nullptr);
160        }
161
162        paint.setColor(0xFF181C18);
163        r = SkRect::MakeLTRB(820, 215, 970, 397);
164        canvas->drawRect(r, paint);
165
166        x = SkIntToScalar(830);
167        y = SkIntToScalar(235);
168        paint.setTextSize(SkIntToScalar(19));
169        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
170            paint.setColor(fg[i]);
171
172            canvas->drawText(text, textLen, x, y, paint);
173            y += paint.getFontMetrics(nullptr);
174        }
175
176        // check skew
177        {
178            paint.setLCDRenderText(false);
179            SkAutoCanvasRestore acr(canvas, true);
180            canvas->skew(0.0f, 0.151515f);
181            paint.setTextSize(SkIntToScalar(32));
182            canvas->drawText(text, textLen, 745, 70, paint);
183        }
184        {
185            paint.setLCDRenderText(true);
186            SkAutoCanvasRestore acr(canvas, true);
187            canvas->skew(0.5f, 0.0f);
188            paint.setTextSize(SkIntToScalar(32));
189            canvas->drawText(text, textLen, 580, 125, paint);
190        }
191
192        // check color emoji
193        if (fEmojiTypeface) {
194            paint.setTypeface(fEmojiTypeface);
195            paint.setTextSize(SkIntToScalar(19));
196            canvas->drawText(fEmojiText, strlen(fEmojiText), 670, 90, paint);
197        }
198#if SK_SUPPORT_GPU
199        // render offscreen buffer
200        if (surface) {
201            SkAutoCanvasRestore acr(inputCanvas, true);
202            // since we prepended this matrix already, we blit using identity
203            inputCanvas->resetMatrix();
204            SkImage* image = surface->newImageSnapshot();
205            inputCanvas->drawImage(image, 0, 0, nullptr);
206            image->unref();
207        }
208#endif
209    }
210
211private:
212    SkAutoTUnref<SkTypeface> fEmojiTypeface;
213    const char* fEmojiText;
214
215    typedef skiagm::GM INHERITED;
216};
217
218DEF_GM(return new DFTextGM;)
219