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