blob: a772f64510c137dba9ef7d5b213848e01d509583 [file] [log] [blame]
reed@google.com32d25b62011-12-20 16:19:00 +00001#include "SkTestImageFilters.h"
2#include "SkCanvas.h"
reed@google.com76dd2772012-01-05 21:15:07 +00003#include "SkDevice.h"
reed@google.com32d25b62011-12-20 16:19:00 +00004
reed@google.com76dd2772012-01-05 21:15:07 +00005class OwnDeviceCanvas : public SkCanvas {
6public:
7 OwnDeviceCanvas(SkDevice* device) : SkCanvas(device) {
8 SkSafeUnref(device);
9 }
10};
11
12bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +000013 const SkMatrix& matrix,
14 SkBitmap* result,
15 SkIPoint* loc) {
16 SkVector vec;
17 matrix.mapVectors(&vec, &fOffset, 1);
18
19 loc->fX += SkScalarRoundToInt(vec.fX);
20 loc->fY += SkScalarRoundToInt(vec.fY);
21 *result = src;
22 return true;
23}
24
25bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
26 SkIRect* dst) {
27 SkVector vec;
28 ctm.mapVectors(&vec, &fOffset, 1);
29
30 *dst = src;
31 dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
32 return true;
33}
34
35void SkOffsetImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
36 this->INHERITED::flatten(buffer);
37 buffer.writeScalar(fOffset.x());
38 buffer.writeScalar(fOffset.y());
39}
40
41SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
42 fOffset.fX = buffer.readScalar();
43 fOffset.fY = buffer.readScalar();
44}
45
46SkFlattenable::Factory SkOffsetImageFilter::getFactory() {
47 return CreateProc;
48}
49
50///////////////////////////////////////////////////////////////////////////////
51
52SkComposeImageFilter::~SkComposeImageFilter() {
53 SkSafeUnref(fInner);
54 SkSafeUnref(fOuter);
55}
56
reed@google.com76dd2772012-01-05 21:15:07 +000057bool SkComposeImageFilter::onFilterImage(Proxy* proxy,
58 const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +000059 const SkMatrix& ctm,
60 SkBitmap* result,
61 SkIPoint* loc) {
62 if (!fOuter && !fInner) {
63 return false;
64 }
65
66 if (!fOuter || !fInner) {
reed@google.com76dd2772012-01-05 21:15:07 +000067 return (fOuter ? fOuter : fInner)->filterImage(proxy, src, ctm, result, loc);
reed@google.com32d25b62011-12-20 16:19:00 +000068 }
69
70 SkBitmap tmp;
reed@google.com76dd2772012-01-05 21:15:07 +000071 return fInner->filterImage(proxy, src, ctm, &tmp, loc) &&
72 fOuter->filterImage(proxy, tmp, ctm, result, loc);
reed@google.com32d25b62011-12-20 16:19:00 +000073}
74
75bool SkComposeImageFilter::onFilterBounds(const SkIRect& src,
76 const SkMatrix& ctm,
77 SkIRect* dst) {
78 if (!fOuter && !fInner) {
79 return false;
80 }
81
82 if (!fOuter || !fInner) {
83 return (fOuter ? fOuter : fInner)->filterBounds(src, ctm, dst);
84 }
85
86 SkIRect tmp;
87 return fInner->filterBounds(src, ctm, &tmp) &&
88 fOuter->filterBounds(tmp, ctm, dst);
89}
90
91void SkComposeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
92 this->INHERITED::flatten(buffer);
93
94 buffer.writeFlattenable(fOuter);
95 buffer.writeFlattenable(fInner);
96}
97
98SkComposeImageFilter::SkComposeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
99 fOuter = (SkImageFilter*)buffer.readFlattenable();
100 fInner = (SkImageFilter*)buffer.readFlattenable();
101}
102
103SkFlattenable::Factory SkComposeImageFilter::getFactory() {
104 return CreateProc;
105}
106
107///////////////////////////////////////////////////////////////////////////////
108
109template <typename T> T* SkSafeRefReturn(T* obj) {
110 SkSafeRef(obj);
111 return obj;
112}
113
114void SkMergeImageFilter::initAlloc(int count, bool hasModes) {
115 if (count < 1) {
116 fFilters = NULL;
117 fModes = NULL;
118 fCount = 0;
119 } else {
120 int modeCount = hasModes ? count : 0;
121 size_t size = sizeof(SkImageFilter*) * count + sizeof(uint8_t) * modeCount;
122 if (size <= sizeof(fStorage)) {
123 fFilters = SkTCast<SkImageFilter**>(fStorage);
124 } else {
125 fFilters = SkTCast<SkImageFilter**>(sk_malloc_throw(size));
126 }
127 fModes = hasModes ? SkTCast<uint8_t*>(fFilters + count) : NULL;
128 fCount = count;
129 }
130}
131
132void SkMergeImageFilter::init(SkImageFilter* const filters[], int count,
133 const SkXfermode::Mode modes[]) {
134 this->initAlloc(count, !!modes);
135 for (int i = 0; i < count; ++i) {
136 fFilters[i] = SkSafeRefReturn(filters[i]);
137 if (modes) {
138 fModes[i] = SkToU8(modes[i]);
139 }
140 }
141}
142
143SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
144 SkXfermode::Mode mode) {
145 SkImageFilter* filters[] = { first, second };
146 SkXfermode::Mode modes[] = { mode, mode };
147 this->init(filters, 2, SkXfermode::kSrcOver_Mode == mode ? NULL : modes);
148}
149
150SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* const filters[], int count,
151 const SkXfermode::Mode modes[]) {
152 this->init(filters, count, modes);
153}
154
155SkMergeImageFilter::~SkMergeImageFilter() {
156 for (int i = 0; i < fCount; ++i) {
157 SkSafeUnref(fFilters[i]);
158 }
159
160 if (fFilters != SkTCast<SkImageFilter**>(fStorage)) {
161 sk_free(fFilters);
162 // fModes is allocated in the same block as fFilters, so no need to
163 // separately free it.
164 }
165}
166
167bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
168 SkIRect* dst) {
169 if (fCount < 1) {
170 return false;
171 }
172
173 SkIRect totalBounds;
174
175 for (int i = 0; i < fCount; ++i) {
176 SkImageFilter* filter = fFilters[i];
177 SkIRect r;
178 if (filter) {
179 if (!filter->filterBounds(src, ctm, &r)) {
180 return false;
181 }
182 } else {
183 r = src;
184 }
185 if (0 == i) {
186 totalBounds = r;
187 } else {
188 totalBounds.join(r);
189 }
190 }
191
192 // don't modify dst until now, so we don't accidentally change it in the
193 // loop, but then return false on the next filter.
194 *dst = totalBounds;
195 return true;
196}
197
reed@google.com76dd2772012-01-05 21:15:07 +0000198bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
199 const SkMatrix& ctm,
reed@google.com32d25b62011-12-20 16:19:00 +0000200 SkBitmap* result, SkIPoint* loc) {
201 if (fCount < 1) {
202 return false;
203 }
204
205 const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
206 src.width(), src.height());
207 SkIRect bounds;
208 if (!this->filterBounds(srcBounds, ctm, &bounds)) {
209 return false;
210 }
211
212 const int x0 = bounds.left();
213 const int y0 = bounds.top();
214
reed@google.com76dd2772012-01-05 21:15:07 +0000215 SkDevice* dst = proxy->createDevice(bounds.width(), bounds.height());
216 if (NULL == dst) {
217 return false;
218 }
219 OwnDeviceCanvas canvas(dst);
reed@google.com32d25b62011-12-20 16:19:00 +0000220 SkPaint paint;
221
222 for (int i = 0; i < fCount; ++i) {
223 SkBitmap tmp;
224 const SkBitmap* srcPtr;
225 SkIPoint pos = *loc;
226 SkImageFilter* filter = fFilters[i];
227 if (filter) {
reed@google.com76dd2772012-01-05 21:15:07 +0000228 if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
reed@google.com32d25b62011-12-20 16:19:00 +0000229 return false;
230 }
231 srcPtr = &tmp;
232 } else {
233 srcPtr = &src;
234 }
235
236 if (fModes) {
237 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
238 } else {
239 paint.setXfermode(NULL);
240 }
241 canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
242 }
243
244 loc->set(bounds.left(), bounds.top());
reed@google.com76dd2772012-01-05 21:15:07 +0000245 *result = dst->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000246 return true;
247}
248
249void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
250 this->INHERITED::flatten(buffer);
251
252 int storedCount = fCount;
253 if (fModes) {
254 // negative count signals we have modes
255 storedCount = -storedCount;
256 }
257 buffer.write32(storedCount);
258
259 if (fCount) {
260 for (int i = 0; i < fCount; ++i) {
261 buffer.writeFlattenable(fFilters[i]);
262 }
263 if (fModes) {
264 buffer.write(fModes, fCount * sizeof(fModes[0]));
265 }
266 }
267}
268
269SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
270 int storedCount = buffer.readS32();
271 this->initAlloc(SkAbs32(storedCount), storedCount < 0);
272
273 for (int i = 0; i < fCount; ++i) {
274 fFilters[i] = (SkImageFilter*)buffer.readFlattenable();
275 }
276
277 if (fModes) {
278 SkASSERT(storedCount < 0);
279 buffer.read(fModes, fCount * sizeof(fModes[0]));
280 } else {
281 SkASSERT(storedCount >= 0);
282 }
283}
284
285SkFlattenable::Factory SkMergeImageFilter::getFactory() {
286 return CreateProc;
287}
288
289///////////////////////////////////////////////////////////////////////////////
290
291#include "SkColorFilter.h"
292
293SkColorFilterImageFilter::~SkColorFilterImageFilter() {
294 SkSafeUnref(fColorFilter);
295}
296
reed@google.com76dd2772012-01-05 21:15:07 +0000297bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +0000298 const SkMatrix& matrix,
299 SkBitmap* result,
300 SkIPoint* loc) {
reed@google.com32d25b62011-12-20 16:19:00 +0000301 SkColorFilter* cf = fColorFilter;
302 if (NULL == cf) {
303 *result = src;
304 return true;
305 }
306
reed@google.com76dd2772012-01-05 21:15:07 +0000307 SkDevice* dev = proxy->createDevice(src.width(), src.height());
308 if (NULL == dev) {
reed@google.com32d25b62011-12-20 16:19:00 +0000309 return false;
310 }
reed@google.com76dd2772012-01-05 21:15:07 +0000311 OwnDeviceCanvas canvas(dev);
312 SkPaint paint;
reed@google.com32d25b62011-12-20 16:19:00 +0000313
reed@google.com76dd2772012-01-05 21:15:07 +0000314 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
315 paint.setColorFilter(fColorFilter);
316 canvas.drawSprite(src, 0, 0, &paint);
317
318 *result = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000319 return true;
320}
321
322void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
323 this->INHERITED::flatten(buffer);
324
325 buffer.writeFlattenable(fColorFilter);
326}
327
328SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
329 fColorFilter = (SkColorFilter*)buffer.readFlattenable();
330}
331
332SkFlattenable::Factory SkColorFilterImageFilter::getFactory() {
333 return CreateProc;
334}
335
336///////////////////////////////////////////////////////////////////////////////
337
reed@google.com76dd2772012-01-05 21:15:07 +0000338bool SkDownSampleImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +0000339 const SkMatrix& matrix,
340 SkBitmap* result, SkIPoint*) {
341 SkScalar scale = fScale;
342 if (scale > SK_Scalar1 || scale <= 0) {
343 return false;
344 }
345
346 int dstW = SkScalarRoundToInt(src.width() * scale);
347 int dstH = SkScalarRoundToInt(src.height() * scale);
348 if (dstW < 1) {
349 dstW = 1;
350 }
351 if (dstH < 1) {
352 dstH = 1;
353 }
reed@google.com76dd2772012-01-05 21:15:07 +0000354
355 SkBitmap tmp;
356
reed@google.com32d25b62011-12-20 16:19:00 +0000357 // downsample
358 {
reed@google.com76dd2772012-01-05 21:15:07 +0000359 SkDevice* dev = proxy->createDevice(dstW, dstH);
360 if (NULL == dev) {
361 return false;
362 }
363 OwnDeviceCanvas canvas(dev);
reed@google.com32d25b62011-12-20 16:19:00 +0000364 SkPaint paint;
reed@google.com76dd2772012-01-05 21:15:07 +0000365
reed@google.com32d25b62011-12-20 16:19:00 +0000366 paint.setFilterBitmap(true);
reed@google.com32d25b62011-12-20 16:19:00 +0000367 canvas.scale(scale, scale);
368 canvas.drawBitmap(src, 0, 0, &paint);
reed@google.com76dd2772012-01-05 21:15:07 +0000369 tmp = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000370 }
reed@google.com76dd2772012-01-05 21:15:07 +0000371
reed@google.com32d25b62011-12-20 16:19:00 +0000372 // upscale
373 {
reed@google.com76dd2772012-01-05 21:15:07 +0000374 SkDevice* dev = proxy->createDevice(src.width(), src.height());
375 if (NULL == dev) {
376 return false;
377 }
378 OwnDeviceCanvas canvas(dev);
379
380 SkRect r = SkRect::MakeWH(SkIntToScalar(src.width()),
381 SkIntToScalar(src.height()));
382 canvas.drawBitmapRect(tmp, NULL, r, NULL);
383 *result = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000384 }
385 return true;
386}
387
388void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
389 this->INHERITED::flatten(buffer);
390
391 buffer.writeScalar(fScale);
392}
393
394SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
395 fScale = buffer.readScalar();
396}
397
398SkFlattenable::Factory SkDownSampleImageFilter::getFactory() {
399 return CreateProc;
400}
401