blob: 50b92c86942dda82050f8a2bac6cbc6b2a22796a [file] [log] [blame]
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +00001
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
19namespace 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 */
25class Xfermodes3GM : public GM {
26public:
27 Xfermodes3GM() {}
28
29protected:
30 virtual SkString onShortName() SK_OVERRIDE {
31 return SkString("xfermodes3");
32 }
33
34 virtual SkISize onISize() SK_OVERRIDE {
tfarinaf5393182014-06-09 23:59:03 -070035 return SkISize::Make(630, 1215);
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +000036 }
37
38 virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE {
39 SkPaint bgPaint;
40 bgPaint.setColor(0xFF70D0E0);
41 canvas->drawPaint(bgPaint);
42 }
43
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;
commit-bot@chromium.orgde1559c2013-08-14 19:20:45 +000065 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);
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +000083
commit-bot@chromium.orgde1559c2013-08-14 19:20:45 +000084 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +000085
commit-bot@chromium.orgde1559c2013-08-14 19:20:45 +000086 ++test;
87 x += kSize + 10;
88 if (!(test % kTestsPerRow)) {
89 x = 0;
90 y += kSize + 30;
91 }
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +000092 }
commit-bot@chromium.orgde1559c2013-08-14 19:20:45 +000093 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);
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000100
commit-bot@chromium.orgde1559c2013-08-14 19:20:45 +0000101 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000102
commit-bot@chromium.orgde1559c2013-08-14 19:20:45 +0000103 ++test;
104 x += kSize + 10;
105 if (!(test % kTestsPerRow)) {
106 x = 0;
107 y += kSize + 30;
108 }
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000109 }
110 }
111 }
112 }
113
114private:
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 */
123 SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) {
124 SkCanvas* tempCanvas = NULL;
125#if SK_SUPPORT_GPU
reed52d9ac62014-06-30 09:05:34 -0700126 GrContext* context = baseCanvas->getGrContext();
127 if (NULL != context) {
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000128 GrTextureDesc desc;
129 desc.fWidth = w;
130 desc.fHeight = h;
reed52d9ac62014-06-30 09:05:34 -0700131 desc.fConfig = SkImageInfo2GrPixelConfig(baseCanvas->imageInfo());
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000132 desc.fFlags = kRenderTarget_GrTextureFlagBit;
133 SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0));
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000134 SkAutoTUnref<SkBaseDevice> device(SkGpuDevice::Create(surface.get()));
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000135 if (NULL != device.get()) {
136 tempCanvas = SkNEW_ARGS(SkCanvas, (device.get()));
137 }
138 }
139#endif
140 return tempCanvas;
141 }
142
143 void drawMode(SkCanvas* canvas,
144 int x, int y, int w, int h,
145 const SkPaint& modePaint, SkCanvas* layerCanvas) {
146 canvas->save();
147
148 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
149
150 SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
151
152 SkCanvas* modeCanvas;
153 if (NULL == layerCanvas) {
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000154 canvas->saveLayer(&r, NULL);
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000155 modeCanvas = canvas;
156 } else {
157 modeCanvas = layerCanvas;
158 }
159
160 SkPaint bgPaint;
161 bgPaint.setAntiAlias(false);
162 bgPaint.setShader(fBGShader);
163 modeCanvas->drawRect(r, bgPaint);
164 modeCanvas->drawRect(r, modePaint);
165 modeCanvas = NULL;
166
167 if (NULL == layerCanvas) {
168 canvas->restore();
169 } else {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000170 SkAutoROCanvasPixels ropixels(layerCanvas);
171 SkBitmap bitmap;
172 if (ropixels.asROBitmap(&bitmap)) {
173 canvas->drawBitmap(bitmap, 0, 0);
174 }
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000175 }
176
177 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
178 SkPaint borderPaint;
179 borderPaint.setStyle(SkPaint::kStroke_Style);
180 canvas->drawRect(r, borderPaint);
181
182 canvas->restore();
183 }
184
185 virtual void onOnceBeforeDraw() SK_OVERRIDE {
186 static const uint32_t kCheckData[] = {
187 SkPackARGB32(0xFF, 0x40, 0x40, 0x40),
188 SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
189 SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
190 SkPackARGB32(0xFF, 0x40, 0x40, 0x40)
191 };
192 SkBitmap bg;
reed@google.comeb9a46c2014-01-25 16:46:20 +0000193 bg.allocN32Pixels(2, 2, true);
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000194 SkAutoLockPixels bgAlp(bg);
195 memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000196
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000197 SkMatrix lm;
198 lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000199 fBGShader.reset(SkShader::CreateBitmapShader(bg,
200 SkShader::kRepeat_TileMode,
201 SkShader::kRepeat_TileMode,
202 &lm));
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000203
204 SkPaint bmpPaint;
205 static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
206 static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000,
207 0xF020F060, SK_ColorWHITE };
208 bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter,
209 3 * SkIntToScalar(kSize) / 4,
210 kColors,
211 NULL,
212 SK_ARRAY_COUNT(kColors),
213 SkShader::kRepeat_TileMode))->unref();
214
215 SkBitmap bmp;
reed@google.comeb9a46c2014-01-25 16:46:20 +0000216 bmp.allocN32Pixels(kSize, kSize);
commit-bot@chromium.org103f2d02013-08-08 21:13:38 +0000217 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
243DEF_GM(return new Xfermodes3GM;)
244
245}