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 "SkBitmapSource.h"
12#include "SkBlurImageFilter.h"
13#include "SkColorFilter.h"
14#include "SkColorFilterImageFilter.h"
15#include "SkColorMatrixFilter.h"
16#include "SkFlattenableBuffers.h"
17#include "SkMergeImageFilter.h"
18#include "SkMorphologyImageFilter.h"
19#include "SkOnce.h"
20#include "SkTestImageFilters.h"
21#include "SkXfermodeImageFilter.h"
22
23// More closely models how Blink's OffsetFilter works as of 10/23/13. SkOffsetImageFilter doesn't
24// perform a draw and this one does.
25class SimpleOffsetFilter : public SkImageFilter {
26public:
27    SimpleOffsetFilter(SkScalar dx, SkScalar dy, SkImageFilter* input)
28    : SkImageFilter(input), fDX(dx), fDY(dy) {}
29
30    virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
31                               SkBitmap* dst, SkIPoint* offset) SK_OVERRIDE {
32        SkBitmap source = src;
33        SkImageFilter* input = getInput(0);
34        SkIPoint srcOffset = SkIPoint::Make(0, 0);
35        if (NULL != input && !input->filterImage(proxy, src, ctm, &source, &srcOffset)) {
36            return false;
37        }
38
39        SkIRect bounds;
40        source.getBounds(&bounds);
41
42        if (!this->applyCropRect(&bounds, ctm)) {
43            return false;
44        }
45
46        SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
47        SkCanvas canvas(device);
48        SkPaint paint;
49        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
50        canvas.drawBitmap(source, fDX - bounds.left(), fDY - bounds.top(), &paint);
51        *dst = device->accessBitmap(false);
52        offset->fX += bounds.left();
53        offset->fY += bounds.top();
54        return true;
55    }
56
57    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SimpleOffsetFilter);
58
59protected:
60    explicit SimpleOffsetFilter(SkFlattenableReadBuffer& buffer)
61    : SkImageFilter(1, buffer) {
62        fDX = buffer.readScalar();
63        fDY = buffer.readScalar();
64    }
65
66    virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
67        this->SkImageFilter::flatten(buffer);
68        buffer.writeScalar(fDX);
69        buffer.writeScalar(fDY);
70    }
71
72private:
73    SkScalar fDX, fDY;
74};
75
76static void init_flattenable(int*) {
77    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SimpleOffsetFilter)
78}
79
80class ImageFiltersGraphGM : public skiagm::GM {
81public:
82    ImageFiltersGraphGM() : fInitialized(false) {
83        int dummy;
84        SK_DECLARE_STATIC_ONCE(once);
85        SkOnce(&once, init_flattenable, &dummy);
86    }
87
88protected:
89    virtual SkString onShortName() {
90        return SkString("imagefiltersgraph");
91    }
92
93    void make_bitmap() {
94        fBitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
95        fBitmap.allocPixels();
96        SkBitmapDevice device(fBitmap);
97        SkCanvas canvas(&device);
98        canvas.clear(0x00000000);
99        SkPaint paint;
100        paint.setAntiAlias(true);
101        paint.setColor(0xFFFFFFFF);
102        paint.setTextSize(SkIntToScalar(96));
103        const char* str = "e";
104        canvas.drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
105    }
106
107    void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint) {
108        canvas->save();
109        canvas->clipRect(SkRect::MakeXYWH(0, 0,
110            SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
111        canvas->drawBitmap(bitmap, 0, 0, &paint);
112        canvas->restore();
113    }
114
115    virtual SkISize onISize() { return SkISize::Make(500, 150); }
116
117    virtual void onDraw(SkCanvas* canvas) {
118        if (!fInitialized) {
119            this->make_bitmap();
120            fInitialized = true;
121        }
122        canvas->clear(0x00000000);
123        {
124            SkAutoTUnref<SkImageFilter> bitmapSource(new SkBitmapSource(fBitmap));
125            SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED,
126                                                         SkXfermode::kSrcIn_Mode));
127            SkAutoTUnref<SkImageFilter> blur(new SkBlurImageFilter(4.0f, 4.0f, bitmapSource));
128            SkAutoTUnref<SkImageFilter> erode(new SkErodeImageFilter(4, 4, blur));
129            SkAutoTUnref<SkImageFilter> color(SkColorFilterImageFilter::Create(cf, erode));
130            SkAutoTUnref<SkImageFilter> merge(new SkMergeImageFilter(blur, color));
131
132            SkPaint paint;
133            paint.setImageFilter(merge);
134            canvas->drawPaint(paint);
135            canvas->translate(SkIntToScalar(100), 0);
136        }
137        {
138            SkAutoTUnref<SkImageFilter> morph(new SkDilateImageFilter(5, 5));
139
140            SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
141                                    0, SK_Scalar1, 0, 0, 0,
142                                    0, 0, SK_Scalar1, 0, 0,
143                                    0, 0, 0, 0.5f, 0 };
144
145            SkAutoTUnref<SkColorFilter> matrixFilter(new SkColorMatrixFilter(matrix));
146            SkAutoTUnref<SkImageFilter> colorMorph(SkColorFilterImageFilter::Create(matrixFilter, morph));
147            SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
148            SkAutoTUnref<SkImageFilter> blendColor(new SkXfermodeImageFilter(mode, colorMorph));
149
150            SkPaint paint;
151            paint.setImageFilter(blendColor);
152            drawClippedBitmap(canvas, fBitmap, paint);
153            canvas->translate(SkIntToScalar(100), 0);
154        }
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            SkColorMatrixFilter matrixCF(matrix);
161            SkAutoTUnref<SkImageFilter> matrixFilter(SkColorFilterImageFilter::Create(&matrixCF));
162            SimpleOffsetFilter offsetFilter(SkIntToScalar(10), SkIntToScalar(10), matrixFilter);
163
164            SkAutoTUnref<SkXfermode> arith(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0));
165            SkXfermodeImageFilter arithFilter(arith, matrixFilter, &offsetFilter);
166
167            SkPaint paint;
168            paint.setImageFilter(&arithFilter);
169            drawClippedBitmap(canvas, fBitmap, paint);
170            canvas->translate(SkIntToScalar(100), 0);
171        }
172        {
173            SkAutoTUnref<SkImageFilter> blur(new SkBlurImageFilter(
174              SkIntToScalar(10), SkIntToScalar(10)));
175
176            SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcIn_Mode));
177            SkImageFilter::CropRect cropRect(SkRect::MakeWH(SkIntToScalar(95), SkIntToScalar(100)));
178            SkAutoTUnref<SkImageFilter> blend(new SkXfermodeImageFilter(mode, blur, NULL, &cropRect));
179
180            SkPaint paint;
181            paint.setImageFilter(blend);
182            drawClippedBitmap(canvas, fBitmap, paint);
183            canvas->translate(SkIntToScalar(100), 0);
184        }
185    }
186
187private:
188    typedef GM INHERITED;
189    SkBitmap fBitmap;
190    bool fInitialized;
191};
192
193///////////////////////////////////////////////////////////////////////////////
194
195static skiagm::GM* MyFactory(void*) { return new ImageFiltersGraphGM; }
196static skiagm::GMRegistry reg(MyFactory);
197