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