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 
14 class DFTextGM : public skiagm::GM {
15 public:
DFTextGM()16     DFTextGM() {
17         this->setBGColor(0xFFFFFFFF);
18     }
19 
20 protected:
onOnceBeforeDraw()21     void onOnceBeforeDraw() override {
22         sk_tool_utils::emoji_typeface(&fEmojiTypeface);
23         fEmojiText = sk_tool_utils::emoji_sample_text();
24     }
25 
onShortName()26     SkString onShortName() override {
27         SkString name("dftext");
28         name.append(sk_tool_utils::platform_os_emoji());
29         return name;
30     }
31 
onISize()32     SkISize onISize() override {
33         return SkISize::Make(1024, 768);
34     }
35 
rotate_about(SkCanvas * canvas,SkScalar degrees,SkScalar px,SkScalar py)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 
onDraw(SkCanvas * inputCanvas)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 
211 private:
212     SkAutoTUnref<SkTypeface> fEmojiTypeface;
213     const char* fEmojiText;
214 
215     typedef skiagm::GM INHERITED;
216 };
217 
218 DEF_GM(return new DFTextGM;)
219