3 * Copyright 2013 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkGradientShader.h"
11 #include "SkXfermode.h"
12 #include "SkColorPriv.h"
15 #include "GrContext.h"
16 #include "SkGpuDevice.h"
22 * This tests drawing device-covering rects with solid colors and bitmap shaders over a
23 * checkerboard background using different xfermodes.
25 class Xfermodes3GM : public GM {
30 virtual SkString onShortName() SK_OVERRIDE {
31 return SkString("xfermodes3");
34 virtual SkISize onISize() SK_OVERRIDE {
35 return SkISize::Make(630, 1215);
38 virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE {
40 bgPaint.setColor(0xFF70D0E0);
41 canvas->drawPaint(bgPaint);
44 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
45 canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
48 labelP.setAntiAlias(true);
49 sk_tool_utils::set_portable_typeface(&labelP);
51 static const SkColor kSolidColors[] = {
57 static const SkColor kBmpAlphas[] = {
62 SkAutoTUnref<SkCanvas> tempCanvas(this->possiblyCreateTempCanvas(canvas, kSize, kSize));
66 static const struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = {
67 {SkPaint::kFill_Style, 0},
68 {SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2},
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)),
76 SkIntToScalar(y + kSize + 3) + labelP.getTextSize(),
78 for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) {
80 modePaint.setXfermodeMode(mode);
81 modePaint.setColor(kSolidColors[c]);
82 modePaint.setStyle(kStrokes[s].fStyle);
83 modePaint.setStrokeWidth(kStrokes[s].fWidth);
85 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
89 if (!(test % kTestsPerRow)) {
94 for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) {
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);
102 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
106 if (!(test % kTestsPerRow)) {
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.
124 SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) {
125 SkCanvas* tempCanvas = NULL;
127 GrContext* context = baseCanvas->getGrContext();
132 desc.fConfig = SkImageInfo2GrPixelConfig(baseCanvas->imageInfo());
133 desc.fFlags = kRenderTarget_GrSurfaceFlag;
134 SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0));
135 SkAutoTUnref<SkBaseDevice> device(SkGpuDevice::Create(surface.get(),
136 SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)));
138 tempCanvas = SkNEW_ARGS(SkCanvas, (device.get()));
145 void drawMode(SkCanvas* canvas,
146 int x, int y, int w, int h,
147 const SkPaint& modePaint, SkCanvas* layerCanvas) {
150 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
152 SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
154 SkCanvas* modeCanvas;
155 if (NULL == layerCanvas) {
156 canvas->saveLayer(&r, NULL);
159 modeCanvas = layerCanvas;
163 bgPaint.setAntiAlias(false);
164 bgPaint.setShader(fBGShader);
165 modeCanvas->drawRect(r, bgPaint);
166 modeCanvas->drawRect(r, modePaint);
169 if (NULL == layerCanvas) {
172 SkAutoROCanvasPixels ropixels(layerCanvas);
174 if (ropixels.asROBitmap(&bitmap)) {
175 canvas->drawBitmap(bitmap, 0, 0);
179 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
181 borderPaint.setStyle(SkPaint::kStroke_Style);
182 canvas->drawRect(r, borderPaint);
187 virtual void onOnceBeforeDraw() SK_OVERRIDE {
188 static const uint32_t kCheckData[] = {
189 SkPackARGB32(0xFF, 0x40, 0x40, 0x40),
190 SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
191 SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
192 SkPackARGB32(0xFF, 0x40, 0x40, 0x40)
195 bg.allocN32Pixels(2, 2, true);
196 SkAutoLockPixels bgAlp(bg);
197 memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
200 lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
201 fBGShader.reset(SkShader::CreateBitmapShader(bg,
202 SkShader::kRepeat_TileMode,
203 SkShader::kRepeat_TileMode,
207 static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
208 static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000,
209 0xF020F060, SK_ColorWHITE };
210 bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter,
211 3 * SkIntToScalar(kSize) / 4,
214 SK_ARRAY_COUNT(kColors),
215 SkShader::kRepeat_TileMode))->unref();
218 bmp.allocN32Pixels(kSize, kSize);
219 SkCanvas bmpCanvas(bmp);
221 bmpCanvas.clear(SK_ColorTRANSPARENT);
222 SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
223 7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
224 bmpCanvas.drawRect(rect, bmpPaint);
226 fBmpShader.reset(SkShader::CreateBitmapShader(bmp,
227 SkShader::kClamp_TileMode,
228 SkShader::kClamp_TileMode));
237 SkAutoTUnref<SkShader> fBGShader;
238 SkAutoTUnref<SkShader> fBmpShader;
240 typedef GM INHERITED;
243 //////////////////////////////////////////////////////////////////////////////
245 DEF_GM(return new Xfermodes3GM;)