• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 #include "sk_tool_utils.h"
10 #include "SkBlendModePriv.h"
11 #include "SkCanvas.h"
12 #include "SkImage.h"
13 #include "SkMaskFilter.h"
14 #include "SkPictureRecorder.h"
15 #include "SkShaderMaskFilter.h"
16 #include "SkTextUtils.h"
17 
draw_masked_image(SkCanvas * canvas,const SkImage * image,SkScalar x,SkScalar y,const SkImage * mask,sk_sp<SkMaskFilter> outer,SkBlendMode mode)18 static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y,
19                               const SkImage* mask, sk_sp<SkMaskFilter> outer, SkBlendMode mode) {
20     SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(),
21                                           SkIntToScalar(image->height() / mask->height()));
22     SkPaint paint;
23     auto mf = SkShaderMaskFilter::Make(mask->makeShader(&matrix));
24     if (outer) {
25         mf = SkMaskFilter::MakeCompose(outer, mf);
26     }
27     paint.setMaskFilter(mf);
28     paint.setAntiAlias(true);
29     paint.setBlendMode(mode);
30     canvas->drawImage(image, x, y, &paint);
31 }
32 
33 #include "SkGradientShader.h"
make_shader(const SkRect & r)34 static sk_sp<SkShader> make_shader(const SkRect& r) {
35     const SkPoint pts[] = {
36         { r.fLeft, r.fTop }, { r.fRight, r.fBottom },
37     };
38     const SkColor colors[] = { 0, SK_ColorWHITE };
39     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode);
40 }
41 
42 DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) {
43     SkRect r = { 0, 0, 100, 150 };
44     auto shader = make_shader(r);
45     auto mf = SkShaderMaskFilter::Make(shader);
46 
47     canvas->translate(20, 20);
48     canvas->scale(2, 2);
49 
50     SkPaint paint;
51     paint.setMaskFilter(mf);
52     paint.setColor(SK_ColorRED);
53     paint.setAntiAlias(true);
54     canvas->drawOval(r, paint);
55 }
56 
57 #include "Resources.h"
58 DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 560, 370) {
59     canvas->scale(1.25f, 1.25f);
60 
61     auto image = GetResourceAsImage("images/mandrill_128.png");
62     auto mask = GetResourceAsImage("images/color_wheel.png");
63     if (!image || !mask) {
64         return;
65     }
66     auto blurmf = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5);
67     auto gradmf = SkShaderMaskFilter::Make(make_shader(SkRect::MakeIWH(mask->width(),
68                                                                        mask->height())));
69 
70     const sk_sp<SkMaskFilter> array[] = { nullptr , blurmf, gradmf };
71     for (SkBlendMode mode : {SkBlendMode::kSrcOver, SkBlendMode::kSrcIn}) {
72         canvas->save();
73         for (sk_sp<SkMaskFilter> mf : array) {
74             draw_masked_image(canvas, image.get(), 10, 10, mask.get(), mf, mode);
75             canvas->translate(image->width() + 20.f, 0);
76         }
77         canvas->restore();
78         canvas->translate(0, image->height() + 20.f);
79     }
80 }
81 
82 ///////////////////////////////////////////////////////////////////////////////////////////////////
83 
84 #include "SkPictureRecorder.h"
85 #include "SkPath.h"
86 
make_path_mf(const SkPath & path,unsigned alpha)87 static sk_sp<SkMaskFilter> make_path_mf(const SkPath& path, unsigned alpha) {
88     SkPaint paint;
89     paint.setAntiAlias(true);
90     paint.setAlpha(alpha);
91 
92     SkPictureRecorder recorder;
93     recorder.beginRecording(1000, 1000)->drawPath(path, paint);
94     auto shader = SkShader::MakePictureShader(recorder.finishRecordingAsPicture(),
95                                               SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
96                                               nullptr, nullptr);
97     return SkShaderMaskFilter::Make(shader);
98 }
99 
100 typedef void (*MakePathsProc)(const SkRect&, SkPath*, SkPath*);
101 
102 const char* gCoverageName[] = {
103     "union", "sect", "diff", "rev-diff", "xor"
104 };
105 
106 DEF_SIMPLE_GM(combinemaskfilter, canvas, 560, 510) {
107     const SkRect r = { 0, 0, 100, 100 };
108 
109     SkPaint paint;
110     paint.setColor(SK_ColorRED);
111 
112     SkFont font;
113     font.setSize(20);
114 
115     const SkRect r2 = r.makeOutset(1.5f, 1.5f);
116     SkPaint strokePaint;
117     strokePaint.setStyle(SkPaint::kStroke_Style);
118 
__anonc1cd69450102(const SkRect& r, SkPath* pathA, SkPath* pathB) 119     auto proc0 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
120         pathA->moveTo(r.fLeft, r.fBottom);
121         pathA->lineTo(r.fRight, r.fTop);
122         pathA->lineTo(r.fRight, r.fBottom);
123         pathB->moveTo(r.fLeft, r.fTop);
124         pathB->lineTo(r.fRight, r.fBottom);
125         pathB->lineTo(r.fLeft, r.fBottom);
126     };
__anonc1cd69450202(const SkRect& r, SkPath* pathA, SkPath* pathB) 127     auto proc1 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
128         pathA->addCircle(r.width()*0.25f, r.height()*0.25f, r.width()*0.5f);
129         pathB->addCircle(r.width()*0.75f, r.height()*0.75f, r.width()*0.5f);
130     };
131     MakePathsProc procs[] = { proc0, proc1 };
132 
133     sk_sp<SkMaskFilter> mfA[2], mfB[2];
134     for (int i = 0; i < 2; ++i) {
135         SkPath a, b;
136         procs[i](r, &a, &b);
137         mfA[i] = make_path_mf(a, 1 * 0xFF / 3);
138         mfB[i] = make_path_mf(b, 2 * 0xFF / 3);
139     }
140 
141     canvas->translate(10, 10 + 20);
142     canvas->save();
143     for (int i = 0; i < 5; ++i) {
144         SkTextUtils::DrawString(canvas, gCoverageName[i], r.width()*0.5f, -10, font, SkPaint(),
145                                        SkTextUtils::kCenter_Align);
146 
147         SkCoverageMode cmode = static_cast<SkCoverageMode>(i);
148         canvas->save();
149         // esp. on gpu side, its valuable to exercise modes that do and do-not convolve coverage
150         // with alpha. SrcOver and SrcIn have these properties, but also happen to "look" the same
151         // for this test.
152         const SkBlendMode bmodes[] = { SkBlendMode::kSrcOver, SkBlendMode::kSrcIn };
153         SkASSERT( SkBlendMode_SupportsCoverageAsAlpha(bmodes[0]));  // test as-alpha
154         SkASSERT(!SkBlendMode_SupportsCoverageAsAlpha(bmodes[1]));  // test not-as-alpha
155         for (auto bmode : bmodes) {
156             paint.setBlendMode(bmode);
157             for (int j = 0; j < 2; ++j) {
158                 paint.setMaskFilter(SkMaskFilter::MakeCombine(mfA[j], mfB[j], cmode));
159                 canvas->drawRect(r2, strokePaint);
160                 canvas->drawRect(r, paint);
161                 canvas->translate(0, r.height() + 10);
162             }
163             canvas->translate(0, 40);
164         }
165         canvas->restore();
166         canvas->translate(r.width() + 10, 0);
167     }
168     canvas->restore();
169 }
170 
171 #include "SkSurface.h"
172 #include "SkBlurImageFilter.h"
173 #include "SkMaskFilter.h"
make_circle_image(SkCanvas * canvas,SkScalar radius,int margin)174 static sk_sp<SkImage> make_circle_image(SkCanvas* canvas, SkScalar radius, int margin) {
175     const int n = SkScalarCeilToInt(radius) * 2 + margin * 2;
176     auto surf = sk_tool_utils::makeSurface(canvas, SkImageInfo::MakeN32Premul(n, n));
177     SkPaint paint;
178     paint.setAntiAlias(true);
179     surf->getCanvas()->drawCircle(n * 0.5f, n * 0.5f, radius, paint);
180     return surf->makeImageSnapshot();
181 }
182 
183 DEF_SIMPLE_GM(savelayer_maskfilter, canvas, 450, 675) {
184     auto layerImage = GetResourceAsImage("images/mandrill_128.png");
185     auto maskImage = make_circle_image(canvas, 50, 1);
186     SkRect r = SkRect::MakeWH(102, 102);
187 
188     SkPaint overlayPaint;
189     overlayPaint.setStyle(SkPaint::kStroke_Style);
190 
191     // test that the maskfilter sees these changes to the ctm
192     canvas->translate(10, 10);
193     canvas->scale(2, 2);
194 
195     sk_sp<SkMaskFilter> mfs[] = {
196         SkShaderMaskFilter::Make(maskImage->makeShader()),
197         SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 3.5f),
198         nullptr,
199     };
200     mfs[2] = SkMaskFilter::MakeCompose(mfs[1], mfs[0]);
201 
202     // Important that we test with and without an imagefilter attached to the layer,
203     // as cpu and gpu backends treat these differently (w/ or w/o a SkSpecialImage)
204     const sk_sp<SkImageFilter> imfs[] = {nullptr, SkBlurImageFilter::Make(3.5f, 3.5f, nullptr)};
205 
206     for (auto& mf : mfs) {
207         SkPaint layerPaint;
208         layerPaint.setMaskFilter(mf);
209         canvas->save();
210         for (auto& imf : imfs) {
211             layerPaint.setImageFilter(imf);
212 
213             canvas->saveLayer(&r, &layerPaint);
214             canvas->drawImage(layerImage, 0, 0, nullptr);
215             canvas->restore();
216 
217             // now draw the (approximage) expected bounds of the mask
218             canvas->drawRect(r.makeOutset(1, 1), overlayPaint);
219 
220             canvas->translate(r.width() + 10, 0);
221         }
222         canvas->restore();
223         canvas->translate(0, r.height() + 10);
224     }
225 }
226 
draw_mask(SkCanvas * canvas)227 static void draw_mask(SkCanvas* canvas) {
228     SkPaint p;
229     p.setAntiAlias(true);
230     canvas->drawOval(SkRect::Make(canvas->imageInfo().bounds()), p);
231 }
232 
233 DEF_SIMPLE_GM(shadermaskfilter_localmatrix, canvas, 1500, 1000) {
234     static constexpr SkScalar kSize = 100;
235 
236     using ShaderMakerT = sk_sp<SkShader>(*)(SkCanvas*, const SkMatrix& lm);
237     static const ShaderMakerT gShaderMakers[] = {
__anonc1cd69450302() 238         [](SkCanvas* canvas, const SkMatrix& lm) -> sk_sp<SkShader> {
239             auto surface = sk_tool_utils::makeSurface(canvas,
240                                                       SkImageInfo::MakeN32Premul(kSize, kSize));
241             draw_mask(surface->getCanvas());
242             return surface->makeImageSnapshot()->makeShader(SkShader::kClamp_TileMode,
243                                                             SkShader::kClamp_TileMode, &lm);
244         },
__anonc1cd69450402() 245         [](SkCanvas*, const SkMatrix& lm) -> sk_sp<SkShader> {
246             SkPictureRecorder recorder;
247             draw_mask(recorder.beginRecording(kSize, kSize));
248             return SkShader::MakePictureShader(recorder.finishRecordingAsPicture(),
249                                                SkShader::kClamp_TileMode,
250                                                SkShader::kClamp_TileMode,
251                                                &lm, nullptr);
252         },
253     };
254 
255     struct Config {
256         SkMatrix fCanvasMatrix,
257                  fMaskMatrix,
258                  fShaderMatrix;
259     } gConfigs[] = {
260         { SkMatrix::I(), SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10) },
261         { SkMatrix::MakeScale(2, 2), SkMatrix::I(), SkMatrix::MakeTrans(10, 10) },
262         { SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10), SkMatrix::I() },
263         { SkMatrix::Concat(SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10)),
264           SkMatrix::I(), SkMatrix::I() },
265         { SkMatrix::I(),
266           SkMatrix::Concat(SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10)),
267           SkMatrix::I() },
268         { SkMatrix::I(), SkMatrix::I(),
269           SkMatrix::Concat(SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10)) },
270     };
271 
272     using DrawerT = void(*)(SkCanvas*, const SkRect&, const SkPaint&);
273     static const DrawerT gDrawers[] = {
__anonc1cd69450502() 274         [](SkCanvas* canvas, const SkRect& dest, const SkPaint& mask) {
275             canvas->drawRect(dest, mask);
276         },
__anonc1cd69450602() 277         [](SkCanvas* canvas, const SkRect& dest, const SkPaint& mask) {
278             canvas->saveLayer(&dest, &mask);
279             SkPaint p = mask;
280             p.setMaskFilter(nullptr);
281             canvas->drawPaint(p);
282             canvas->restore();
283         },
284     };
285 
286     SkPaint paint, rectPaint;
287     paint.setColor(0xff00ff00);
288     rectPaint.setStyle(SkPaint::kStroke_Style);
289     rectPaint.setColor(0xffff0000);
290 
291     for (const auto& sm : gShaderMakers) {
292         for (const auto& drawer : gDrawers) {
293             {
294                 SkAutoCanvasRestore acr(canvas, true);
295                 for (const auto& cfg : gConfigs) {
296                     paint.setMaskFilter(SkShaderMaskFilter::Make(sm(canvas, cfg.fShaderMatrix))
297                                         ->makeWithMatrix(cfg.fMaskMatrix));
298                     auto dest = SkRect::MakeWH(kSize, kSize);
299                     SkMatrix::Concat(cfg.fMaskMatrix, cfg.fShaderMatrix).mapRect(&dest);
300 
301                     {
302                         SkAutoCanvasRestore acr(canvas, true);
303                         canvas->concat(cfg.fCanvasMatrix);
304                         drawer(canvas, dest, paint);
305                         canvas->drawRect(dest, rectPaint);
306                     }
307 
308                     canvas->translate(kSize * 2.5f, 0);
309                 }
310             }
311             canvas->translate(0, kSize * 2.5f);
312         }
313 
314     }
315 }
316