1 /* 2 * Copyright 2012 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 10 #include "SkCanvas.h" 11 #include "SkGradientShader.h" 12 #include "SkGraphics.h" 13 #include "SkImage.h" 14 #include "SkShader.h" 15 #include "SkString.h" 16 #include "SkTDArray.h" 17 18 static sk_sp<SkShader> make_shader(SkBlendMode mode) { 19 SkPoint pts[2]; 20 SkColor colors[2]; 21 22 pts[0].set(0, 0); 23 pts[1].set(SkIntToScalar(100), 0); 24 colors[0] = SK_ColorRED; 25 colors[1] = SK_ColorBLUE; 26 auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode); 27 28 pts[0].set(0, 0); 29 pts[1].set(0, SkIntToScalar(100)); 30 colors[0] = SK_ColorBLACK; 31 colors[1] = SkColorSetARGB(0x80, 0, 0, 0); 32 auto shaderB = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode); 33 34 return SkShader::MakeComposeShader(std::move(shaderA), std::move(shaderB), mode); 35 } 36 37 class ComposeShaderGM : public skiagm::GM { 38 public: 39 ComposeShaderGM() { 40 fShader = make_shader(SkBlendMode::kDstIn); 41 } 42 43 protected: 44 SkString onShortName() override { 45 return SkString("composeshader"); 46 } 47 48 SkISize onISize() override { 49 return SkISize::Make(120, 120); 50 } 51 52 void onDraw(SkCanvas* canvas) override { 53 SkPaint paint; 54 paint.setColor(SK_ColorGREEN); 55 canvas->drawRect(SkRect::MakeWH(100, 100), paint); 56 paint.setShader(fShader); 57 canvas->drawRect(SkRect::MakeWH(100, 100), paint); 58 } 59 60 protected: 61 sk_sp<SkShader> fShader; 62 63 private: 64 typedef GM INHERITED ; 65 }; 66 67 class ComposeShaderAlphaGM : public skiagm::GM { 68 public: 69 ComposeShaderAlphaGM() {} 70 71 protected: 72 SkString onShortName() override { 73 return SkString("composeshader_alpha"); 74 } 75 76 SkISize onISize() override { 77 return SkISize::Make(750, 220); 78 } 79 80 void onDraw(SkCanvas* canvas) override { 81 sk_sp<SkShader> shaders[] = { 82 make_shader(SkBlendMode::kDstIn), 83 make_shader(SkBlendMode::kSrcOver), 84 }; 85 86 SkPaint paint; 87 paint.setColor(SK_ColorGREEN); 88 89 const SkRect r = SkRect::MakeXYWH(5, 5, 100, 100); 90 91 for (size_t y = 0; y < SK_ARRAY_COUNT(shaders); ++y) { 92 canvas->save(); 93 for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) { 94 paint.setAlpha(0xFF); 95 paint.setShader(nullptr); 96 canvas->drawRect(r, paint); 97 98 paint.setAlpha(alpha); 99 paint.setShader(shaders[y]); 100 canvas->drawRect(r, paint); 101 102 canvas->translate(r.width() + 5, 0); 103 } 104 canvas->restore(); 105 canvas->translate(0, r.height() + 5); 106 } 107 } 108 109 private: 110 typedef GM INHERITED ; 111 }; 112 113 114 // creates a square bitmap with red background and a green circle in the center 115 static void draw_color_bm(SkBitmap* bm, int length) { 116 SkPaint paint; 117 paint.setColor(SK_ColorGREEN); 118 119 bm->allocN32Pixels(length, length); 120 bm->eraseColor(SK_ColorRED); 121 122 SkCanvas canvas(*bm); 123 canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/2), 124 paint); 125 } 126 127 // creates a square alpha8 bitmap with transparent background and an opaque circle in the center 128 static void draw_alpha8_bm(SkBitmap* bm, int length) { 129 SkPaint circlePaint; 130 circlePaint.setColor(SK_ColorBLACK); 131 132 bm->allocPixels(SkImageInfo::MakeA8(length, length)); 133 bm->eraseColor(SK_ColorTRANSPARENT); 134 135 SkCanvas canvas(*bm); 136 canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/4), 137 circlePaint); 138 } 139 140 // creates a linear gradient shader 141 static sk_sp<SkShader> make_linear_gradient_shader(int length) { 142 SkPoint pts[2]; 143 SkColor colors[2]; 144 pts[0].set(0, 0); 145 pts[1].set(SkIntToScalar(length), 0); 146 colors[0] = SK_ColorBLUE; 147 colors[1] = SkColorSetARGB(0, 0, 0, 0xFF); 148 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode); 149 } 150 151 152 class ComposeShaderBitmapGM : public skiagm::GM { 153 public: 154 ComposeShaderBitmapGM() {} 155 156 protected: 157 void onOnceBeforeDraw() override { 158 draw_color_bm(&fColorBitmap, squareLength); 159 draw_alpha8_bm(&fAlpha8Bitmap, squareLength); 160 SkMatrix s; 161 s.reset(); 162 fColorBitmapShader = SkShader::MakeBitmapShader(fColorBitmap, SkShader::kRepeat_TileMode, 163 SkShader::kRepeat_TileMode, &s); 164 fAlpha8BitmapShader = SkShader::MakeBitmapShader(fAlpha8Bitmap, SkShader::kRepeat_TileMode, 165 SkShader::kRepeat_TileMode, &s); 166 fLinearGradientShader = make_linear_gradient_shader(squareLength); 167 } 168 169 SkString onShortName() override { 170 return SkString("composeshader_bitmap"); 171 } 172 173 SkISize onISize() override { 174 return SkISize::Make(7 * (squareLength + 5), 2 * (squareLength + 5)); 175 } 176 177 void onDraw(SkCanvas* canvas) override { 178 SkBlendMode mode = SkBlendMode::kDstOver; 179 180 sk_sp<SkShader> shaders[] = { 181 // gradient should appear over color bitmap 182 SkShader::MakeComposeShader(fLinearGradientShader, fColorBitmapShader, mode), 183 // gradient should appear over alpha8 bitmap colorized by the paint color 184 SkShader::MakeComposeShader(fLinearGradientShader, fAlpha8BitmapShader, mode), 185 }; 186 187 SkPaint paint; 188 paint.setColor(SK_ColorYELLOW); 189 190 const SkRect r = SkRect::MakeXYWH(0, 0, SkIntToScalar(squareLength), 191 SkIntToScalar(squareLength)); 192 193 for (size_t y = 0; y < SK_ARRAY_COUNT(shaders); ++y) { 194 canvas->save(); 195 for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) { 196 paint.setAlpha(alpha); 197 paint.setShader(shaders[y]); 198 canvas->drawRect(r, paint); 199 200 canvas->translate(r.width() + 5, 0); 201 } 202 canvas->restore(); 203 canvas->translate(0, r.height() + 5); 204 } 205 } 206 207 private: 208 /** This determines the length and width of the bitmaps used in the ComposeShaders. Values 209 * above 20 may cause an SkASSERT to fail in SkSmallAllocator. However, larger values will 210 * work in a release build. You can change this parameter and then compile a release build 211 * to have this GM draw larger bitmaps for easier visual inspection. 212 */ 213 static constexpr int squareLength = 20; 214 215 SkBitmap fColorBitmap; 216 SkBitmap fAlpha8Bitmap; 217 sk_sp<SkShader> fColorBitmapShader; 218 sk_sp<SkShader> fAlpha8BitmapShader; 219 sk_sp<SkShader> fLinearGradientShader; 220 221 typedef GM INHERITED; 222 }; 223 224 DEF_SIMPLE_GM(composeshader_bitmap2, canvas, 200, 200) { 225 int width = 255; 226 int height = 255; 227 SkTDArray<uint8_t> dst8Storage; 228 dst8Storage.setCount(width * height); 229 SkTDArray<uint32_t> dst32Storage; 230 dst32Storage.setCount(width * height * sizeof(int32_t)); 231 for (int y = 0; y < height; ++y) { 232 for (int x = 0; x < width; ++x) { 233 dst8Storage[y * width + x] = (y + x) / 2; 234 dst32Storage[y * width + x] = SkPackARGB32(0xFF, x, y, 0); 235 } 236 } 237 SkPaint paint; 238 paint.setAntiAlias(true); 239 paint.setColor(SK_ColorBLUE); 240 SkRect r = {0, 0, SkIntToScalar(width), SkIntToScalar(height)}; 241 canvas->drawRect(r, paint); 242 SkBitmap skBitmap, skMask; 243 SkImageInfo imageInfo = SkImageInfo::Make(width, height, 244 SkColorType::kN32_SkColorType, kPremul_SkAlphaType); 245 skBitmap.installPixels(imageInfo, dst32Storage.begin(), width * sizeof(int32_t), 246 nullptr, nullptr); 247 imageInfo = SkImageInfo::Make(width, height, 248 SkColorType::kAlpha_8_SkColorType, kPremul_SkAlphaType); 249 skMask.installPixels(imageInfo, dst8Storage.begin(), width, nullptr, nullptr); 250 sk_sp<SkImage> skSrc = SkImage::MakeFromBitmap(skBitmap); 251 sk_sp<SkImage> skMaskImage = SkImage::MakeFromBitmap(skMask); 252 paint.setShader( 253 SkShader::MakeComposeShader(skMaskImage->makeShader(), skSrc->makeShader(), 254 SkBlendMode::kSrcIn)); 255 canvas->drawRect(r, paint); 256 } 257 258 ////////////////////////////////////////////////////////////////////////////// 259 260 DEF_GM( return new ComposeShaderGM; ) 261 DEF_GM( return new ComposeShaderAlphaGM; ) 262 DEF_GM( return new ComposeShaderBitmapGM; ) 263