1 /*
2  * Copyright 2011 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 "SkCanvas.h"
11 #include "SkColorFilter.h"
12 #include "SkColorPriv.h"
13 #include "SkImageFilterPriv.h"
14 #include "SkShader.h"
15 #include "SkTextUtils.h"
16 
17 #include "SkBlurImageFilter.h"
18 #include "SkColorFilterImageFilter.h"
19 #include "SkDropShadowImageFilter.h"
20 #include "SkSpecialImage.h"
21 
22 class FailImageFilter : public SkImageFilter {
23 public:
Make()24     static sk_sp<SkImageFilter> Make() {
25         return sk_sp<SkImageFilter>(new FailImageFilter);
26     }
27 
28     SK_FLATTENABLE_HOOKS(FailImageFilter)
29 protected:
FailImageFilter()30     FailImageFilter() : INHERITED(nullptr, 0, nullptr) {}
31 
onFilterImage(SkSpecialImage * source,const Context &,SkIPoint * offset) const32     sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
33                                         SkIPoint* offset) const override {
34         return nullptr;
35     }
onMakeColorSpace(SkColorSpaceXformer *) const36     sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
37         return sk_ref_sp(this);
38     }
39 
40 private:
41 
42     typedef SkImageFilter INHERITED;
43 };
44 
CreateProc(SkReadBuffer & buffer)45 sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
46     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
47     return FailImageFilter::Make();
48 }
49 
50 class IdentityImageFilter : public SkImageFilter {
51 public:
Make(sk_sp<SkImageFilter> input)52     static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilter> input) {
53         return sk_sp<SkImageFilter>(new IdentityImageFilter(std::move(input)));
54     }
55 
56 
57     SK_FLATTENABLE_HOOKS(IdentityImageFilter)
58 protected:
onFilterImage(SkSpecialImage * source,const Context &,SkIPoint * offset) const59     sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
60                                         SkIPoint* offset) const override {
61         offset->set(0, 0);
62         return sk_ref_sp<SkSpecialImage>(source);
63     }
onMakeColorSpace(SkColorSpaceXformer *) const64     sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
65         return sk_ref_sp(const_cast<IdentityImageFilter*>(this));
66     }
67 
68 private:
IdentityImageFilter(sk_sp<SkImageFilter> input)69     IdentityImageFilter(sk_sp<SkImageFilter> input) : INHERITED(&input, 1, nullptr) {}
70 
71     typedef SkImageFilter INHERITED;
72 };
73 
74 // Register these image filters as deserializable before main().
75 namespace {
76     static struct Initializer {
Initializer__anonfe9da76a0111::Initializer77         Initializer() {
78             SK_REGISTER_FLATTENABLE(IdentityImageFilter);
79             SK_REGISTER_FLATTENABLE(FailImageFilter);
80         }
81     } initializer;
82 }
83 
CreateProc(SkReadBuffer & buffer)84 sk_sp<SkFlattenable> IdentityImageFilter::CreateProc(SkReadBuffer& buffer) {
85     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
86     return IdentityImageFilter::Make(common.getInput(0));
87 }
88 
89 ///////////////////////////////////////////////////////////////////////////////
90 
draw_paint(SkCanvas * canvas,const SkRect & r,sk_sp<SkImageFilter> imf)91 static void draw_paint(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) {
92     SkPaint paint;
93     paint.setImageFilter(std::move(imf));
94     paint.setColor(SK_ColorGREEN);
95     canvas->save();
96     canvas->clipRect(r);
97     canvas->drawPaint(paint);
98     canvas->restore();
99 }
100 
draw_line(SkCanvas * canvas,const SkRect & r,sk_sp<SkImageFilter> imf)101 static void draw_line(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) {
102     SkPaint paint;
103     paint.setColor(SK_ColorBLUE);
104     paint.setImageFilter(imf);
105     paint.setStrokeWidth(r.width()/10);
106     canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
107 }
108 
draw_rect(SkCanvas * canvas,const SkRect & r,sk_sp<SkImageFilter> imf)109 static void draw_rect(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) {
110     SkPaint paint;
111     paint.setColor(SK_ColorYELLOW);
112     paint.setImageFilter(imf);
113     SkRect rr(r);
114     rr.inset(r.width()/10, r.height()/10);
115     canvas->drawRect(rr, paint);
116 }
117 
draw_path(SkCanvas * canvas,const SkRect & r,sk_sp<SkImageFilter> imf)118 static void draw_path(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) {
119     SkPaint paint;
120     paint.setColor(SK_ColorMAGENTA);
121     paint.setImageFilter(imf);
122     paint.setAntiAlias(true);
123     canvas->drawCircle(r.centerX(), r.centerY(), r.width()*2/5, paint);
124 }
125 
draw_text(SkCanvas * canvas,const SkRect & r,sk_sp<SkImageFilter> imf)126 static void draw_text(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) {
127     SkPaint paint;
128     paint.setImageFilter(imf);
129     paint.setColor(SK_ColorCYAN);
130     SkFont font(sk_tool_utils::create_portable_typeface(), r.height()/2);
131     SkTextUtils::DrawString(canvas, "Text", r.centerX(), r.centerY(), font, paint,
132                             SkTextUtils::kCenter_Align);
133 }
134 
draw_bitmap(SkCanvas * canvas,const SkRect & r,sk_sp<SkImageFilter> imf)135 static void draw_bitmap(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) {
136     SkPaint paint;
137     paint.setImageFilter(std::move(imf));
138 
139     SkIRect bounds;
140     r.roundOut(&bounds);
141 
142     SkBitmap bm;
143     bm.allocN32Pixels(bounds.width(), bounds.height());
144     bm.eraseColor(SK_ColorTRANSPARENT);
145     SkCanvas c(bm);
146     draw_path(&c, r, nullptr);
147 
148     canvas->drawBitmap(bm, 0, 0, &paint);
149 }
150 
151 ///////////////////////////////////////////////////////////////////////////////
152 
153 class ImageFiltersBaseGM : public skiagm::GM {
154 public:
ImageFiltersBaseGM()155     ImageFiltersBaseGM () {}
156 
157 protected:
onShortName()158     SkString onShortName() override {
159         return SkString("imagefiltersbase");
160     }
161 
onISize()162     SkISize onISize() override { return SkISize::Make(700, 500); }
163 
draw_frame(SkCanvas * canvas,const SkRect & r)164     void draw_frame(SkCanvas* canvas, const SkRect& r) {
165         SkPaint paint;
166         paint.setStyle(SkPaint::kStroke_Style);
167         paint.setColor(SK_ColorRED);
168         canvas->drawRect(r, paint);
169     }
170 
onDraw(SkCanvas * canvas)171     void onDraw(SkCanvas* canvas) override {
172         void (*drawProc[])(SkCanvas*, const SkRect&, sk_sp<SkImageFilter>) = {
173             draw_paint,
174             draw_line, draw_rect, draw_path, draw_text,
175             draw_bitmap,
176         };
177 
178         auto cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcIn);
179         sk_sp<SkImageFilter> filters[] = {
180             nullptr,
181             IdentityImageFilter::Make(nullptr),
182             FailImageFilter::Make(),
183             SkColorFilterImageFilter::Make(std::move(cf), nullptr),
184             // The strage 0.29 value tickles an edge case where crop rect calculates
185             // a small border, but the blur really needs no border. This tickels
186             // an msan uninitialized value bug.
187             SkBlurImageFilter::Make(12.0f, 0.29f, nullptr),
188             SkDropShadowImageFilter::Make(
189                                     10.0f, 5.0f, 3.0f, 3.0f, SK_ColorBLUE,
190                                     SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
191                                     nullptr),
192         };
193 
194         SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
195         SkScalar MARGIN = SkIntToScalar(16);
196         SkScalar DX = r.width() + MARGIN;
197         SkScalar DY = r.height() + MARGIN;
198 
199         canvas->translate(MARGIN, MARGIN);
200         for (size_t i = 0; i < SK_ARRAY_COUNT(drawProc); ++i) {
201             canvas->save();
202             for (size_t j = 0; j < SK_ARRAY_COUNT(filters); ++j) {
203                 drawProc[i](canvas, r, filters[j]);
204 
205                 draw_frame(canvas, r);
206                 canvas->translate(0, DY);
207             }
208             canvas->restore();
209             canvas->translate(DX, 0);
210         }
211     }
212 
213 private:
214     typedef GM INHERITED;
215 };
216 DEF_GM( return new ImageFiltersBaseGM; )
217 
218 ///////////////////////////////////////////////////////////////////////////////
219 
220 /*
221  *  Want to test combos of filter and LCD text, to be sure we disable LCD in the presence of
222  *  a filter.
223  */
224 class ImageFiltersTextBaseGM : public skiagm::GM {
225     SkString fSuffix;
226 public:
ImageFiltersTextBaseGM(const char suffix[])227     ImageFiltersTextBaseGM(const char suffix[]) : fSuffix(suffix) {}
228 
229 protected:
onShortName()230     SkString onShortName() override {
231         SkString name;
232         name.printf("%s_%s", "textfilter", fSuffix.c_str());
233         return name;
234     }
235 
onISize()236     SkISize onISize() override { return SkISize::Make(512, 342); }
237 
drawWaterfall(SkCanvas * canvas,const SkPaint & paint)238     void drawWaterfall(SkCanvas* canvas, const SkPaint& paint) {
239         static const SkFont::Edging kEdgings[3] = {
240             SkFont::Edging::kAlias,
241             SkFont::Edging::kAntiAlias,
242             SkFont::Edging::kSubpixelAntiAlias,
243         };
244         SkFont font(sk_tool_utils::create_portable_typeface(), 30);
245 
246         SkAutoCanvasRestore acr(canvas, true);
247         for (SkFont::Edging edging : kEdgings) {
248             font.setEdging(edging);
249             canvas->drawString("Hamburgefon", 0, 0, font, paint);
250             canvas->translate(0, 40);
251         }
252     }
253 
254     virtual void installFilter(SkPaint* paint) = 0;
255 
onDraw(SkCanvas * canvas)256     void onDraw(SkCanvas* canvas) override {
257         SkPaint paint;
258 
259         canvas->translate(20, 40);
260 
261         for (int doSaveLayer = 0; doSaveLayer <= 1; ++doSaveLayer) {
262             SkAutoCanvasRestore acr(canvas, true);
263             for (int useFilter = 0; useFilter <= 1; ++useFilter) {
264                 SkAutoCanvasRestore acr2(canvas, true);
265 
266                 SkPaint paint;
267                 if (useFilter) {
268                     this->installFilter(&paint);
269                 }
270                 if (doSaveLayer) {
271                     canvas->saveLayer(nullptr, &paint);
272                     paint.setImageFilter(nullptr);
273                 }
274                 this->drawWaterfall(canvas, paint);
275 
276                 acr2.restore();
277                 canvas->translate(250, 0);
278             }
279             acr.restore();
280             canvas->translate(0, 200);
281         }
282     }
283 
284 private:
285     typedef GM INHERITED;
286 };
287 
288 class ImageFiltersText_IF : public ImageFiltersTextBaseGM {
289 public:
ImageFiltersText_IF()290     ImageFiltersText_IF() : ImageFiltersTextBaseGM("image") {}
291 
installFilter(SkPaint * paint)292     void installFilter(SkPaint* paint) override {
293         paint->setImageFilter(SkBlurImageFilter::Make(1.5f, 1.5f, nullptr));
294     }
295 };
296 DEF_GM( return new ImageFiltersText_IF; )
297 
298 class ImageFiltersText_CF : public ImageFiltersTextBaseGM {
299 public:
ImageFiltersText_CF()300     ImageFiltersText_CF() : ImageFiltersTextBaseGM("color") {}
301 
installFilter(SkPaint * paint)302     void installFilter(SkPaint* paint) override {
303         paint->setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorBLUE, SkBlendMode::kSrcIn));
304     }
305 };
306 DEF_GM( return new ImageFiltersText_CF; )
307