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