• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
make_shader(SkBlendMode mode)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:
ComposeShaderGM()39     ComposeShaderGM() {
40         fShader = make_shader(SkBlendMode::kDstIn);
41     }
42 
43 protected:
onShortName()44     SkString onShortName() override {
45         return SkString("composeshader");
46     }
47 
onISize()48     SkISize onISize() override {
49         return SkISize::Make(120, 120);
50     }
51 
onDraw(SkCanvas * canvas)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:
ComposeShaderAlphaGM()69     ComposeShaderAlphaGM() {}
70 
71 protected:
onShortName()72     SkString onShortName() override {
73         return SkString("composeshader_alpha");
74     }
75 
onISize()76     SkISize onISize() override {
77         return SkISize::Make(750, 220);
78     }
79 
onDraw(SkCanvas * canvas)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
draw_color_bm(SkBitmap * bm,int length)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
draw_alpha8_bm(SkBitmap * bm,int length)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
make_linear_gradient_shader(int length)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:
ComposeShaderBitmapGM()154     ComposeShaderBitmapGM() {}
155 
156 protected:
onOnceBeforeDraw()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 
onShortName()169     SkString onShortName() override {
170         return SkString("composeshader_bitmap");
171     }
172 
onISize()173     SkISize onISize() override {
174         return SkISize::Make(7 * (squareLength + 5), 2 * (squareLength + 5));
175     }
176 
onDraw(SkCanvas * canvas)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