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