• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2013 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "gm.h"
9 #include "SkBitmap.h"
10 #include "SkGradientShader.h"
11 #include "SkXfermode.h"
12 #include "SkColorPriv.h"
13 
14 #if SK_SUPPORT_GPU
15 #include "GrContext.h"
16 #include "SkGpuDevice.h"
17 #endif
18 
19 namespace skiagm {
20 
21 /**
22  * This tests drawing device-covering rects with solid colors and bitmap shaders over a
23  * checkerboard background using different xfermodes.
24  */
25 class Xfermodes3GM : public GM {
26 public:
Xfermodes3GM()27     Xfermodes3GM() {}
28 
29 protected:
onShortName()30     virtual SkString onShortName() SK_OVERRIDE {
31         return SkString("xfermodes3");
32     }
33 
onISize()34     virtual SkISize onISize() SK_OVERRIDE {
35         return make_isize(630, 1215);
36     }
37 
onDrawBackground(SkCanvas * canvas)38     virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE {
39         SkPaint bgPaint;
40         bgPaint.setColor(0xFF70D0E0);
41         canvas->drawPaint(bgPaint);
42     }
43 
onDraw(SkCanvas * canvas)44     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
45         canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
46 
47         SkPaint labelP;
48         labelP.setAntiAlias(true);
49 
50         static const SkColor kSolidColors[] = {
51             SK_ColorTRANSPARENT,
52             SK_ColorBLUE,
53             0x80808000
54         };
55 
56         static const SkColor kBmpAlphas[] = {
57             0xff,
58             0x80,
59         };
60 
61         SkAutoTUnref<SkCanvas> tempCanvas(this->possiblyCreateTempCanvas(canvas, kSize, kSize));
62 
63         int test = 0;
64         int x = 0, y = 0;
65         static const struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = {
66             {SkPaint::kFill_Style, 0},
67             {SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2},
68         };
69         for (size_t s = 0; s < SK_ARRAY_COUNT(kStrokes); ++s) {
70             for (size_t m = 0; m <= SkXfermode::kLastMode; ++m) {
71                 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(m);
72                 canvas->drawText(SkXfermode::ModeName(mode),
73                                  strlen(SkXfermode::ModeName(mode)),
74                                  SkIntToScalar(x),
75                                  SkIntToScalar(y + kSize + 3) + labelP.getTextSize(),
76                                  labelP);
77                 for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) {
78                     SkPaint modePaint;
79                     modePaint.setXfermodeMode(mode);
80                     modePaint.setColor(kSolidColors[c]);
81                     modePaint.setStyle(kStrokes[s].fStyle);
82                     modePaint.setStrokeWidth(kStrokes[s].fWidth);
83 
84                     this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
85 
86                     ++test;
87                     x += kSize + 10;
88                     if (!(test % kTestsPerRow)) {
89                         x = 0;
90                         y += kSize + 30;
91                     }
92                 }
93                 for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) {
94                     SkPaint modePaint;
95                     modePaint.setXfermodeMode(mode);
96                     modePaint.setAlpha(kBmpAlphas[a]);
97                     modePaint.setShader(fBmpShader);
98                     modePaint.setStyle(kStrokes[s].fStyle);
99                     modePaint.setStrokeWidth(kStrokes[s].fWidth);
100 
101                     this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
102 
103                     ++test;
104                     x += kSize + 10;
105                     if (!(test % kTestsPerRow)) {
106                         x = 0;
107                         y += kSize + 30;
108                     }
109                 }
110             }
111         }
112     }
113 
114 private:
115     /**
116      * GrContext has optimizations around full rendertarget draws that can be replaced with clears.
117      * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but
118      * saveLayer() uses the texture cache. This means that the actual render target may be larger
119      * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT.
120      * So when running on a GPU canvas we explicitly create a temporary canvas using a texture with
121      * dimensions exactly matching the layer size.
122      */
possiblyCreateTempCanvas(SkCanvas * baseCanvas,int w,int h)123     SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) {
124         SkCanvas* tempCanvas = NULL;
125 #if SK_SUPPORT_GPU
126         GrRenderTarget* rt = baseCanvas->getDevice()->accessRenderTarget();
127         if (NULL != rt) {
128             GrContext* context = rt->getContext();
129             GrTextureDesc desc;
130             desc.fWidth = w;
131             desc.fHeight = h;
132             desc.fConfig = rt->config();
133             desc.fFlags = kRenderTarget_GrTextureFlagBit;
134             SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0));
135             SkAutoTUnref<SkBaseDevice> device(SkGpuDevice::Create(surface.get()));
136             if (NULL != device.get()) {
137                 tempCanvas = SkNEW_ARGS(SkCanvas, (device.get()));
138             }
139         }
140 #endif
141         return tempCanvas;
142     }
143 
drawMode(SkCanvas * canvas,int x,int y,int w,int h,const SkPaint & modePaint,SkCanvas * layerCanvas)144     void drawMode(SkCanvas* canvas,
145                   int x, int y, int w, int h,
146                   const SkPaint& modePaint, SkCanvas* layerCanvas) {
147         canvas->save();
148 
149         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
150 
151         SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
152 
153         SkCanvas* modeCanvas;
154         if (NULL == layerCanvas) {
155             canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
156             modeCanvas = canvas;
157         } else {
158             modeCanvas = layerCanvas;
159         }
160 
161         SkPaint bgPaint;
162         bgPaint.setAntiAlias(false);
163         bgPaint.setShader(fBGShader);
164         modeCanvas->drawRect(r, bgPaint);
165         modeCanvas->drawRect(r, modePaint);
166         modeCanvas = NULL;
167 
168         if (NULL == layerCanvas) {
169             canvas->restore();
170         } else {
171             SkBitmap bitmap = layerCanvas->getDevice()->accessBitmap(false);
172             canvas->drawBitmap(bitmap, 0, 0);
173         }
174 
175         r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
176         SkPaint borderPaint;
177         borderPaint.setStyle(SkPaint::kStroke_Style);
178         canvas->drawRect(r, borderPaint);
179 
180         canvas->restore();
181     }
182 
onOnceBeforeDraw()183     virtual void onOnceBeforeDraw() SK_OVERRIDE {
184         static const uint32_t kCheckData[] = {
185             SkPackARGB32(0xFF, 0x40, 0x40, 0x40),
186             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
187             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
188             SkPackARGB32(0xFF, 0x40, 0x40, 0x40)
189         };
190         SkBitmap bg;
191         bg.setConfig(SkBitmap::kARGB_8888_Config, 2, 2, 0, kOpaque_SkAlphaType);
192         bg.allocPixels();
193         SkAutoLockPixels bgAlp(bg);
194         memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
195 
196         fBGShader.reset(SkShader::CreateBitmapShader(bg,
197                                                      SkShader::kRepeat_TileMode,
198                                                      SkShader::kRepeat_TileMode));
199         SkMatrix lm;
200         lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
201         fBGShader->setLocalMatrix(lm);
202 
203         SkPaint bmpPaint;
204         static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
205         static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000,
206                                           0xF020F060, SK_ColorWHITE };
207         bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter,
208                                                           3 * SkIntToScalar(kSize) / 4,
209                                                           kColors,
210                                                           NULL,
211                                                           SK_ARRAY_COUNT(kColors),
212                                                           SkShader::kRepeat_TileMode))->unref();
213 
214         SkBitmap bmp;
215         bmp.setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize);
216         bmp.allocPixels();
217         SkCanvas bmpCanvas(bmp);
218 
219         bmpCanvas.clear(SK_ColorTRANSPARENT);
220         SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
221                         7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
222         bmpCanvas.drawRect(rect, bmpPaint);
223 
224         fBmpShader.reset(SkShader::CreateBitmapShader(bmp,
225                                                       SkShader::kClamp_TileMode,
226                                                       SkShader::kClamp_TileMode));
227     }
228 
229     enum {
230         kCheckSize = 8,
231         kSize = 30,
232         kTestsPerRow = 15,
233     };
234 
235     SkAutoTUnref<SkShader> fBGShader;
236     SkAutoTUnref<SkShader> fBmpShader;
237 
238     typedef GM INHERITED;
239 };
240 
241 //////////////////////////////////////////////////////////////////////////////
242 
243 DEF_GM(return new Xfermodes3GM;)
244 
245 }
246