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: 27 Xfermodes3GM() {} 28 29 protected: 30 virtual SkString onShortName() SK_OVERRIDE { 31 return SkString("xfermodes3"); 32 } 33 34 virtual SkISize onISize() SK_OVERRIDE { 35 return make_isize(630, 620); 36 } 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; 65 for (size_t m = 0; m <= SkXfermode::kLastMode; ++m) { 66 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(m); 67 canvas->drawText(SkXfermode::ModeName(mode), 68 strlen(SkXfermode::ModeName(mode)), 69 SkIntToScalar(x), 70 SkIntToScalar(y + kSize + 3) + labelP.getTextSize(), 71 labelP); 72 for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) { 73 SkPaint modePaint; 74 modePaint.setXfermodeMode(mode); 75 modePaint.setColor(kSolidColors[c]); 76 77 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get()); 78 79 ++test; 80 x += kSize + 10; 81 if (!(test % kTestsPerRow)) { 82 x = 0; 83 y += kSize + 30; 84 } 85 } 86 for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) { 87 SkPaint modePaint; 88 modePaint.setXfermodeMode(mode); 89 modePaint.setAlpha(kBmpAlphas[a]); 90 modePaint.setShader(fBmpShader); 91 92 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get()); 93 94 ++test; 95 x += kSize + 10; 96 if (!(test % kTestsPerRow)) { 97 x = 0; 98 y += kSize + 30; 99 } 100 } 101 } 102 } 103 104 private: 105 /** 106 * GrContext has optimizations around full rendertarget draws that can be replaced with clears. 107 * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but 108 * saveLayer() uses the texture cache. This means that the actual render target may be larger 109 * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT. 110 * So when running on a GPU canvas we explicitly create a temporary canvas using a texture with 111 * dimensions exactly matching the layer size. 112 */ 113 SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) { 114 SkCanvas* tempCanvas = NULL; 115 #if SK_SUPPORT_GPU 116 GrRenderTarget* rt = baseCanvas->getDevice()->accessRenderTarget(); 117 if (NULL != rt) { 118 GrContext* context = rt->getContext(); 119 GrTextureDesc desc; 120 desc.fWidth = w; 121 desc.fHeight = h; 122 desc.fConfig = rt->config(); 123 desc.fFlags = kRenderTarget_GrTextureFlagBit; 124 SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0)); 125 SkAutoTUnref<SkDevice> device(SkGpuDevice::Create(surface.get())); 126 if (NULL != device.get()) { 127 tempCanvas = SkNEW_ARGS(SkCanvas, (device.get())); 128 } 129 } 130 #endif 131 return tempCanvas; 132 } 133 134 void drawMode(SkCanvas* canvas, 135 int x, int y, int w, int h, 136 const SkPaint& modePaint, SkCanvas* layerCanvas) { 137 canvas->save(); 138 139 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 140 141 SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)); 142 143 SkCanvas* modeCanvas; 144 if (NULL == layerCanvas) { 145 canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag); 146 modeCanvas = canvas; 147 } else { 148 modeCanvas = layerCanvas; 149 } 150 151 SkPaint bgPaint; 152 bgPaint.setAntiAlias(false); 153 bgPaint.setShader(fBGShader); 154 modeCanvas->drawRect(r, bgPaint); 155 modeCanvas->drawRect(r, modePaint); 156 modeCanvas = NULL; 157 158 if (NULL == layerCanvas) { 159 canvas->restore(); 160 } else { 161 SkBitmap bitmap = layerCanvas->getDevice()->accessBitmap(false); 162 canvas->drawBitmap(bitmap, 0, 0); 163 } 164 165 r.inset(-SK_ScalarHalf, -SK_ScalarHalf); 166 SkPaint borderPaint; 167 borderPaint.setStyle(SkPaint::kStroke_Style); 168 canvas->drawRect(r, borderPaint); 169 170 canvas->restore(); 171 } 172 173 virtual void onOnceBeforeDraw() SK_OVERRIDE { 174 static const uint32_t kCheckData[] = { 175 SkPackARGB32(0xFF, 0x40, 0x40, 0x40), 176 SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0), 177 SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0), 178 SkPackARGB32(0xFF, 0x40, 0x40, 0x40) 179 }; 180 SkBitmap bg; 181 bg.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); 182 bg.allocPixels(); 183 SkAutoLockPixels bgAlp(bg); 184 memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData)); 185 bg.setIsOpaque(true); 186 187 fBGShader.reset(SkShader::CreateBitmapShader(bg, 188 SkShader::kRepeat_TileMode, 189 SkShader::kRepeat_TileMode)); 190 SkMatrix lm; 191 lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize)); 192 fBGShader->setLocalMatrix(lm); 193 194 SkPaint bmpPaint; 195 static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 }; 196 static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000, 197 0xF020F060, SK_ColorWHITE }; 198 bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter, 199 3 * SkIntToScalar(kSize) / 4, 200 kColors, 201 NULL, 202 SK_ARRAY_COUNT(kColors), 203 SkShader::kRepeat_TileMode))->unref(); 204 205 SkBitmap bmp; 206 bmp.setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize); 207 bmp.allocPixels(); 208 SkCanvas bmpCanvas(bmp); 209 210 bmpCanvas.clear(SK_ColorTRANSPARENT); 211 SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8, 212 7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8}; 213 bmpCanvas.drawRect(rect, bmpPaint); 214 215 fBmpShader.reset(SkShader::CreateBitmapShader(bmp, 216 SkShader::kClamp_TileMode, 217 SkShader::kClamp_TileMode)); 218 } 219 220 enum { 221 kCheckSize = 8, 222 kSize = 30, 223 kTestsPerRow = 15, 224 }; 225 226 SkAutoTUnref<SkShader> fBGShader; 227 SkAutoTUnref<SkShader> fBmpShader; 228 229 typedef GM INHERITED; 230 }; 231 232 ////////////////////////////////////////////////////////////////////////////// 233 234 DEF_GM(return new Xfermodes3GM;) 235 236 } 237