1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "gm.h" 9 #include "sk_tool_utils.h" 10 #include "SkBitmap.h" 11 #include "SkGradientShader.h" 12 #include "SkSurface.h" 13 #include "SkBlendModePriv.h" 14 #include "SkColorPriv.h" 15 16 #if SK_SUPPORT_GPU 17 #include "GrContext.h" 18 #endif 19 20 namespace skiagm { 21 22 /** 23 * This tests drawing device-covering rects with solid colors and bitmap shaders over a 24 * checkerboard background using different xfermodes. 25 */ 26 class Xfermodes3GM : public GM { 27 public: 28 Xfermodes3GM() {} 29 30 protected: 31 SkString onShortName() override { 32 return SkString("xfermodes3"); 33 } 34 35 SkISize onISize() override { 36 return SkISize::Make(630, 1215); 37 } 38 39 void onDrawBackground(SkCanvas* canvas) override { 40 SkPaint bgPaint; 41 bgPaint.setColor(sk_tool_utils::color_to_565(0xFF70D0E0)); 42 canvas->drawPaint(bgPaint); 43 } 44 45 void onDraw(SkCanvas* canvas) override { 46 canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); 47 48 SkPaint labelP; 49 labelP.setAntiAlias(true); 50 sk_tool_utils::set_portable_typeface(&labelP); 51 52 constexpr SkColor kSolidColors[] = { 53 SK_ColorTRANSPARENT, 54 SK_ColorBLUE, 55 0x80808000 56 }; 57 58 constexpr SkColor kBmpAlphas[] = { 59 0xff, 60 0x80, 61 }; 62 63 auto tempSurface(this->possiblyCreateTempSurface(canvas, kSize, kSize)); 64 65 int test = 0; 66 int x = 0, y = 0; 67 constexpr struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = { 68 {SkPaint::kFill_Style, 0}, 69 {SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2}, 70 }; 71 for (size_t s = 0; s < SK_ARRAY_COUNT(kStrokes); ++s) { 72 for (size_t m = 0; m <= (size_t)SkBlendMode::kLastMode; ++m) { 73 SkBlendMode mode = static_cast<SkBlendMode>(m); 74 canvas->drawString(SkBlendMode_Name(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.setBlendMode(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, tempSurface.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.setBlendMode(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, tempSurface.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 */ 124 sk_sp<SkSurface> possiblyCreateTempSurface(SkCanvas* baseCanvas, int w, int h) { 125 #if SK_SUPPORT_GPU 126 GrContext* context = baseCanvas->getGrContext(); 127 SkImageInfo baseInfo = baseCanvas->imageInfo(); 128 SkImageInfo info = SkImageInfo::Make(w, h, baseInfo.colorType(), baseInfo.alphaType(), 129 baseInfo.refColorSpace()); 130 SkSurfaceProps canvasProps(SkSurfaceProps::kLegacyFontHost_InitType); 131 baseCanvas->getProps(&canvasProps); 132 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, &canvasProps); 133 #else 134 return nullptr; 135 #endif 136 } 137 138 void drawMode(SkCanvas* canvas, 139 int x, int y, int w, int h, 140 const SkPaint& modePaint, SkSurface* surface) { 141 canvas->save(); 142 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 143 144 SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)); 145 146 SkCanvas* modeCanvas; 147 if (nullptr == surface) { 148 canvas->saveLayer(&r, nullptr); 149 modeCanvas = canvas; 150 } else { 151 modeCanvas = surface->getCanvas(); 152 } 153 154 SkPaint bgPaint; 155 bgPaint.setAntiAlias(false); 156 bgPaint.setShader(fBGShader); 157 modeCanvas->drawRect(r, bgPaint); 158 modeCanvas->drawRect(r, modePaint); 159 modeCanvas = nullptr; 160 161 if (nullptr == surface) { 162 canvas->restore(); 163 } else { 164 surface->draw(canvas, 0, 0, nullptr); 165 } 166 167 r.inset(-SK_ScalarHalf, -SK_ScalarHalf); 168 SkPaint borderPaint; 169 borderPaint.setStyle(SkPaint::kStroke_Style); 170 canvas->drawRect(r, borderPaint); 171 172 canvas->restore(); 173 } 174 175 void onOnceBeforeDraw() override { 176 const uint32_t kCheckData[] = { 177 SkPackARGB32(0xFF, 0x42, 0x41, 0x42), 178 SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6), 179 SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6), 180 SkPackARGB32(0xFF, 0x42, 0x41, 0x42) 181 }; 182 SkBitmap bg; 183 bg.allocN32Pixels(2, 2, true); 184 memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData)); 185 186 SkMatrix lm; 187 lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize)); 188 fBGShader = SkShader::MakeBitmapShader(bg, SkShader::kRepeat_TileMode, 189 SkShader::kRepeat_TileMode, &lm); 190 191 SkPaint bmpPaint; 192 const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 }; 193 const SkColor kColors[] = { 194 SK_ColorTRANSPARENT, 0x80800000, 0xF020F060, SK_ColorWHITE 195 }; 196 bmpPaint.setShader(SkGradientShader::MakeRadial(kCenter, 3 * SkIntToScalar(kSize) / 4, 197 kColors, nullptr, SK_ARRAY_COUNT(kColors), 198 SkShader::kRepeat_TileMode)); 199 200 SkBitmap bmp; 201 bmp.allocN32Pixels(kSize, kSize); 202 SkCanvas bmpCanvas(bmp); 203 204 bmpCanvas.clear(SK_ColorTRANSPARENT); 205 SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8, 206 7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8}; 207 bmpCanvas.drawRect(rect, bmpPaint); 208 209 fBmpShader = SkShader::MakeBitmapShader(bmp, SkShader::kClamp_TileMode, 210 SkShader::kClamp_TileMode); 211 } 212 213 enum { 214 kCheckSize = 8, 215 kSize = 30, 216 kTestsPerRow = 15, 217 }; 218 219 sk_sp<SkShader> fBGShader; 220 sk_sp<SkShader> fBmpShader; 221 222 typedef GM INHERITED; 223 }; 224 225 ////////////////////////////////////////////////////////////////////////////// 226 227 DEF_GM(return new Xfermodes3GM;) 228 229 } 230