b58f91f4c0599b12d3dcc8d9cc8ea1f9fa325911
[platform/upstream/libSkiaSharp.git] / gm / composeshader.cpp
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 "SkShader.h"
14 #include "SkString.h"
15 #include "SkXfermode.h"
16
17 static sk_sp<SkShader> make_shader(SkXfermode::Mode mode) {
18     SkPoint pts[2];
19     SkColor colors[2];
20
21     pts[0].set(0, 0);
22     pts[1].set(SkIntToScalar(100), 0);
23     colors[0] = SK_ColorRED;
24     colors[1] = SK_ColorBLUE;
25     auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
26
27     pts[0].set(0, 0);
28     pts[1].set(0, SkIntToScalar(100));
29     colors[0] = SK_ColorBLACK;
30     colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
31     auto shaderB = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
32
33     return SkShader::MakeComposeShader(std::move(shaderA), std::move(shaderB),
34                                        SkXfermode::Make(mode));
35 }
36
37 class ComposeShaderGM : public skiagm::GM {
38 public:
39     ComposeShaderGM() {
40         fShader = make_shader(SkXfermode::kDstIn_Mode);
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->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
56         paint.setShader(fShader);
57         canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(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(SkXfermode::kDstIn_Mode),
83             make_shader(SkXfermode::kSrcOver_Mode),
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         auto xfer(SkXfermode::Make(SkXfermode::kDstOver_Mode));
179
180         sk_sp<SkShader> shaders[] = {
181             // gradient should appear over color bitmap
182             SkShader::MakeComposeShader(fLinearGradientShader, fColorBitmapShader, xfer),
183             // gradient should appear over alpha8 bitmap colorized by the paint color
184             SkShader::MakeComposeShader(fLinearGradientShader, fAlpha8BitmapShader, xfer),
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, nullptr);
247     imageInfo = SkImageInfo::Make(width, height,
248             SkColorType::kAlpha_8_SkColorType, kPremul_SkAlphaType);
249     skMask.installPixels(imageInfo, dst8Storage.begin(), width, nullptr, nullptr, nullptr);
250     sk_sp<SkImage> skSrc = SkImage::MakeFromBitmap(skBitmap);
251     sk_sp<SkShader> skSrcShader =
252         skSrc->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
253     sk_sp<SkImage> skMaskImage = SkImage::MakeFromBitmap(skMask);
254     sk_sp<SkShader> skMaskShader = skMaskImage->makeShader(
255         SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
256     sk_sp<SkXfermode> dstInMode = SkXfermode::Make(SkXfermode::kSrcIn_Mode);
257     paint.setShader(
258         SkShader::MakeComposeShader(skMaskShader, skSrcShader, dstInMode));
259     canvas->drawRect(r, paint);
260 }
261
262 //////////////////////////////////////////////////////////////////////////////
263
264 DEF_GM( return new ComposeShaderGM; )
265 DEF_GM( return new ComposeShaderAlphaGM; )
266 DEF_GM( return new ComposeShaderBitmapGM; )