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 #include "SkTextUtils.h" 16 #include "GrContext.h" 17 18 namespace skiagm { 19 20 /** 21 * This tests drawing device-covering rects with solid colors and bitmap shaders over a 22 * checkerboard background using different xfermodes. 23 */ 24 class Xfermodes3GM : public GM { 25 public: Xfermodes3GM()26 Xfermodes3GM() { this->setBGColor(sk_tool_utils::color_to_565(0xFF70D0E0)); } 27 28 protected: onShortName()29 SkString onShortName() override { 30 return SkString("xfermodes3"); 31 } 32 onISize()33 SkISize onISize() override { 34 return SkISize::Make(630, 1215); 35 } 36 onDraw(SkCanvas * canvas)37 void onDraw(SkCanvas* canvas) override { 38 canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); 39 40 SkFont font(sk_tool_utils::create_portable_typeface()); 41 SkPaint labelP; 42 43 constexpr SkColor kSolidColors[] = { 44 SK_ColorTRANSPARENT, 45 SK_ColorBLUE, 46 0x80808000 47 }; 48 49 constexpr SkColor kBmpAlphas[] = { 50 0xff, 51 0x80, 52 }; 53 54 auto tempSurface(this->makeTempSurface(canvas, kSize, kSize)); 55 56 int test = 0; 57 int x = 0, y = 0; 58 constexpr struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = { 59 {SkPaint::kFill_Style, 0}, 60 {SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2}, 61 }; 62 for (size_t s = 0; s < SK_ARRAY_COUNT(kStrokes); ++s) { 63 for (size_t m = 0; m <= (size_t)SkBlendMode::kLastMode; ++m) { 64 SkBlendMode mode = static_cast<SkBlendMode>(m); 65 canvas->drawString(SkBlendMode_Name(mode), 66 SkIntToScalar(x), 67 SkIntToScalar(y + kSize + 3) + font.getSize(), 68 font, labelP); 69 for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) { 70 SkPaint modePaint; 71 modePaint.setBlendMode(mode); 72 modePaint.setColor(kSolidColors[c]); 73 modePaint.setStyle(kStrokes[s].fStyle); 74 modePaint.setStrokeWidth(kStrokes[s].fWidth); 75 76 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempSurface.get()); 77 78 ++test; 79 x += kSize + 10; 80 if (!(test % kTestsPerRow)) { 81 x = 0; 82 y += kSize + 30; 83 } 84 } 85 for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) { 86 SkPaint modePaint; 87 modePaint.setBlendMode(mode); 88 modePaint.setAlpha(kBmpAlphas[a]); 89 modePaint.setShader(fBmpShader); 90 modePaint.setStyle(kStrokes[s].fStyle); 91 modePaint.setStrokeWidth(kStrokes[s].fWidth); 92 93 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempSurface.get()); 94 95 ++test; 96 x += kSize + 10; 97 if (!(test % kTestsPerRow)) { 98 x = 0; 99 y += kSize + 30; 100 } 101 } 102 } 103 } 104 } 105 106 private: 107 /** 108 * GrContext has optimizations around full rendertarget draws that can be replaced with clears. 109 * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but 110 * saveLayer() uses the texture cache. This means that the actual render target may be larger 111 * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT. 112 * So explicitly create a temporary canvas with dimensions exactly the layer size. 113 */ makeTempSurface(SkCanvas * baseCanvas,int w,int h)114 sk_sp<SkSurface> makeTempSurface(SkCanvas* baseCanvas, int w, int h) { 115 SkImageInfo baseInfo = baseCanvas->imageInfo(); 116 SkImageInfo info = SkImageInfo::Make(w, h, baseInfo.colorType(), baseInfo.alphaType(), 117 baseInfo.refColorSpace()); 118 return baseCanvas->makeSurface(info); 119 } 120 drawMode(SkCanvas * canvas,int x,int y,int w,int h,const SkPaint & modePaint,SkSurface * surface)121 void drawMode(SkCanvas* canvas, 122 int x, int y, int w, int h, 123 const SkPaint& modePaint, SkSurface* surface) { 124 canvas->save(); 125 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 126 127 SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)); 128 129 SkCanvas* modeCanvas; 130 if (nullptr == surface) { 131 canvas->saveLayer(&r, nullptr); 132 canvas->clipRect(r); 133 modeCanvas = canvas; 134 } else { 135 modeCanvas = surface->getCanvas(); 136 } 137 138 SkPaint bgPaint; 139 bgPaint.setAntiAlias(false); 140 bgPaint.setShader(fBGShader); 141 modeCanvas->drawRect(r, bgPaint); 142 modeCanvas->drawRect(r, modePaint); 143 modeCanvas = nullptr; 144 145 if (nullptr == surface) { 146 canvas->restore(); 147 } else { 148 surface->draw(canvas, 0, 0, nullptr); 149 } 150 151 r.inset(-SK_ScalarHalf, -SK_ScalarHalf); 152 SkPaint borderPaint; 153 borderPaint.setStyle(SkPaint::kStroke_Style); 154 canvas->drawRect(r, borderPaint); 155 156 canvas->restore(); 157 } 158 onOnceBeforeDraw()159 void onOnceBeforeDraw() override { 160 const uint32_t kCheckData[] = { 161 SkPackARGB32(0xFF, 0x42, 0x41, 0x42), 162 SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6), 163 SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6), 164 SkPackARGB32(0xFF, 0x42, 0x41, 0x42) 165 }; 166 SkBitmap bg; 167 bg.allocN32Pixels(2, 2, true); 168 memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData)); 169 170 SkMatrix lm; 171 lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize)); 172 fBGShader = SkShader::MakeBitmapShader(bg, SkShader::kRepeat_TileMode, 173 SkShader::kRepeat_TileMode, &lm); 174 175 SkPaint bmpPaint; 176 const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 }; 177 const SkColor kColors[] = { 178 SK_ColorTRANSPARENT, 0x80800000, 0xF020F060, SK_ColorWHITE 179 }; 180 bmpPaint.setShader(SkGradientShader::MakeRadial(kCenter, 3 * SkIntToScalar(kSize) / 4, 181 kColors, nullptr, SK_ARRAY_COUNT(kColors), 182 SkShader::kRepeat_TileMode)); 183 184 SkBitmap bmp; 185 bmp.allocN32Pixels(kSize, kSize); 186 SkCanvas bmpCanvas(bmp); 187 188 bmpCanvas.clear(SK_ColorTRANSPARENT); 189 SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8, 190 7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8}; 191 bmpCanvas.drawRect(rect, bmpPaint); 192 193 fBmpShader = SkShader::MakeBitmapShader(bmp, SkShader::kClamp_TileMode, 194 SkShader::kClamp_TileMode); 195 } 196 197 enum { 198 kCheckSize = 8, 199 kSize = 30, 200 kTestsPerRow = 15, 201 }; 202 203 sk_sp<SkShader> fBGShader; 204 sk_sp<SkShader> fBmpShader; 205 206 typedef GM INHERITED; 207 }; 208 209 ////////////////////////////////////////////////////////////////////////////// 210 211 DEF_GM(return new Xfermodes3GM;) 212 213 } 214