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 SkISize::Make(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 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 if (context) { 129 GrTextureDesc desc; 130 desc.fWidth = w; 131 desc.fHeight = h; 132 desc.fConfig = SkImageInfo2GrPixelConfig(baseCanvas->imageInfo()); 133 desc.fFlags = kRenderTarget_GrTextureFlagBit; 134 SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0)); 135 SkAutoTUnref<SkBaseDevice> device(SkGpuDevice::Create(surface.get(), 136 SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))); 137 if (device.get()) { 138 tempCanvas = SkNEW_ARGS(SkCanvas, (device.get())); 139 } 140 } 141 #endif 142 return tempCanvas; 143 } 144 drawMode(SkCanvas * canvas,int x,int y,int w,int h,const SkPaint & modePaint,SkCanvas * layerCanvas)145 void drawMode(SkCanvas* canvas, 146 int x, int y, int w, int h, 147 const SkPaint& modePaint, SkCanvas* layerCanvas) { 148 canvas->save(); 149 150 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 151 152 SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)); 153 154 SkCanvas* modeCanvas; 155 if (NULL == layerCanvas) { 156 canvas->saveLayer(&r, NULL); 157 modeCanvas = canvas; 158 } else { 159 modeCanvas = layerCanvas; 160 } 161 162 SkPaint bgPaint; 163 bgPaint.setAntiAlias(false); 164 bgPaint.setShader(fBGShader); 165 modeCanvas->drawRect(r, bgPaint); 166 modeCanvas->drawRect(r, modePaint); 167 modeCanvas = NULL; 168 169 if (NULL == layerCanvas) { 170 canvas->restore(); 171 } else { 172 SkAutoROCanvasPixels ropixels(layerCanvas); 173 SkBitmap bitmap; 174 if (ropixels.asROBitmap(&bitmap)) { 175 canvas->drawBitmap(bitmap, 0, 0); 176 } 177 } 178 179 r.inset(-SK_ScalarHalf, -SK_ScalarHalf); 180 SkPaint borderPaint; 181 borderPaint.setStyle(SkPaint::kStroke_Style); 182 canvas->drawRect(r, borderPaint); 183 184 canvas->restore(); 185 } 186 onOnceBeforeDraw()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) 193 }; 194 SkBitmap bg; 195 bg.allocN32Pixels(2, 2, true); 196 SkAutoLockPixels bgAlp(bg); 197 memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData)); 198 199 SkMatrix lm; 200 lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize)); 201 fBGShader.reset(SkShader::CreateBitmapShader(bg, 202 SkShader::kRepeat_TileMode, 203 SkShader::kRepeat_TileMode, 204 &lm)); 205 206 SkPaint bmpPaint; 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, 212 kColors, 213 NULL, 214 SK_ARRAY_COUNT(kColors), 215 SkShader::kRepeat_TileMode))->unref(); 216 217 SkBitmap bmp; 218 bmp.allocN32Pixels(kSize, kSize); 219 SkCanvas bmpCanvas(bmp); 220 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); 225 226 fBmpShader.reset(SkShader::CreateBitmapShader(bmp, 227 SkShader::kClamp_TileMode, 228 SkShader::kClamp_TileMode)); 229 } 230 231 enum { 232 kCheckSize = 8, 233 kSize = 30, 234 kTestsPerRow = 15, 235 }; 236 237 SkAutoTUnref<SkShader> fBGShader; 238 SkAutoTUnref<SkShader> fBmpShader; 239 240 typedef GM INHERITED; 241 }; 242 243 ////////////////////////////////////////////////////////////////////////////// 244 245 DEF_GM(return new Xfermodes3GM;) 246 247 } 248