xref: /aosp_15_r20/external/skia/gm/composeshader.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorPriv.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTLazy.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tools/GpuToolUtils.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
34*c8dee2aaSAndroid Build Coastguard Worker 
make_shader(SkBlendMode mode)35*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_shader(SkBlendMode mode) {
36*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[2];
37*c8dee2aaSAndroid Build Coastguard Worker     SkColor colors[2];
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker     pts[0].set(0, 0);
40*c8dee2aaSAndroid Build Coastguard Worker     pts[1].set(SkIntToScalar(100), 0);
41*c8dee2aaSAndroid Build Coastguard Worker     colors[0] = SK_ColorRED;
42*c8dee2aaSAndroid Build Coastguard Worker     colors[1] = SK_ColorBLUE;
43*c8dee2aaSAndroid Build Coastguard Worker     auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker     pts[0].set(0, 0);
46*c8dee2aaSAndroid Build Coastguard Worker     pts[1].set(0, SkIntToScalar(100));
47*c8dee2aaSAndroid Build Coastguard Worker     colors[0] = SK_ColorBLACK;
48*c8dee2aaSAndroid Build Coastguard Worker     colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
49*c8dee2aaSAndroid Build Coastguard Worker     auto shaderB = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker     return SkShaders::Blend(mode, std::move(shaderA), std::move(shaderB));
52*c8dee2aaSAndroid Build Coastguard Worker }
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker class ComposeShaderGM : public skiagm::GM {
55*c8dee2aaSAndroid Build Coastguard Worker protected:
onOnceBeforeDraw()56*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
57*c8dee2aaSAndroid Build Coastguard Worker         fShader = make_shader(SkBlendMode::kDstIn);
58*c8dee2aaSAndroid Build Coastguard Worker     }
59*c8dee2aaSAndroid Build Coastguard Worker 
getName() const60*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("composeshader"); }
61*c8dee2aaSAndroid Build Coastguard Worker 
getISize()62*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return SkISize::Make(120, 120); }
63*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)64*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
65*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
66*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(SK_ColorGREEN);
67*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(SkRect::MakeWH(100, 100), paint);
68*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(fShader);
69*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(SkRect::MakeWH(100, 100), paint);
70*c8dee2aaSAndroid Build Coastguard Worker     }
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker protected:
73*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker private:
76*c8dee2aaSAndroid Build Coastguard Worker     typedef GM INHERITED ;
77*c8dee2aaSAndroid Build Coastguard Worker };
78*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ComposeShaderGM; )
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker class ComposeShaderAlphaGM : public skiagm::GM {
81*c8dee2aaSAndroid Build Coastguard Worker public:
ComposeShaderAlphaGM()82*c8dee2aaSAndroid Build Coastguard Worker     ComposeShaderAlphaGM() {}
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const85*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("composeshader_alpha"); }
86*c8dee2aaSAndroid Build Coastguard Worker 
getISize()87*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return SkISize::Make(750, 220); }
88*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)89*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
90*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkShader> shaders[] = {
91*c8dee2aaSAndroid Build Coastguard Worker             make_shader(SkBlendMode::kDstIn),
92*c8dee2aaSAndroid Build Coastguard Worker             make_shader(SkBlendMode::kSrcOver),
93*c8dee2aaSAndroid Build Coastguard Worker         };
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
96*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(SK_ColorGREEN);
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker         const SkRect r = SkRect::MakeXYWH(5, 5, 100, 100);
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker         for (size_t y = 0; y < std::size(shaders); ++y) {
101*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
102*c8dee2aaSAndroid Build Coastguard Worker             for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) {
103*c8dee2aaSAndroid Build Coastguard Worker                 paint.setAlphaf(1.0f);
104*c8dee2aaSAndroid Build Coastguard Worker                 paint.setShader(nullptr);
105*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawRect(r, paint);
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker                 paint.setAlpha(alpha);
108*c8dee2aaSAndroid Build Coastguard Worker                 paint.setShader(shaders[y]);
109*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawRect(r, paint);
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(r.width() + 5, 0);
112*c8dee2aaSAndroid Build Coastguard Worker             }
113*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
114*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, r.height() + 5);
115*c8dee2aaSAndroid Build Coastguard Worker         }
116*c8dee2aaSAndroid Build Coastguard Worker     }
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker private:
119*c8dee2aaSAndroid Build Coastguard Worker     typedef GM INHERITED ;
120*c8dee2aaSAndroid Build Coastguard Worker };
DEF_GM(return new ComposeShaderAlphaGM;)121*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ComposeShaderAlphaGM; )
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker // creates a square bitmap with red background and a green circle in the center
124*c8dee2aaSAndroid Build Coastguard Worker static void draw_color_bm(SkBitmap* bm, int length) {
125*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
126*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorGREEN);
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     bm->allocN32Pixels(length, length);
129*c8dee2aaSAndroid Build Coastguard Worker     bm->eraseColor(SK_ColorRED);
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas canvas(*bm);
132*c8dee2aaSAndroid Build Coastguard Worker     canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/2),
133*c8dee2aaSAndroid Build Coastguard Worker                       paint);
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker // creates a square alpha8 bitmap with transparent background and an opaque circle in the center
draw_alpha8_bm(SkBitmap * bm,int length)137*c8dee2aaSAndroid Build Coastguard Worker static void draw_alpha8_bm(SkBitmap* bm, int length) {
138*c8dee2aaSAndroid Build Coastguard Worker     SkPaint circlePaint;
139*c8dee2aaSAndroid Build Coastguard Worker     circlePaint.setColor(SK_ColorBLACK);
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker     bm->allocPixels(SkImageInfo::MakeA8(length, length));
142*c8dee2aaSAndroid Build Coastguard Worker     bm->eraseColor(SK_ColorTRANSPARENT);
143*c8dee2aaSAndroid Build Coastguard Worker 
144*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas canvas(*bm);
145*c8dee2aaSAndroid Build Coastguard Worker     canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/4),
146*c8dee2aaSAndroid Build Coastguard Worker                       circlePaint);
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker 
149*c8dee2aaSAndroid Build Coastguard Worker // creates a linear gradient shader
make_linear_gradient_shader(int length)150*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_linear_gradient_shader(int length) {
151*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[2];
152*c8dee2aaSAndroid Build Coastguard Worker     SkColor colors[2];
153*c8dee2aaSAndroid Build Coastguard Worker     pts[0].set(0, 0);
154*c8dee2aaSAndroid Build Coastguard Worker     pts[1].set(SkIntToScalar(length), 0);
155*c8dee2aaSAndroid Build Coastguard Worker     colors[0] = SK_ColorBLUE;
156*c8dee2aaSAndroid Build Coastguard Worker     colors[1] = SkColorSetARGB(0, 0, 0, 0xFF);
157*c8dee2aaSAndroid Build Coastguard Worker     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker 
160*c8dee2aaSAndroid Build Coastguard Worker 
161*c8dee2aaSAndroid Build Coastguard Worker class ComposeShaderBitmapGM : public skiagm::GM {
162*c8dee2aaSAndroid Build Coastguard Worker public:
ComposeShaderBitmapGM(bool use_lm)163*c8dee2aaSAndroid Build Coastguard Worker     ComposeShaderBitmapGM(bool use_lm) : fUseLocalMatrix(use_lm) {}
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const166*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override {
167*c8dee2aaSAndroid Build Coastguard Worker         return SkStringPrintf("composeshader_bitmap%s", fUseLocalMatrix ? "_lm" : "");
168*c8dee2aaSAndroid Build Coastguard Worker     }
169*c8dee2aaSAndroid Build Coastguard Worker 
getISize()170*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override {
171*c8dee2aaSAndroid Build Coastguard Worker         return SkISize::Make(7 * (squareLength + 5), 2 * (squareLength + 5));
172*c8dee2aaSAndroid Build Coastguard Worker     }
173*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)174*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
175*c8dee2aaSAndroid Build Coastguard Worker         if (!fInitialized) {
176*c8dee2aaSAndroid Build Coastguard Worker             draw_color_bm(&fColorBitmap, squareLength);
177*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<SkImage> img = SkImages::RasterFromBitmap(fColorBitmap);
178*c8dee2aaSAndroid Build Coastguard Worker             img = ToolUtils::MakeTextureImage(canvas, std::move(img));
179*c8dee2aaSAndroid Build Coastguard Worker             if (img) {
180*c8dee2aaSAndroid Build Coastguard Worker                 fColorBitmapShader = img->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
181*c8dee2aaSAndroid Build Coastguard Worker                                                      SkSamplingOptions(), SkMatrix::I());
182*c8dee2aaSAndroid Build Coastguard Worker             }
183*c8dee2aaSAndroid Build Coastguard Worker             draw_alpha8_bm(&fAlpha8Bitmap, squareLength);
184*c8dee2aaSAndroid Build Coastguard Worker             img = SkImages::RasterFromBitmap(fAlpha8Bitmap);
185*c8dee2aaSAndroid Build Coastguard Worker             img = ToolUtils::MakeTextureImage(canvas, std::move(img));
186*c8dee2aaSAndroid Build Coastguard Worker             if (img) {
187*c8dee2aaSAndroid Build Coastguard Worker                 fAlpha8BitmapShader = fAlpha8Bitmap.makeShader(SkTileMode::kRepeat,
188*c8dee2aaSAndroid Build Coastguard Worker                                                                SkTileMode::kRepeat,
189*c8dee2aaSAndroid Build Coastguard Worker                                                                SkSamplingOptions(),
190*c8dee2aaSAndroid Build Coastguard Worker                                                                SkMatrix::I());
191*c8dee2aaSAndroid Build Coastguard Worker             }
192*c8dee2aaSAndroid Build Coastguard Worker             fLinearGradientShader = make_linear_gradient_shader(squareLength);
193*c8dee2aaSAndroid Build Coastguard Worker             fInitialized = true;
194*c8dee2aaSAndroid Build Coastguard Worker         }
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker         SkBlendMode mode = SkBlendMode::kDstOver;
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix lm = SkMatrix::Translate(0, squareLength * 0.5f);
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkShader> shaders[] = {
201*c8dee2aaSAndroid Build Coastguard Worker             // gradient should appear over color bitmap
202*c8dee2aaSAndroid Build Coastguard Worker             SkShaders::Blend(mode, fLinearGradientShader, fColorBitmapShader),
203*c8dee2aaSAndroid Build Coastguard Worker             // gradient should appear over alpha8 bitmap colorized by the paint color
204*c8dee2aaSAndroid Build Coastguard Worker             SkShaders::Blend(mode, fLinearGradientShader, fAlpha8BitmapShader),
205*c8dee2aaSAndroid Build Coastguard Worker         };
206*c8dee2aaSAndroid Build Coastguard Worker         if (fUseLocalMatrix) {
207*c8dee2aaSAndroid Build Coastguard Worker             for (unsigned i = 0; i < std::size(shaders); ++i) {
208*c8dee2aaSAndroid Build Coastguard Worker                 shaders[i] = shaders[i] ? shaders[i]->makeWithLocalMatrix(lm) : nullptr;
209*c8dee2aaSAndroid Build Coastguard Worker             }
210*c8dee2aaSAndroid Build Coastguard Worker         }
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
213*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(SK_ColorYELLOW);
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker         const SkRect r = SkRect::MakeIWH(squareLength, squareLength);
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker         for (size_t y = 0; y < std::size(shaders); ++y) {
218*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
219*c8dee2aaSAndroid Build Coastguard Worker             for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) {
220*c8dee2aaSAndroid Build Coastguard Worker                 paint.setAlpha(alpha);
221*c8dee2aaSAndroid Build Coastguard Worker                 paint.setShader(shaders[y]);
222*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawRect(r, paint);
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(r.width() + 5, 0);
225*c8dee2aaSAndroid Build Coastguard Worker             }
226*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
227*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, r.height() + 5);
228*c8dee2aaSAndroid Build Coastguard Worker         }
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker private:
232*c8dee2aaSAndroid Build Coastguard Worker     /** This determines the length and width of the bitmaps used in the ComposeShaders.  Values
233*c8dee2aaSAndroid Build Coastguard Worker      *  above 20 may cause an SkASSERT to fail in SkSmallAllocator. However, larger values will
234*c8dee2aaSAndroid Build Coastguard Worker      *  work in a release build.  You can change this parameter and then compile a release build
235*c8dee2aaSAndroid Build Coastguard Worker      *  to have this GM draw larger bitmaps for easier visual inspection.
236*c8dee2aaSAndroid Build Coastguard Worker      */
237*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int squareLength = 20;
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker     const bool fUseLocalMatrix;
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker     bool fInitialized = false;
242*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap fColorBitmap;
243*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap fAlpha8Bitmap;
244*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fColorBitmapShader;
245*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fAlpha8BitmapShader;
246*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fLinearGradientShader;
247*c8dee2aaSAndroid Build Coastguard Worker 
248*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GM;
249*c8dee2aaSAndroid Build Coastguard Worker };
250*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ComposeShaderBitmapGM(false); )
DEF_GM(return new ComposeShaderBitmapGM (true);)251*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ComposeShaderBitmapGM(true); )
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(composeshader_bitmap2, canvas, 200, 200) {
254*c8dee2aaSAndroid Build Coastguard Worker     int width = 255;
255*c8dee2aaSAndroid Build Coastguard Worker     int height = 255;
256*c8dee2aaSAndroid Build Coastguard Worker     SkTDArray<uint8_t> dst8Storage;
257*c8dee2aaSAndroid Build Coastguard Worker     dst8Storage.resize(width * height);
258*c8dee2aaSAndroid Build Coastguard Worker     SkTDArray<uint32_t> dst32Storage;
259*c8dee2aaSAndroid Build Coastguard Worker     dst32Storage.resize(width * height * sizeof(int32_t));
260*c8dee2aaSAndroid Build Coastguard Worker     for (int y = 0; y < height; ++y) {
261*c8dee2aaSAndroid Build Coastguard Worker         for (int x = 0; x < width; ++x) {
262*c8dee2aaSAndroid Build Coastguard Worker             dst8Storage[y * width + x] = (y + x) / 2;
263*c8dee2aaSAndroid Build Coastguard Worker             dst32Storage[y * width + x] = SkPackARGB32(0xFF, x, y, 0);
264*c8dee2aaSAndroid Build Coastguard Worker         }
265*c8dee2aaSAndroid Build Coastguard Worker     }
266*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
267*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
268*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorBLUE);
269*c8dee2aaSAndroid Build Coastguard Worker     SkRect r = {0, 0, SkIntToScalar(width), SkIntToScalar(height)};
270*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(r, paint);
271*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap skBitmap, skMask;
272*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo imageInfo = SkImageInfo::Make(width, height,
273*c8dee2aaSAndroid Build Coastguard Worker             SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
274*c8dee2aaSAndroid Build Coastguard Worker     skBitmap.installPixels(imageInfo, dst32Storage.begin(), width * sizeof(int32_t),
275*c8dee2aaSAndroid Build Coastguard Worker                            nullptr, nullptr);
276*c8dee2aaSAndroid Build Coastguard Worker     imageInfo = SkImageInfo::Make(width, height,
277*c8dee2aaSAndroid Build Coastguard Worker             SkColorType::kAlpha_8_SkColorType, kPremul_SkAlphaType);
278*c8dee2aaSAndroid Build Coastguard Worker     skMask.installPixels(imageInfo, dst8Storage.begin(), width, nullptr, nullptr);
279*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> skSrc = skBitmap.asImage();
280*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> skMaskImage = skMask.asImage();
281*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(
282*c8dee2aaSAndroid Build Coastguard Worker         SkShaders::Blend(SkBlendMode::kSrcIn,
283*c8dee2aaSAndroid Build Coastguard Worker                          skMaskImage->makeShader(SkSamplingOptions()),
284*c8dee2aaSAndroid Build Coastguard Worker                          skSrc->makeShader(SkSamplingOptions())));
285*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(r, paint);
286*c8dee2aaSAndroid Build Coastguard Worker }
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
289*c8dee2aaSAndroid Build Coastguard Worker 
make_src_shader(SkScalar size)290*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_src_shader(SkScalar size) {
291*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint pts[] = { { 0, 0 }, { 0, size } };
292*c8dee2aaSAndroid Build Coastguard Worker     const SkColor colors[] = { 0xFF0000FF, 0x000000FF };
293*c8dee2aaSAndroid Build Coastguard Worker     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker 
make_dst_shader(SkScalar size)296*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_dst_shader(SkScalar size) {
297*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint pts[] = { { 0, 0 }, { size, 0 } };
298*c8dee2aaSAndroid Build Coastguard Worker     const SkColor colors[] = { SK_ColorRED, 0x00FF0000 };
299*c8dee2aaSAndroid Build Coastguard Worker     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
300*c8dee2aaSAndroid Build Coastguard Worker }
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker const SkScalar gCellSize = 100;
303*c8dee2aaSAndroid Build Coastguard Worker 
draw_cell(SkCanvas * canvas,sk_sp<SkShader> src,sk_sp<SkShader> dst,SkBlendMode mode,SkAlpha alpha)304*c8dee2aaSAndroid Build Coastguard Worker static void draw_cell(SkCanvas* canvas, sk_sp<SkShader> src, sk_sp<SkShader> dst,
305*c8dee2aaSAndroid Build Coastguard Worker                       SkBlendMode mode, SkAlpha alpha) {
306*c8dee2aaSAndroid Build Coastguard Worker     const SkRect r = SkRect::MakeWH(gCellSize, gCellSize);
307*c8dee2aaSAndroid Build Coastguard Worker     SkPaint p;
308*c8dee2aaSAndroid Build Coastguard Worker     p.setAlpha(alpha);
309*c8dee2aaSAndroid Build Coastguard Worker 
310*c8dee2aaSAndroid Build Coastguard Worker     SkAutoCanvasRestore acr(canvas, false);
311*c8dee2aaSAndroid Build Coastguard Worker     canvas->saveLayer(&r, &p);
312*c8dee2aaSAndroid Build Coastguard Worker     p.setAlpha(0xFF);
313*c8dee2aaSAndroid Build Coastguard Worker 
314*c8dee2aaSAndroid Build Coastguard Worker     p.setShader(dst);
315*c8dee2aaSAndroid Build Coastguard Worker     p.setBlendMode(SkBlendMode::kSrc);
316*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(r, p);
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker     p.setShader(src);
319*c8dee2aaSAndroid Build Coastguard Worker     p.setBlendMode(mode);
320*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(r, p);
321*c8dee2aaSAndroid Build Coastguard Worker }
322*c8dee2aaSAndroid Build Coastguard Worker 
draw_composed(SkCanvas * canvas,sk_sp<SkShader> src,sk_sp<SkShader> dst,SkBlendMode mode,SkAlpha alpha)323*c8dee2aaSAndroid Build Coastguard Worker static void draw_composed(SkCanvas* canvas, sk_sp<SkShader> src, sk_sp<SkShader> dst,
324*c8dee2aaSAndroid Build Coastguard Worker                           SkBlendMode mode, SkAlpha alpha) {
325*c8dee2aaSAndroid Build Coastguard Worker     SkPaint p;
326*c8dee2aaSAndroid Build Coastguard Worker     p.setAlpha(alpha);
327*c8dee2aaSAndroid Build Coastguard Worker     p.setShader(SkShaders::Blend(mode, dst, src));
328*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(SkRect::MakeWH(gCellSize, gCellSize), p);
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker 
draw_pair(SkCanvas * canvas,sk_sp<SkShader> src,sk_sp<SkShader> dst,SkBlendMode mode)331*c8dee2aaSAndroid Build Coastguard Worker static void draw_pair(SkCanvas* canvas, sk_sp<SkShader> src, sk_sp<SkShader> dst,
332*c8dee2aaSAndroid Build Coastguard Worker                       SkBlendMode mode) {
333*c8dee2aaSAndroid Build Coastguard Worker     SkAutoCanvasRestore acr(canvas, true);
334*c8dee2aaSAndroid Build Coastguard Worker 
335*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar gap = 4;
336*c8dee2aaSAndroid Build Coastguard Worker     SkRect r = SkRect::MakeWH(2 * gCellSize + gap, 2 * gCellSize + gap);
337*c8dee2aaSAndroid Build Coastguard Worker     r.outset(gap + 1.5f, gap + 1.5f);
338*c8dee2aaSAndroid Build Coastguard Worker     SkPaint p;
339*c8dee2aaSAndroid Build Coastguard Worker     p.setStyle(SkPaint::kStroke_Style);
340*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(r, p); // border
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker     SkAlpha alpha = 0xFF;
343*c8dee2aaSAndroid Build Coastguard Worker     for (int y = 0; y < 2; ++y) {
344*c8dee2aaSAndroid Build Coastguard Worker         draw_cell(canvas, src, dst, mode, alpha);
345*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
346*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(gCellSize + gap, 0);
347*c8dee2aaSAndroid Build Coastguard Worker         draw_composed(canvas, src, dst, mode, alpha);
348*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
349*c8dee2aaSAndroid Build Coastguard Worker 
350*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(0, gCellSize + gap);
351*c8dee2aaSAndroid Build Coastguard Worker         alpha = 0x80;
352*c8dee2aaSAndroid Build Coastguard Worker     }
353*c8dee2aaSAndroid Build Coastguard Worker }
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(composeshader_grid, canvas, 882, 882) {
356*c8dee2aaSAndroid Build Coastguard Worker     auto src = make_src_shader(gCellSize);
357*c8dee2aaSAndroid Build Coastguard Worker     auto dst = make_dst_shader(gCellSize);
358*c8dee2aaSAndroid Build Coastguard Worker 
359*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar margin = 15;
360*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar dx = 2*gCellSize + margin;
361*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar dy = 2*gCellSize + margin;
362*c8dee2aaSAndroid Build Coastguard Worker 
363*c8dee2aaSAndroid Build Coastguard Worker     canvas->translate(margin, margin);
364*c8dee2aaSAndroid Build Coastguard Worker     canvas->save();
365*c8dee2aaSAndroid Build Coastguard Worker     for (int m = 0; m < 16; ++m) {
366*c8dee2aaSAndroid Build Coastguard Worker         SkBlendMode mode = static_cast<SkBlendMode>(m);
367*c8dee2aaSAndroid Build Coastguard Worker         draw_pair(canvas, src, dst, mode);
368*c8dee2aaSAndroid Build Coastguard Worker         if ((m % 4) == 3) {
369*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
370*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, dy);
371*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
372*c8dee2aaSAndroid Build Coastguard Worker         } else {
373*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(dx, 0);
374*c8dee2aaSAndroid Build Coastguard Worker         }
375*c8dee2aaSAndroid Build Coastguard Worker     }
376*c8dee2aaSAndroid Build Coastguard Worker     canvas->restore();
377*c8dee2aaSAndroid Build Coastguard Worker }
378