• Home
  • History
  • Annotate
  • 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     SkString onShortName() override {
31         return SkString("xfermodes3");
32     }
33 
onISize()34     SkISize onISize() override {
35         return SkISize::Make(630, 1215);
36     }
37 
onDrawBackground(SkCanvas * canvas)38     void onDrawBackground(SkCanvas* canvas) override {
39         SkPaint bgPaint;
40         bgPaint.setColor(0xFF70D0E0);
41         canvas->drawPaint(bgPaint);
42     }
43 
onDraw(SkCanvas * canvas)44     void onDraw(SkCanvas* canvas) override {
45         canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
46 
47         SkPaint labelP;
48         labelP.setAntiAlias(true);
49         sk_tool_utils::set_portable_typeface(&labelP);
50 
51         static const SkColor kSolidColors[] = {
52             SK_ColorTRANSPARENT,
53             SK_ColorBLUE,
54             0x80808000
55         };
56 
57         static const SkColor kBmpAlphas[] = {
58             0xff,
59             0x80,
60         };
61 
62         SkAutoTUnref<SkCanvas> tempCanvas(this->possiblyCreateTempCanvas(canvas, kSize, kSize));
63 
64         int test = 0;
65         int x = 0, y = 0;
66         static const struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = {
67             {SkPaint::kFill_Style, 0},
68             {SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2},
69         };
70         for (size_t s = 0; s < SK_ARRAY_COUNT(kStrokes); ++s) {
71             for (size_t m = 0; m <= SkXfermode::kLastMode; ++m) {
72                 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(m);
73                 canvas->drawText(SkXfermode::ModeName(mode),
74                                  strlen(SkXfermode::ModeName(mode)),
75                                  SkIntToScalar(x),
76                                  SkIntToScalar(y + kSize + 3) + labelP.getTextSize(),
77                                  labelP);
78                 for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) {
79                     SkPaint modePaint;
80                     modePaint.setXfermodeMode(mode);
81                     modePaint.setColor(kSolidColors[c]);
82                     modePaint.setStyle(kStrokes[s].fStyle);
83                     modePaint.setStrokeWidth(kStrokes[s].fWidth);
84 
85                     this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
86 
87                     ++test;
88                     x += kSize + 10;
89                     if (!(test % kTestsPerRow)) {
90                         x = 0;
91                         y += kSize + 30;
92                     }
93                 }
94                 for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) {
95                     SkPaint modePaint;
96                     modePaint.setXfermodeMode(mode);
97                     modePaint.setAlpha(kBmpAlphas[a]);
98                     modePaint.setShader(fBmpShader);
99                     modePaint.setStyle(kStrokes[s].fStyle);
100                     modePaint.setStrokeWidth(kStrokes[s].fWidth);
101 
102                     this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
103 
104                     ++test;
105                     x += kSize + 10;
106                     if (!(test % kTestsPerRow)) {
107                         x = 0;
108                         y += kSize + 30;
109                     }
110                 }
111             }
112         }
113     }
114 
115 private:
116     /**
117      * GrContext has optimizations around full rendertarget draws that can be replaced with clears.
118      * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but
119      * saveLayer() uses the texture cache. This means that the actual render target may be larger
120      * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT.
121      * So when running on a GPU canvas we explicitly create a temporary canvas using a texture with
122      * dimensions exactly matching the layer size.
123      */
possiblyCreateTempCanvas(SkCanvas * baseCanvas,int w,int h)124     SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) {
125         SkCanvas* tempCanvas = NULL;
126 #if SK_SUPPORT_GPU
127         GrContext* context = baseCanvas->getGrContext();
128         SkImageInfo baseInfo = baseCanvas->imageInfo();
129         SkImageInfo info = SkImageInfo::Make(w, h, baseInfo.colorType(), baseInfo.alphaType(),
130                                              baseInfo.profileType());
131         SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted,
132                                         info, 0, NULL));
133         if (surface) {
134             tempCanvas = SkRef(surface->getCanvas());
135         }
136 #endif
137         return tempCanvas;
138     }
139 
drawMode(SkCanvas * canvas,int x,int y,int w,int h,const SkPaint & modePaint,SkCanvas * layerCanvas)140     void drawMode(SkCanvas* canvas,
141                   int x, int y, int w, int h,
142                   const SkPaint& modePaint, SkCanvas* layerCanvas) {
143         canvas->save();
144 
145         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
146 
147         SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
148 
149         SkCanvas* modeCanvas;
150         if (NULL == layerCanvas) {
151             canvas->saveLayer(&r, NULL);
152             modeCanvas = canvas;
153         } else {
154             modeCanvas = layerCanvas;
155         }
156 
157         SkPaint bgPaint;
158         bgPaint.setAntiAlias(false);
159         bgPaint.setShader(fBGShader);
160         modeCanvas->drawRect(r, bgPaint);
161         modeCanvas->drawRect(r, modePaint);
162         modeCanvas = NULL;
163 
164         if (NULL == layerCanvas) {
165             canvas->restore();
166         } else {
167             SkAutoROCanvasPixels ropixels(layerCanvas);
168             SkBitmap bitmap;
169             if (ropixels.asROBitmap(&bitmap)) {
170                 canvas->drawBitmap(bitmap, 0, 0);
171             }
172         }
173 
174         r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
175         SkPaint borderPaint;
176         borderPaint.setStyle(SkPaint::kStroke_Style);
177         canvas->drawRect(r, borderPaint);
178 
179         canvas->restore();
180     }
181 
onOnceBeforeDraw()182     void onOnceBeforeDraw() override {
183         static const uint32_t kCheckData[] = {
184             SkPackARGB32(0xFF, 0x40, 0x40, 0x40),
185             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
186             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
187             SkPackARGB32(0xFF, 0x40, 0x40, 0x40)
188         };
189         SkBitmap bg;
190         bg.allocN32Pixels(2, 2, true);
191         SkAutoLockPixels bgAlp(bg);
192         memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
193 
194         SkMatrix lm;
195         lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
196         fBGShader.reset(SkShader::CreateBitmapShader(bg,
197                                                      SkShader::kRepeat_TileMode,
198                                                      SkShader::kRepeat_TileMode,
199                                                      &lm));
200 
201         SkPaint bmpPaint;
202         static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
203         static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000,
204                                           0xF020F060, SK_ColorWHITE };
205         bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter,
206                                                           3 * SkIntToScalar(kSize) / 4,
207                                                           kColors,
208                                                           NULL,
209                                                           SK_ARRAY_COUNT(kColors),
210                                                           SkShader::kRepeat_TileMode))->unref();
211 
212         SkBitmap bmp;
213         bmp.allocN32Pixels(kSize, kSize);
214         SkCanvas bmpCanvas(bmp);
215 
216         bmpCanvas.clear(SK_ColorTRANSPARENT);
217         SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
218                         7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
219         bmpCanvas.drawRect(rect, bmpPaint);
220 
221         fBmpShader.reset(SkShader::CreateBitmapShader(bmp,
222                                                       SkShader::kClamp_TileMode,
223                                                       SkShader::kClamp_TileMode));
224     }
225 
226     enum {
227         kCheckSize = 8,
228         kSize = 30,
229         kTestsPerRow = 15,
230     };
231 
232     SkAutoTUnref<SkShader> fBGShader;
233     SkAutoTUnref<SkShader> fBmpShader;
234 
235     typedef GM INHERITED;
236 };
237 
238 //////////////////////////////////////////////////////////////////////////////
239 
240 DEF_GM(return new Xfermodes3GM;)
241 
242 }
243