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 "SkBlurMaskFilter.h"
11 #include "SkCanvas.h"
12 #include "SkImage.h"
13 #include "SkShaderMaskFilter.h"
14 
15 static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y,
16                               const SkImage* mask, sk_sp<SkMaskFilter> outer = nullptr) {
17     SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(),
18                                           SkIntToScalar(image->height() / mask->height()));
19     SkPaint paint;
20     auto mf = SkShaderMaskFilter::Make(mask->makeShader(&matrix));
21     if (outer) {
22         mf = SkMaskFilter::MakeCompose(outer, mf);
23     }
24     paint.setMaskFilter(mf);
25     paint.setAntiAlias(true);
26     canvas->drawImage(image, x, y, &paint);
27 }
28 
29 #include "SkGradientShader.h"
30 static sk_sp<SkShader> make_shader(const SkRect& r) {
31     const SkPoint pts[] = {
32         { r.fLeft, r.fTop }, { r.fRight, r.fBottom },
33     };
34     const SkColor colors[] = { 0, SK_ColorWHITE };
35     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode);
36 }
37 
38 DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) {
39     SkRect r = { 0, 0, 100, 150 };
40     auto shader = make_shader(r);
41     auto mf = SkShaderMaskFilter::Make(shader);
42 
43     canvas->translate(20, 20);
44     canvas->scale(2, 2);
45 
46     SkPaint paint;
47     paint.setMaskFilter(mf);
48     paint.setColor(SK_ColorRED);
49     paint.setAntiAlias(true);
50     canvas->drawOval(r, paint);
51 }
52 
53 #include "Resources.h"
54 DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 512, 512) {
55     canvas->scale(1.25f, 1.25f);
56 
57     auto image = GetResourceAsImage("images/mandrill_128.png");
58     auto mask = GetResourceAsImage("images/color_wheel.png");
59     auto blurmf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 5);
60 
61     canvas->drawImage(image, 10, 10, nullptr);
62     canvas->drawImage(mask, 10 + image->width() + 10.f, 10, nullptr);
63 
64     draw_masked_image(canvas, image.get(), 10, 10 + image->height() + 10.f, mask.get());
65     draw_masked_image(canvas, image.get(), 10 + image->width() + 10.f, 10 + image->height() + 10.f,
66                       mask.get(), blurmf);
67 }
68 
69 ///////////////////////////////////////////////////////////////////////////////////////////////////
70 
71 #include "SkPictureRecorder.h"
72 #include "SkPath.h"
73 
74 static sk_sp<SkMaskFilter> make_path_mf(const SkPath& path, unsigned alpha) {
75     SkPaint paint;
76     paint.setAntiAlias(true);
77     paint.setAlpha(alpha);
78 
79     SkPictureRecorder recorder;
80     recorder.beginRecording(1000, 1000)->drawPath(path, paint);
81     auto shader = SkShader::MakePictureShader(recorder.finishRecordingAsPicture(),
82                                               SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
83                                               nullptr, nullptr);
84     return SkShaderMaskFilter::Make(shader);
85 }
86 
87 typedef void (*MakePathsProc)(const SkRect&, SkPath*, SkPath*);
88 
89 const char* gCoverageName[] = {
90     "union", "sect", "diff", "rev-diff", "xor"
91 };
92 
93 DEF_SIMPLE_GM(combinemaskfilter, canvas, 565, 250) {
94     const SkRect r = { 0, 0, 100, 100 };
95 
96     SkPaint paint;
97     paint.setColor(SK_ColorRED);
98 
99     SkPaint labelP;
100     labelP.setAntiAlias(true);
101     labelP.setTextSize(20);
102     labelP.setTextAlign(SkPaint::kCenter_Align);
103 
104     const SkRect r2 = r.makeOutset(1.5f, 1.5f);
105     SkPaint paint2;
106     paint2.setStyle(SkPaint::kStroke_Style);
107 
108     auto proc0 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
109         pathA->moveTo(r.fLeft, r.fBottom);
110         pathA->lineTo(r.fRight, r.fTop);
111         pathA->lineTo(r.fRight, r.fBottom);
112         pathB->moveTo(r.fLeft, r.fTop);
113         pathB->lineTo(r.fRight, r.fBottom);
114         pathB->lineTo(r.fLeft, r.fBottom);
115     };
116     auto proc1 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
117         pathA->addCircle(r.width()*0.25f, r.height()*0.25f, r.width()*0.5f);
118         pathB->addCircle(r.width()*0.75f, r.height()*0.75f, r.width()*0.5f);
119     };
120     MakePathsProc procs[] = { proc0, proc1 };
121 
122     sk_sp<SkMaskFilter> mfA[2], mfB[2];
123     for (int i = 0; i < 2; ++i) {
124         SkPath a, b;
125         procs[i](r, &a, &b);
126         mfA[i] = make_path_mf(a, 1 * 0xFF / 3);
127         mfB[i] = make_path_mf(b, 2 * 0xFF / 3);
128     }
129 
130     canvas->translate(10, 10 + 20);
131     canvas->save();
132     for (int i = 0; i < 5; ++i) {
133         canvas->drawText(gCoverageName[i], strlen(gCoverageName[i]), r.width()*0.5f, -10, labelP);
134 
135         SkCoverageMode mode = static_cast<SkCoverageMode>(i);
136         canvas->save();
137         for (int j = 0; j < 2; ++j) {
138             paint.setMaskFilter(SkMaskFilter::MakeCombine(mfA[j], mfB[j], mode));
139             canvas->drawRect(r2, paint2);
140             canvas->drawRect(r, paint);
141             canvas->translate(0, r.height() + 10);
142         }
143         canvas->restore();
144         canvas->translate(r.width() + 10, 0);
145     }
146     canvas->restore();
147 }
148