• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkFilterQuality.h"
13 #include "include/core/SkFont.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSize.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTileMode.h"
25 #include "include/core/SkTypeface.h"
26 #include "include/core/SkTypes.h"
27 #include "include/effects/SkGradientShader.h"
28 #include "include/utils/SkTextUtils.h"
29 #include "tools/Resources.h"
30 #include "tools/ToolUtils.h"
31 
32 #include <functional>
33 
makebm(SkBitmap * bm,SkColorType ct,int w,int h)34 static void makebm(SkBitmap* bm, SkColorType ct, int w, int h) {
35     bm->allocPixels(SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType));
36     bm->eraseColor(SK_ColorTRANSPARENT);
37 
38     SkCanvas    canvas(*bm);
39     SkPoint     pts[] = { { 0, 0 }, { SkIntToScalar(w), SkIntToScalar(h)} };
40     SkColor     colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
41     SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
42     SkPaint     paint;
43 
44     paint.setDither(true);
45     paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, SK_ARRAY_COUNT(colors),
46                                                  SkTileMode::kClamp));
47     canvas.drawPaint(paint);
48 }
49 
setup(SkPaint * paint,const SkBitmap & bm,bool filter,SkTileMode tmx,SkTileMode tmy)50 static void setup(SkPaint* paint, const SkBitmap& bm, bool filter,
51                   SkTileMode tmx, SkTileMode tmy) {
52     paint->setShader(bm.makeShader(tmx, tmy));
53     paint->setFilterQuality(filter ? kLow_SkFilterQuality : kNone_SkFilterQuality);
54 }
55 
56 constexpr SkColorType gColorTypes[] = {
57     kN32_SkColorType,
58     kRGB_565_SkColorType,
59 };
60 
61 class TilingGM : public skiagm::GM {
62 public:
TilingGM(bool powerOfTwoSize)63     TilingGM(bool powerOfTwoSize)
64             : fPowerOfTwoSize(powerOfTwoSize) {
65     }
66 
67     SkBitmap    fTexture[SK_ARRAY_COUNT(gColorTypes)];
68 
69 protected:
70 
71     enum {
72         kPOTSize = 32,
73         kNPOTSize = 21,
74     };
75 
onShortName()76     SkString onShortName() override {
77         SkString name("tilemodes");
78         if (!fPowerOfTwoSize) {
79             name.append("_npot");
80         }
81         return name;
82     }
83 
onISize()84     SkISize onISize() override { return SkISize::Make(880, 560); }
85 
onOnceBeforeDraw()86     void onOnceBeforeDraw() override {
87         int size = fPowerOfTwoSize ? kPOTSize : kNPOTSize;
88         for (size_t i = 0; i < SK_ARRAY_COUNT(gColorTypes); i++) {
89             makebm(&fTexture[i], gColorTypes[i], size, size);
90         }
91     }
92 
onDraw(SkCanvas * canvas)93     void onDraw(SkCanvas* canvas) override {
94         SkPaint textPaint;
95         SkFont  font(ToolUtils::create_portable_typeface(), 12);
96 
97         int size = fPowerOfTwoSize ? kPOTSize : kNPOTSize;
98 
99         SkRect r = { 0, 0, SkIntToScalar(size*2), SkIntToScalar(size*2) };
100 
101         const char* gConfigNames[] = { "8888", "565", "4444" };
102 
103         constexpr bool gFilters[] = { false, true };
104         static const char* gFilterNames[] = { "point", "bilinear" };
105 
106         constexpr SkTileMode gModes[] = {
107             SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kMirror };
108         static const char* gModeNames[] = { "C", "R", "M" };
109 
110         SkScalar y = SkIntToScalar(24);
111         SkScalar x = SkIntToScalar(10);
112 
113         for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
114             for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
115                 SkPaint p;
116                 p.setDither(true);
117                 SkString str;
118                 SkFont   font(ToolUtils::create_portable_typeface());
119                 str.printf("[%s,%s]", gModeNames[kx], gModeNames[ky]);
120 
121                 SkTextUtils::DrawString(canvas, str.c_str(), x + r.width()/2, y, font, p,
122                                         SkTextUtils::kCenter_Align);
123 
124                 x += r.width() * 4 / 3;
125             }
126         }
127 
128         y += SkIntToScalar(16);
129 
130         for (size_t i = 0; i < SK_ARRAY_COUNT(gColorTypes); i++) {
131             for (size_t j = 0; j < SK_ARRAY_COUNT(gFilters); j++) {
132                 x = SkIntToScalar(10);
133                 for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
134                     for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
135                         SkPaint paint;
136 #if 1 // Temporary change to regen bitmap before each draw. This may help tracking down an issue
137       // on SGX where resizing NPOT textures to POT textures exhibits a driver bug.
138                         if (!fPowerOfTwoSize) {
139                             makebm(&fTexture[i], gColorTypes[i], size, size);
140                         }
141 #endif
142                         setup(&paint, fTexture[i], gFilters[j], gModes[kx], gModes[ky]);
143                         paint.setDither(true);
144 
145                         canvas->save();
146                         canvas->translate(x, y);
147                         canvas->drawRect(r, paint);
148                         canvas->restore();
149 
150                         x += r.width() * 4 / 3;
151                     }
152                 }
153                 canvas->drawString(SkStringPrintf("%s, %s", gConfigNames[i], gFilterNames[j]),
154                                    x, y + r.height() * 2 / 3, font, textPaint);
155 
156                 y += r.height() * 4 / 3;
157             }
158         }
159     }
160 
161 private:
162     bool fPowerOfTwoSize;
163     typedef skiagm::GM INHERITED;
164 };
165 DEF_GM( return new TilingGM(true); )
166 DEF_GM( return new TilingGM(false); )
167 
168 constexpr int gWidth = 32;
169 constexpr int gHeight = 32;
170 
make_bm(SkTileMode tx,SkTileMode ty)171 static sk_sp<SkShader> make_bm(SkTileMode tx, SkTileMode ty) {
172     SkBitmap bm;
173     makebm(&bm, kN32_SkColorType, gWidth, gHeight);
174     return bm.makeShader(tx, ty);
175 }
176 
make_grad(SkTileMode tx,SkTileMode ty)177 static sk_sp<SkShader> make_grad(SkTileMode tx, SkTileMode ty) {
178     SkPoint pts[] = { { 0, 0 }, { SkIntToScalar(gWidth), SkIntToScalar(gHeight)} };
179     SkPoint center = { SkIntToScalar(gWidth)/2, SkIntToScalar(gHeight)/2 };
180     SkScalar rad = SkIntToScalar(gWidth)/2;
181     SkColor  colors[] = {0xFFFF0000, ToolUtils::color_to_565(0xFF0044FF)};
182 
183     int index = (int)ty;
184     switch (index % 3) {
185         case 0:
186             return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), tx);
187         case 1:
188             return SkGradientShader::MakeRadial(center, rad, colors, nullptr, SK_ARRAY_COUNT(colors), tx);
189         case 2:
190             return SkGradientShader::MakeSweep(center.fX, center.fY, colors, nullptr,
191                                                SK_ARRAY_COUNT(colors), tx, 135, 225, 0, nullptr);
192     }
193     return nullptr;
194 }
195 
196 typedef sk_sp<SkShader> (*ShaderProc)(SkTileMode, SkTileMode);
197 
198 class Tiling2GM : public skiagm::GM {
199     ShaderProc fProc;
200     const char* fName;
201 
202 public:
Tiling2GM(ShaderProc proc,const char name[])203     Tiling2GM(ShaderProc proc, const char name[]) : fProc(proc), fName(name) {}
204 
205 private:
onShortName()206     SkString onShortName() override { return SkString(fName); }
207 
onISize()208     SkISize onISize() override { return SkISize::Make(650, 610); }
209 
onDraw(SkCanvas * canvas)210     void onDraw(SkCanvas* canvas) override {
211         canvas->scale(SkIntToScalar(3)/2, SkIntToScalar(3)/2);
212 
213         const SkScalar w = SkIntToScalar(gWidth);
214         const SkScalar h = SkIntToScalar(gHeight);
215         SkRect r = { -w, -h, w*2, h*2 };
216 
217         constexpr SkTileMode gModes[] = {
218             SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kMirror
219         };
220         const char* gModeNames[] = {
221             "Clamp", "Repeat", "Mirror"
222         };
223 
224         SkScalar y = SkIntToScalar(24);
225         SkScalar x = SkIntToScalar(66);
226 
227         SkFont font(ToolUtils::create_portable_typeface());
228 
229         for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
230             SkString str(gModeNames[kx]);
231             SkTextUtils::DrawString(canvas, str.c_str(), x + r.width()/2, y, font, SkPaint(),
232                                     SkTextUtils::kCenter_Align);
233             x += r.width() * 4 / 3;
234         }
235 
236         y += SkIntToScalar(16) + h;
237 
238         for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
239             x = SkIntToScalar(16) + w;
240 
241             SkString str(gModeNames[ky]);
242             SkTextUtils::DrawString(canvas, str.c_str(), x, y + h/2, font, SkPaint(),
243                                     SkTextUtils::kRight_Align);
244 
245             x += SkIntToScalar(50);
246             for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
247                 SkPaint paint;
248                 paint.setShader(fProc(gModes[kx], gModes[ky]));
249 
250                 canvas->save();
251                 canvas->translate(x, y);
252                 canvas->drawRect(r, paint);
253                 canvas->restore();
254 
255                 x += r.width() * 4 / 3;
256             }
257             y += r.height() * 4 / 3;
258         }
259     }
260 };
261 
262 DEF_GM( return new Tiling2GM(make_bm,   "tilemode_bitmap"); )
263 DEF_GM( return new Tiling2GM(make_grad, "tilemode_gradient"); )
264 
265 ////////////////////
266 
267 DEF_SIMPLE_GM(tilemode_decal, canvas, 720, 1100) {
268     auto img = GetResourceAsImage("images/mandrill_128.png");
269     SkPaint bgpaint;
270     bgpaint.setColor(SK_ColorYELLOW);
271 
272     SkRect r = { -20, -20, img->width() + 20.0f, img->height() + 20.0f };
273     canvas->translate(45, 45);
274 
275     std::function<void(SkPaint*, SkTileMode, SkTileMode)> shader_procs[] = {
__anon27c05da90202() 276         [img](SkPaint* paint, SkTileMode tx, SkTileMode ty) {
277             // Test no filtering with decal mode
278             paint->setShader(img->makeShader(tx, ty));
279             paint->setFilterQuality(kNone_SkFilterQuality);
280         },
__anon27c05da90302() 281         [img](SkPaint* paint, SkTileMode tx, SkTileMode ty) {
282             // Test bilerp approximation for decal mode (or clamp to border HW)
283             paint->setShader(img->makeShader(tx, ty));
284             paint->setFilterQuality(kLow_SkFilterQuality);
285         },
__anon27c05da90402() 286         [img](SkPaint* paint, SkTileMode tx, SkTileMode ty) {
287             // Test bicubic filter with decal mode
288             paint->setShader(img->makeShader(tx, ty));
289             paint->setFilterQuality(kHigh_SkFilterQuality);
290         },
__anon27c05da90502() 291         [img](SkPaint* paint, SkTileMode tx, SkTileMode ty) {
292             SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
293             const SkPoint pts[] = {{ 0, 0 }, {img->width()*1.0f, img->height()*1.0f }};
294             const SkScalar* pos = nullptr;
295             const int count = SK_ARRAY_COUNT(colors);
296             paint->setShader(SkGradientShader::MakeLinear(pts, colors, pos, count, tx));
297         },
__anon27c05da90602() 298         [img](SkPaint* paint, SkTileMode tx, SkTileMode ty) {
299             SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
300             const SkScalar* pos = nullptr;
301             const int count = SK_ARRAY_COUNT(colors);
302             paint->setShader(SkGradientShader::MakeRadial({ img->width()*0.5f, img->width()*0.5f },
303                                                       img->width()*0.5f, colors, pos, count, tx));
304         },
305     };
306 
307     const struct XY {
308         SkTileMode  fX;
309         SkTileMode  fY;
310     } pairs[] = {
311         { SkTileMode::kClamp,    SkTileMode::kClamp },
312         { SkTileMode::kClamp,    SkTileMode::kDecal },
313         { SkTileMode::kDecal,    SkTileMode::kClamp },
314         { SkTileMode::kDecal,    SkTileMode::kDecal },
315     };
316     for (const auto& p : pairs) {
317         SkPaint paint;
318         canvas->save();
319         for (const auto& proc : shader_procs) {
320             canvas->save();
321             // Apply a slight rotation to highlight the differences between filtered and unfiltered
322             // decal edges
323             canvas->rotate(4);
324             canvas->drawRect(r, bgpaint);
325             proc(&paint, p.fX, p.fY);
326             canvas->drawRect(r, paint);
327             canvas->restore();
328             canvas->translate(0, r.height() + 20);
329         }
330         canvas->restore();
331         canvas->translate(r.width() + 10, 0);
332     }
333 }
334 
335