imagefiltersgraph.cpp revision 72c9faab45124e08c85f70ca38536914862d947c
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 SK_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 SK_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    uint32_t onGetFlags() const SK_OVERRIDE {
106        return kSkipTiled_Flag;
107    }
108
109    virtual SkString onShortName() {
110        return SkString("imagefiltersgraph");
111    }
112
113    void make_bitmap() {
114        fBitmap.allocN32Pixels(100, 100);
115        SkCanvas canvas(fBitmap);
116        canvas.clear(0x00000000);
117        SkPaint paint;
118        paint.setAntiAlias(true);
119        sk_tool_utils::set_portable_typeface(&paint);
120        paint.setColor(0xFFFFFFFF);
121        paint.setTextSize(SkIntToScalar(96));
122        const char* str = "e";
123        canvas.drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
124    }
125
126    void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint) {
127        canvas->save();
128        canvas->clipRect(SkRect::MakeXYWH(0, 0,
129            SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
130        canvas->drawBitmap(bitmap, 0, 0, &paint);
131        canvas->restore();
132    }
133
134    virtual SkISize onISize() { return SkISize::Make(500, 150); }
135
136    virtual void onOnceBeforeDraw() {
137        this->make_bitmap();
138    }
139
140    virtual void onDraw(SkCanvas* canvas) {
141        canvas->clear(0x00000000);
142        {
143            SkAutoTUnref<SkImageFilter> bitmapSource(SkBitmapSource::Create(fBitmap));
144            SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED,
145                                                         SkXfermode::kSrcIn_Mode));
146            SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(4.0f, 4.0f, bitmapSource));
147            SkAutoTUnref<SkImageFilter> erode(SkErodeImageFilter::Create(4, 4, blur));
148            SkAutoTUnref<SkImageFilter> color(SkColorFilterImageFilter::Create(cf, erode));
149            SkAutoTUnref<SkImageFilter> merge(SkMergeImageFilter::Create(blur, color));
150
151            SkPaint paint;
152            paint.setImageFilter(merge);
153            canvas->drawPaint(paint);
154            canvas->translate(SkIntToScalar(100), 0);
155        }
156        {
157            SkAutoTUnref<SkImageFilter> morph(SkDilateImageFilter::Create(5, 5));
158
159            SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
160                                    0, SK_Scalar1, 0, 0, 0,
161                                    0, 0, SK_Scalar1, 0, 0,
162                                    0, 0, 0, 0.5f, 0 };
163
164            SkAutoTUnref<SkColorFilter> matrixFilter(SkColorMatrixFilter::Create(matrix));
165            SkAutoTUnref<SkImageFilter> colorMorph(SkColorFilterImageFilter::Create(matrixFilter, morph));
166            SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
167            SkAutoTUnref<SkImageFilter> blendColor(SkXfermodeImageFilter::Create(mode, colorMorph));
168
169            SkPaint paint;
170            paint.setImageFilter(blendColor);
171            drawClippedBitmap(canvas, fBitmap, paint);
172            canvas->translate(SkIntToScalar(100), 0);
173        }
174        {
175            SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
176                                    0, SK_Scalar1, 0, 0, 0,
177                                    0, 0, SK_Scalar1, 0, 0,
178                                    0, 0, 0, 0.5f, 0 };
179            SkAutoTUnref<SkColorMatrixFilter> matrixCF(SkColorMatrixFilter::Create(matrix));
180            SkAutoTUnref<SkImageFilter> matrixFilter(SkColorFilterImageFilter::Create(matrixCF));
181            SkAutoTUnref<SkImageFilter> offsetFilter(
182                SimpleOffsetFilter::Create(10.0f, 10.f, matrixFilter));
183
184            SkAutoTUnref<SkXfermode> arith(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0));
185            SkAutoTUnref<SkXfermodeImageFilter> arithFilter(
186                SkXfermodeImageFilter::Create(arith, matrixFilter, offsetFilter));
187
188            SkPaint paint;
189            paint.setImageFilter(arithFilter);
190            drawClippedBitmap(canvas, fBitmap, paint);
191            canvas->translate(SkIntToScalar(100), 0);
192        }
193        {
194            SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(
195              SkIntToScalar(10), SkIntToScalar(10)));
196
197            SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcIn_Mode));
198            SkImageFilter::CropRect cropRect(SkRect::MakeWH(SkIntToScalar(95), SkIntToScalar(100)));
199            SkAutoTUnref<SkImageFilter> blend(
200                SkXfermodeImageFilter::Create(mode, blur, NULL, &cropRect));
201
202            SkPaint paint;
203            paint.setImageFilter(blend);
204            drawClippedBitmap(canvas, fBitmap, paint);
205            canvas->translate(SkIntToScalar(100), 0);
206        }
207        {
208            // Test that crop offsets are absolute, not relative to the parent's crop rect.
209            SkAutoTUnref<SkColorFilter> cf1(SkColorFilter::CreateModeFilter(SK_ColorBLUE,
210                                                                            SkXfermode::kSrcIn_Mode));
211            SkAutoTUnref<SkColorFilter> cf2(SkColorFilter::CreateModeFilter(SK_ColorGREEN,
212                                                                            SkXfermode::kSrcIn_Mode));
213            SkImageFilter::CropRect outerRect(SkRect::MakeXYWH(SkIntToScalar(10), SkIntToScalar(10),
214                                                               SkIntToScalar(80), SkIntToScalar(80)));
215            SkImageFilter::CropRect innerRect(SkRect::MakeXYWH(SkIntToScalar(20), SkIntToScalar(20),
216                                                               SkIntToScalar(60), SkIntToScalar(60)));
217            SkAutoTUnref<SkImageFilter> color1(SkColorFilterImageFilter::Create(cf1, NULL, &outerRect));
218            SkAutoTUnref<SkImageFilter> color2(SkColorFilterImageFilter::Create(cf2, color1, &innerRect));
219
220            SkPaint paint;
221            paint.setImageFilter(color2);
222            paint.setColor(0xFFFF0000);
223            canvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 100), paint);
224            canvas->translate(SkIntToScalar(100), 0);
225        }
226    }
227
228private:
229    typedef GM INHERITED;
230    SkBitmap fBitmap;
231};
232
233///////////////////////////////////////////////////////////////////////////////
234
235static skiagm::GM* MyFactory(void*) { return new ImageFiltersGraphGM; }
236static skiagm::GMRegistry reg(MyFactory);
237