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