xref: /third_party/skia/gm/dftext.cpp (revision cb93a386)
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
8#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkColorSpace.h"
12#include "include/core/SkFont.h"
13#include "include/core/SkFontStyle.h"
14#include "include/core/SkFontTypes.h"
15#include "include/core/SkImageInfo.h"
16#include "include/core/SkMatrix.h"
17#include "include/core/SkPaint.h"
18#include "include/core/SkPoint.h"
19#include "include/core/SkRect.h"
20#include "include/core/SkRefCnt.h"
21#include "include/core/SkScalar.h"
22#include "include/core/SkSize.h"
23#include "include/core/SkString.h"
24#include "include/core/SkSurface.h"
25#include "include/core/SkSurfaceProps.h"
26#include "include/core/SkTextBlob.h"
27#include "include/core/SkTypeface.h"
28#include "include/core/SkTypes.h"
29#include "include/private/SkTemplates.h"
30#include "include/private/SkTo.h"
31#include "tools/ToolUtils.h"
32
33#include <string.h>
34
35class DFTextGM : public skiagm::GM {
36public:
37    DFTextGM() {
38        this->setBGColor(0xFFFFFFFF);
39    }
40
41protected:
42    void onOnceBeforeDraw() override {
43        fEmojiTypeface = ToolUtils::emoji_typeface();
44        fEmojiText     = ToolUtils::emoji_sample_text();
45    }
46
47    SkString onShortName() override {
48        return SkString("dftext");
49    }
50
51    SkISize onISize() override {
52        return SkISize::Make(1024, 768);
53    }
54
55    void onDraw(SkCanvas* inputCanvas) override {
56        SkScalar textSizes[] = { 9.0f, 9.0f*2.0f, 9.0f*5.0f, 9.0f*2.0f*5.0f };
57        SkScalar scales[] = { 2.0f*5.0f, 5.0f, 2.0f, 1.0f };
58
59        // set up offscreen rendering with distance field text
60        auto ctx = inputCanvas->recordingContext();
61        SkISize size = onISize();
62        SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType,
63                                                inputCanvas->imageInfo().refColorSpace());
64        SkSurfaceProps inputProps;
65        inputCanvas->getProps(&inputProps);
66        SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag | inputProps.flags(),
67                             inputProps.pixelGeometry());
68        auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props));
69        SkCanvas* canvas = surface ? surface->getCanvas() : inputCanvas;
70        // init our new canvas with the old canvas's matrix
71        canvas->setMatrix(inputCanvas->getLocalToDeviceAs3x3());
72        // apply global scale to test glyph positioning
73        canvas->scale(1.05f, 1.05f);
74        canvas->clear(0xffffffff);
75
76        SkPaint paint;
77        paint.setAntiAlias(true);
78
79        SkFont font(ToolUtils::create_portable_typeface("serif", SkFontStyle()));
80        font.setSubpixel(true);
81
82        const char* text = "Hamburgefons";
83        const size_t textLen = strlen(text);
84
85        // check scaling up
86        SkScalar x = SkIntToScalar(0);
87        SkScalar y = SkIntToScalar(78);
88        for (size_t i = 0; i < SK_ARRAY_COUNT(textSizes); ++i) {
89            SkAutoCanvasRestore acr(canvas, true);
90            canvas->translate(x, y);
91            canvas->scale(scales[i], scales[i]);
92            font.setSize(textSizes[i]);
93            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
94            y += font.getMetrics(nullptr)*scales[i];
95        }
96
97        // check rotation
98        for (size_t i = 0; i < 5; ++i) {
99            SkScalar rotX = SkIntToScalar(10);
100            SkScalar rotY = y;
101
102            SkAutoCanvasRestore acr(canvas, true);
103            canvas->translate(SkIntToScalar(10 + i * 200), -80);
104            canvas->rotate(SkIntToScalar(i * 5), rotX, rotY);
105            for (int ps = 6; ps <= 32; ps += 3) {
106                font.setSize(SkIntToScalar(ps));
107                canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, rotX, rotY, font, paint);
108                rotY += font.getMetrics(nullptr);
109            }
110        }
111
112        // check scaling down
113        font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
114        x = SkIntToScalar(680);
115        y = SkIntToScalar(20);
116        size_t arraySize = SK_ARRAY_COUNT(textSizes);
117        for (size_t i = 0; i < arraySize; ++i) {
118            SkAutoCanvasRestore acr(canvas, true);
119            canvas->translate(x, y);
120            SkScalar scaleFactor = SkScalarInvert(scales[arraySize - i - 1]);
121            canvas->scale(scaleFactor, scaleFactor);
122            font.setSize(textSizes[i]);
123            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
124            y += font.getMetrics(nullptr)*scaleFactor;
125        }
126
127        // check pos text
128        {
129            SkAutoCanvasRestore acr(canvas, true);
130
131            canvas->scale(2.0f, 2.0f);
132
133            SkAutoTArray<SkGlyphID> glyphs(SkToInt(textLen));
134            int count = font.textToGlyphs(text, textLen, SkTextEncoding::kUTF8, glyphs.get(), textLen);
135            SkAutoTArray<SkPoint>  pos(count);
136            font.setSize(textSizes[0]);
137            font.getPos(glyphs.get(), count, pos.get(), {340, 75});
138
139            auto blob = SkTextBlob::MakeFromPosText(glyphs.get(), count * sizeof(SkGlyphID),
140                                                    pos.get(), font, SkTextEncoding::kGlyphID);
141            canvas->drawTextBlob(blob, 0, 0, paint);
142        }
143
144
145        // check gamma-corrected blending
146        const SkColor fg[] = {
147            0xFFFFFFFF,
148            0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
149            0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
150            0xFF000000,
151        };
152
153        paint.setColor(0xFFF7F3F7);
154        SkRect r = SkRect::MakeLTRB(670, 215, 820, 397);
155        canvas->drawRect(r, paint);
156
157        x = SkIntToScalar(680);
158        y = SkIntToScalar(235);
159        font.setSize(SkIntToScalar(19));
160        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
161            paint.setColor(fg[i]);
162
163            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint);
164            y += font.getMetrics(nullptr);
165        }
166
167        paint.setColor(0xFF181C18);
168        r = SkRect::MakeLTRB(820, 215, 970, 397);
169        canvas->drawRect(r, paint);
170
171        x = SkIntToScalar(830);
172        y = SkIntToScalar(235);
173        font.setSize(SkIntToScalar(19));
174        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
175            paint.setColor(fg[i]);
176
177            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint);
178            y += font.getMetrics(nullptr);
179        }
180
181        // check skew
182        {
183            font.setEdging(SkFont::Edging::kAntiAlias);
184            SkAutoCanvasRestore acr(canvas, true);
185            canvas->skew(0.0f, 0.151515f);
186            font.setSize(SkIntToScalar(32));
187            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 745, 70, font, paint);
188        }
189        {
190            font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
191            SkAutoCanvasRestore acr(canvas, true);
192            canvas->skew(0.5f, 0.0f);
193            font.setSize(SkIntToScalar(32));
194            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 580, 125, font, paint);
195        }
196
197        // check perspective
198        {
199            font.setEdging(SkFont::Edging::kAntiAlias);
200            SkAutoCanvasRestore acr(canvas, true);
201            SkMatrix persp;
202            persp.setAll(0.9839f, 0, 0,
203                         0.2246f, 0.6829f, 0,
204                         0.0002352f, -0.0003844f, 1);
205            canvas->concat(persp);
206            canvas->translate(1100, -295);
207            font.setSize(37.5f);
208            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
209        }
210        {
211            font.setSubpixel(false);
212            font.setEdging(SkFont::Edging::kAlias);
213            SkAutoCanvasRestore acr(canvas, true);
214            SkMatrix persp;
215            persp.setAll(0.9839f, 0, 0,
216                         0.2246f, 0.6829f, 0,
217                         0.0002352f, -0.0003844f, 1);
218            canvas->concat(persp);
219            canvas->translate(1075, -245);
220            canvas->scale(375, 375);
221            font.setSize(0.1f);
222            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
223        }
224
225        // check color emoji
226        if (fEmojiTypeface) {
227            SkFont emoiFont;
228            emoiFont.setSubpixel(true);
229            emoiFont.setTypeface(fEmojiTypeface);
230            emoiFont.setSize(SkIntToScalar(19));
231            canvas->drawSimpleText(fEmojiText, strlen(fEmojiText), SkTextEncoding::kUTF8, 670, 90, emoiFont, paint);
232        }
233
234        // render offscreen buffer
235        if (surface) {
236            SkAutoCanvasRestore acr(inputCanvas, true);
237            // since we prepended this matrix already, we blit using identity
238            inputCanvas->resetMatrix();
239            inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0);
240        }
241    }
242
243private:
244    sk_sp<SkTypeface> fEmojiTypeface;
245    const char* fEmojiText;
246
247    using INHERITED = skiagm::GM;
248};
249
250DEF_GM(return new DFTextGM;)
251