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