1/*
2 * Copyright 2012 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
10#include "SkArithmeticMode.h"
11#include "SkDevice.h"
12#include "SkBitmapSource.h"
13#include "SkBlurImageFilter.h"
14#include "SkColorFilter.h"
15#include "SkColorFilterImageFilter.h"
16#include "SkColorMatrixFilter.h"
17#include "SkReadBuffer.h"
18#include "SkWriteBuffer.h"
19#include "SkMergeImageFilter.h"
20#include "SkMorphologyImageFilter.h"
21#include "SkTestImageFilters.h"
22#include "SkXfermodeImageFilter.h"
23
24// More closely models how Blink's OffsetFilter works as of 10/23/13. SkOffsetImageFilter doesn't
25// perform a draw and this one does.
26class SimpleOffsetFilter : public SkImageFilter {
27public:
28    class Registrar {
29    public:
30        Registrar() {
31            SkFlattenable::Register("SimpleOffsetFilter",
32                                    SimpleOffsetFilter::CreateProc,
33                                    SimpleOffsetFilter::GetFlattenableType());
34        }
35    };
36    static SkImageFilter* Create(SkScalar dx, SkScalar dy, SkImageFilter* input) {
37        return SkNEW_ARGS(SimpleOffsetFilter, (dx, dy, input));
38    }
39
40    virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx,
41                               SkBitmap* dst, SkIPoint* offset) const override {
42        SkBitmap source = src;
43        SkImageFilter* input = getInput(0);
44        SkIPoint srcOffset = SkIPoint::Make(0, 0);
45        if (input && !input->filterImage(proxy, src, ctx, &source, &srcOffset)) {
46            return false;
47        }
48
49        SkIRect bounds;
50        if (!this->applyCropRect(ctx, proxy, source, &srcOffset, &bounds, &source)) {
51            return false;
52        }
53
54        SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
55        SkCanvas canvas(device);
56        SkPaint paint;
57        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
58        canvas.drawBitmap(source, fDX - bounds.left(), fDY - bounds.top(), &paint);
59        *dst = device->accessBitmap(false);
60        offset->fX += bounds.left();
61        offset->fY += bounds.top();
62        return true;
63    }
64
65    SK_TO_STRING_OVERRIDE()
66    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SimpleOffsetFilter);
67
68protected:
69    void flatten(SkWriteBuffer& buffer) const override {
70        this->INHERITED::flatten(buffer);
71        buffer.writeScalar(fDX);
72        buffer.writeScalar(fDY);
73    }
74
75private:
76    SimpleOffsetFilter(SkScalar dx, SkScalar dy, SkImageFilter* input)
77        : SkImageFilter(1, &input), fDX(dx), fDY(dy) {}
78
79    SkScalar fDX, fDY;
80
81    typedef SkImageFilter INHERITED;
82};
83
84static SimpleOffsetFilter::Registrar gReg;
85
86SkFlattenable* SimpleOffsetFilter::CreateProc(SkReadBuffer& buffer) {
87    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
88    SkScalar dx = buffer.readScalar();
89    SkScalar dy = buffer.readScalar();
90    return Create(dx, dy, common.getInput(0));
91}
92
93#ifndef SK_IGNORE_TO_STRING
94void SimpleOffsetFilter::toString(SkString* str) const {
95    str->appendf("SimpleOffsetFilter: (");
96    str->append(")");
97}
98#endif
99
100class ImageFiltersGraphGM : public skiagm::GM {
101public:
102    ImageFiltersGraphGM() {}
103
104protected:
105
106    virtual SkString onShortName() {
107        return SkString("imagefiltersgraph");
108    }
109
110    void make_bitmap() {
111        fBitmap.allocN32Pixels(100, 100);
112        SkCanvas canvas(fBitmap);
113        canvas.clear(SK_ColorTRANSPARENT);
114        SkPaint paint;
115        paint.setAntiAlias(true);
116        sk_tool_utils::set_portable_typeface(&paint);
117        paint.setColor(SK_ColorWHITE);
118        paint.setTextSize(SkIntToScalar(96));
119        const char* str = "e";
120        canvas.drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
121    }
122
123    void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint) {
124        canvas->save();
125        canvas->clipRect(SkRect::MakeXYWH(0, 0,
126            SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
127        canvas->drawBitmap(bitmap, 0, 0, &paint);
128        canvas->restore();
129    }
130
131    virtual SkISize onISize() { return SkISize::Make(500, 150); }
132
133    virtual void onOnceBeforeDraw() {
134        this->make_bitmap();
135    }
136
137    virtual void onDraw(SkCanvas* canvas) {
138        canvas->clear(SK_ColorBLACK);
139        {
140            SkAutoTUnref<SkImageFilter> bitmapSource(SkBitmapSource::Create(fBitmap));
141            SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED,
142                                                         SkXfermode::kSrcIn_Mode));
143            SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(4.0f, 4.0f, bitmapSource));
144            SkAutoTUnref<SkImageFilter> erode(SkErodeImageFilter::Create(4, 4, blur));
145            SkAutoTUnref<SkImageFilter> color(SkColorFilterImageFilter::Create(cf, erode));
146            SkAutoTUnref<SkImageFilter> merge(SkMergeImageFilter::Create(blur, color));
147
148            SkPaint paint;
149            paint.setImageFilter(merge);
150            canvas->drawPaint(paint);
151            canvas->translate(SkIntToScalar(100), 0);
152        }
153        {
154            SkAutoTUnref<SkImageFilter> morph(SkDilateImageFilter::Create(5, 5));
155
156            SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
157                                    0, SK_Scalar1, 0, 0, 0,
158                                    0, 0, SK_Scalar1, 0, 0,
159                                    0, 0, 0, 0.5f, 0 };
160
161            SkAutoTUnref<SkColorFilter> matrixFilter(SkColorMatrixFilter::Create(matrix));
162            SkAutoTUnref<SkImageFilter> colorMorph(SkColorFilterImageFilter::Create(matrixFilter, morph));
163            SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
164            SkAutoTUnref<SkImageFilter> blendColor(SkXfermodeImageFilter::Create(mode, colorMorph));
165
166            SkPaint paint;
167            paint.setImageFilter(blendColor);
168            drawClippedBitmap(canvas, fBitmap, paint);
169            canvas->translate(SkIntToScalar(100), 0);
170        }
171        {
172            SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
173                                    0, SK_Scalar1, 0, 0, 0,
174                                    0, 0, SK_Scalar1, 0, 0,
175                                    0, 0, 0, 0.5f, 0 };
176            SkAutoTUnref<SkColorMatrixFilter> matrixCF(SkColorMatrixFilter::Create(matrix));
177            SkAutoTUnref<SkImageFilter> matrixFilter(SkColorFilterImageFilter::Create(matrixCF));
178            SkAutoTUnref<SkImageFilter> offsetFilter(
179                SimpleOffsetFilter::Create(10.0f, 10.f, matrixFilter));
180
181            SkAutoTUnref<SkXfermode> arith(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0));
182            SkAutoTUnref<SkXfermodeImageFilter> arithFilter(
183                SkXfermodeImageFilter::Create(arith, matrixFilter, offsetFilter));
184
185            SkPaint paint;
186            paint.setImageFilter(arithFilter);
187            drawClippedBitmap(canvas, fBitmap, paint);
188            canvas->translate(SkIntToScalar(100), 0);
189        }
190        {
191            SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(
192              SkIntToScalar(10), SkIntToScalar(10)));
193
194            SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcIn_Mode));
195            SkImageFilter::CropRect cropRect(SkRect::MakeWH(SkIntToScalar(95), SkIntToScalar(100)));
196            SkAutoTUnref<SkImageFilter> blend(
197                SkXfermodeImageFilter::Create(mode, blur, NULL, &cropRect));
198
199            SkPaint paint;
200            paint.setImageFilter(blend);
201            drawClippedBitmap(canvas, fBitmap, paint);
202            canvas->translate(SkIntToScalar(100), 0);
203        }
204        {
205            // Test that crop offsets are absolute, not relative to the parent's crop rect.
206            SkAutoTUnref<SkColorFilter> cf1(SkColorFilter::CreateModeFilter(SK_ColorBLUE,
207                                                                            SkXfermode::kSrcIn_Mode));
208            SkAutoTUnref<SkColorFilter> cf2(SkColorFilter::CreateModeFilter(SK_ColorGREEN,
209                                                                            SkXfermode::kSrcIn_Mode));
210            SkImageFilter::CropRect outerRect(SkRect::MakeXYWH(SkIntToScalar(10), SkIntToScalar(10),
211                                                               SkIntToScalar(80), SkIntToScalar(80)));
212            SkImageFilter::CropRect innerRect(SkRect::MakeXYWH(SkIntToScalar(20), SkIntToScalar(20),
213                                                               SkIntToScalar(60), SkIntToScalar(60)));
214            SkAutoTUnref<SkImageFilter> color1(SkColorFilterImageFilter::Create(cf1, NULL, &outerRect));
215            SkAutoTUnref<SkImageFilter> color2(SkColorFilterImageFilter::Create(cf2, color1, &innerRect));
216
217            SkPaint paint;
218            paint.setImageFilter(color2);
219            paint.setColor(SK_ColorRED);
220            canvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 100), paint);
221            canvas->translate(SkIntToScalar(100), 0);
222        }
223    }
224
225private:
226    typedef GM INHERITED;
227    SkBitmap fBitmap;
228};
229
230///////////////////////////////////////////////////////////////////////////////
231
232static skiagm::GM* MyFactory(void*) { return new ImageFiltersGraphGM; }
233static skiagm::GMRegistry reg(MyFactory);
234