• 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 "SkBlurMaskFilter.h"
12 #include "SkCanvas.h"
13 #include "SkImage.h"
14 #include "SkShaderMaskFilter.h"
15 
draw_masked_image(SkCanvas * canvas,const SkImage * image,SkScalar x,SkScalar y,const SkImage * mask,sk_sp<SkMaskFilter> outer,SkBlendMode mode)16 static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y,
17                               const SkImage* mask, sk_sp<SkMaskFilter> outer, SkBlendMode mode) {
18     SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(),
19                                           SkIntToScalar(image->height() / mask->height()));
20     SkPaint paint;
21     auto mf = SkShaderMaskFilter::Make(mask->makeShader(&matrix));
22     if (outer) {
23         mf = SkMaskFilter::MakeCompose(outer, mf);
24     }
25     paint.setMaskFilter(mf);
26     paint.setAntiAlias(true);
27     paint.setBlendMode(mode);
28     canvas->drawImage(image, x, y, &paint);
29 }
30 
31 #include "SkGradientShader.h"
make_shader(const SkRect & r)32 static sk_sp<SkShader> make_shader(const SkRect& r) {
33     const SkPoint pts[] = {
34         { r.fLeft, r.fTop }, { r.fRight, r.fBottom },
35     };
36     const SkColor colors[] = { 0, SK_ColorWHITE };
37     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode);
38 }
39 
40 DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) {
41     SkRect r = { 0, 0, 100, 150 };
42     auto shader = make_shader(r);
43     auto mf = SkShaderMaskFilter::Make(shader);
44 
45     canvas->translate(20, 20);
46     canvas->scale(2, 2);
47 
48     SkPaint paint;
49     paint.setMaskFilter(mf);
50     paint.setColor(SK_ColorRED);
51     paint.setAntiAlias(true);
52     canvas->drawOval(r, paint);
53 }
54 
55 #include "Resources.h"
56 DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 560, 370) {
57     canvas->scale(1.25f, 1.25f);
58 
59     auto image = GetResourceAsImage("images/mandrill_128.png");
60     auto mask = GetResourceAsImage("images/color_wheel.png");
61     auto blurmf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 5);
62     auto gradmf = SkShaderMaskFilter::Make(make_shader(SkRect::MakeIWH(mask->width(),
63                                                                        mask->height())));
64 
65     const sk_sp<SkMaskFilter> array[] = { nullptr , blurmf, gradmf };
66     for (SkBlendMode mode : {SkBlendMode::kSrcOver, SkBlendMode::kSrcIn}) {
67         canvas->save();
68         for (sk_sp<SkMaskFilter> mf : array) {
69             draw_masked_image(canvas, image.get(), 10, 10, mask.get(), mf, mode);
70             canvas->translate(image->width() + 20.f, 0);
71         }
72         canvas->restore();
73         canvas->translate(0, image->height() + 20.f);
74     }
75 }
76 
77 ///////////////////////////////////////////////////////////////////////////////////////////////////
78 
79 #include "SkPictureRecorder.h"
80 #include "SkPath.h"
81 
make_path_mf(const SkPath & path,unsigned alpha)82 static sk_sp<SkMaskFilter> make_path_mf(const SkPath& path, unsigned alpha) {
83     SkPaint paint;
84     paint.setAntiAlias(true);
85     paint.setAlpha(alpha);
86 
87     SkPictureRecorder recorder;
88     recorder.beginRecording(1000, 1000)->drawPath(path, paint);
89     auto shader = SkShader::MakePictureShader(recorder.finishRecordingAsPicture(),
90                                               SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
91                                               nullptr, nullptr);
92     return SkShaderMaskFilter::Make(shader);
93 }
94 
95 typedef void (*MakePathsProc)(const SkRect&, SkPath*, SkPath*);
96 
97 const char* gCoverageName[] = {
98     "union", "sect", "diff", "rev-diff", "xor"
99 };
100 
101 DEF_SIMPLE_GM(combinemaskfilter, canvas, 560, 510) {
102     const SkRect r = { 0, 0, 100, 100 };
103 
104     SkPaint paint;
105     paint.setColor(SK_ColorRED);
106 
107     SkPaint labelP;
108     labelP.setAntiAlias(true);
109     labelP.setTextSize(20);
110     labelP.setTextAlign(SkPaint::kCenter_Align);
111 
112     const SkRect r2 = r.makeOutset(1.5f, 1.5f);
113     SkPaint strokePaint;
114     strokePaint.setStyle(SkPaint::kStroke_Style);
115 
__anon133ef8220102(const SkRect& r, SkPath* pathA, SkPath* pathB) 116     auto proc0 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
117         pathA->moveTo(r.fLeft, r.fBottom);
118         pathA->lineTo(r.fRight, r.fTop);
119         pathA->lineTo(r.fRight, r.fBottom);
120         pathB->moveTo(r.fLeft, r.fTop);
121         pathB->lineTo(r.fRight, r.fBottom);
122         pathB->lineTo(r.fLeft, r.fBottom);
123     };
__anon133ef8220202(const SkRect& r, SkPath* pathA, SkPath* pathB) 124     auto proc1 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
125         pathA->addCircle(r.width()*0.25f, r.height()*0.25f, r.width()*0.5f);
126         pathB->addCircle(r.width()*0.75f, r.height()*0.75f, r.width()*0.5f);
127     };
128     MakePathsProc procs[] = { proc0, proc1 };
129 
130     sk_sp<SkMaskFilter> mfA[2], mfB[2];
131     for (int i = 0; i < 2; ++i) {
132         SkPath a, b;
133         procs[i](r, &a, &b);
134         mfA[i] = make_path_mf(a, 1 * 0xFF / 3);
135         mfB[i] = make_path_mf(b, 2 * 0xFF / 3);
136     }
137 
138     canvas->translate(10, 10 + 20);
139     canvas->save();
140     for (int i = 0; i < 5; ++i) {
141         canvas->drawText(gCoverageName[i], strlen(gCoverageName[i]), r.width()*0.5f, -10, labelP);
142 
143         SkCoverageMode cmode = static_cast<SkCoverageMode>(i);
144         canvas->save();
145         // esp. on gpu side, its valuable to exercise modes that do and do-not convolve coverage
146         // with alpha. SrcOver and SrcIn have these properties, but also happen to "look" the same
147         // for this test.
148         const SkBlendMode bmodes[] = { SkBlendMode::kSrcOver, SkBlendMode::kSrcIn };
149         SkASSERT( SkBlendMode_SupportsCoverageAsAlpha(bmodes[0]));  // test as-alpha
150         SkASSERT(!SkBlendMode_SupportsCoverageAsAlpha(bmodes[1]));  // test not-as-alpha
151         for (auto bmode : bmodes) {
152             paint.setBlendMode(bmode);
153             for (int j = 0; j < 2; ++j) {
154                 paint.setMaskFilter(SkMaskFilter::MakeCombine(mfA[j], mfB[j], cmode));
155                 canvas->drawRect(r2, strokePaint);
156                 canvas->drawRect(r, paint);
157                 canvas->translate(0, r.height() + 10);
158             }
159             canvas->translate(0, 40);
160         }
161         canvas->restore();
162         canvas->translate(r.width() + 10, 0);
163     }
164     canvas->restore();
165 }
166 
167 #include "SkSurface.h"
168 #include "SkBlurImageFilter.h"
169 #include "SkBlurMaskFilter.h"
make_circle_image(SkCanvas * canvas,SkScalar radius,int margin)170 static sk_sp<SkImage> make_circle_image(SkCanvas* canvas, SkScalar radius, int margin) {
171     const int n = SkScalarCeilToInt(radius) * 2 + margin * 2;
172     auto surf = sk_tool_utils::makeSurface(canvas, SkImageInfo::MakeN32Premul(n, n));
173     SkPaint paint;
174     paint.setAntiAlias(true);
175     surf->getCanvas()->drawCircle(n * 0.5f, n * 0.5f, radius, paint);
176     return surf->makeImageSnapshot();
177 }
178 
179 DEF_SIMPLE_GM(savelayer_maskfilter, canvas, 450, 675) {
180     auto layerImage = GetResourceAsImage("images/mandrill_128.png");
181     auto maskImage = make_circle_image(canvas, 50, 1);
182     SkRect r = SkRect::MakeWH(102, 102);
183 
184     SkPaint overlayPaint;
185     overlayPaint.setStyle(SkPaint::kStroke_Style);
186 
187     // test that the maskfilter sees these changes to the ctm
188     canvas->translate(10, 10);
189     canvas->scale(2, 2);
190 
191     sk_sp<SkMaskFilter> mfs[] = {
192         SkShaderMaskFilter::Make(maskImage->makeShader()),
193         SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 3.5f),
194         nullptr,
195     };
196     mfs[2] = SkMaskFilter::MakeCompose(mfs[1], mfs[0]);
197 
198     // Important that we test with and without an imagefilter attached to the layer,
199     // as cpu and gpu backends treat these differently (w/ or w/o a SkSpecialImage)
200     const sk_sp<SkImageFilter> imfs[] = {nullptr, SkBlurImageFilter::Make(3.5f, 3.5f, nullptr)};
201 
202     for (auto& mf : mfs) {
203         SkPaint layerPaint;
204         layerPaint.setMaskFilter(mf);
205         canvas->save();
206         for (auto& imf : imfs) {
207             layerPaint.setImageFilter(imf);
208 
209             canvas->saveLayer(&r, &layerPaint);
210             canvas->drawImage(layerImage, 0, 0, nullptr);
211             canvas->restore();
212 
213             // now draw the (approximage) expected bounds of the mask
214             canvas->drawRect(r.makeOutset(1, 1), overlayPaint);
215 
216             canvas->translate(r.width() + 10, 0);
217         }
218         canvas->restore();
219         canvas->translate(0, r.height() + 10);
220     }
221 }
222 
223