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.
26 class SimpleOffsetFilter : public SkImageFilter {
27 public:
28     class Registrar {
29     public:
Registrar()30         Registrar() {
31             SkFlattenable::Register("SimpleOffsetFilter",
32                                     SimpleOffsetFilter::CreateProc,
33                                     SimpleOffsetFilter::GetFlattenableType());
34         }
35     };
Create(SkScalar dx,SkScalar dy,SkImageFilter * input)36     static SkImageFilter* Create(SkScalar dx, SkScalar dy, SkImageFilter* input) {
37         return SkNEW_ARGS(SimpleOffsetFilter, (dx, dy, input));
38     }
39 
onFilterImage(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * dst,SkIPoint * offset) const40     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 
68 protected:
flatten(SkWriteBuffer & buffer) const69     void flatten(SkWriteBuffer& buffer) const override {
70         this->INHERITED::flatten(buffer);
71         buffer.writeScalar(fDX);
72         buffer.writeScalar(fDY);
73     }
74 
75 private:
SimpleOffsetFilter(SkScalar dx,SkScalar dy,SkImageFilter * input)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 
84 static SimpleOffsetFilter::Registrar gReg;
85 
CreateProc(SkReadBuffer & buffer)86 SkFlattenable* 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
toString(SkString * str) const94 void SimpleOffsetFilter::toString(SkString* str) const {
95     str->appendf("SimpleOffsetFilter: (");
96     str->append(")");
97 }
98 #endif
99 
100 class ImageFiltersGraphGM : public skiagm::GM {
101 public:
ImageFiltersGraphGM()102     ImageFiltersGraphGM() {}
103 
104 protected:
105 
onShortName()106     virtual SkString onShortName() {
107         return SkString("imagefiltersgraph");
108     }
109 
make_bitmap()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 
drawClippedBitmap(SkCanvas * canvas,const SkBitmap & bitmap,const SkPaint & paint)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 
onISize()131     virtual SkISize onISize() { return SkISize::Make(500, 150); }
132 
onOnceBeforeDraw()133     virtual void onOnceBeforeDraw() {
134         this->make_bitmap();
135     }
136 
onDraw(SkCanvas * canvas)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 
225 private:
226     typedef GM INHERITED;
227     SkBitmap fBitmap;
228 };
229 
230 ///////////////////////////////////////////////////////////////////////////////
231 
MyFactory(void *)232 static skiagm::GM* MyFactory(void*) { return new ImageFiltersGraphGM; }
233 static skiagm::GMRegistry reg(MyFactory);
234