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