blob: 70e39efbf5837b6e734b4f34a1a3e5e9deb171df [file] [log] [blame]
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00001
reed@google.com32d25b62011-12-20 16:19:00 +00002#include "SkTestImageFilters.h"
3#include "SkCanvas.h"
reed@google.com76dd2772012-01-05 21:15:07 +00004#include "SkDevice.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00005#include "SkFlattenableBuffers.h"
reed@google.com32d25b62011-12-20 16:19:00 +00006
reed@google.come7639512012-08-07 14:25:44 +00007// Simple helper canvas that "takes ownership" of the provided device, so that
8// when this canvas goes out of scope, so will its device. Could be replaced
9// with the following:
10//
11// SkCanvas canvas(device);
12// SkAutoTUnref<SkDevice> aur(device);
13//
reed@google.com76dd2772012-01-05 21:15:07 +000014class OwnDeviceCanvas : public SkCanvas {
15public:
16 OwnDeviceCanvas(SkDevice* device) : SkCanvas(device) {
17 SkSafeUnref(device);
18 }
19};
20
21bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +000022 const SkMatrix& matrix,
23 SkBitmap* result,
24 SkIPoint* loc) {
25 SkVector vec;
26 matrix.mapVectors(&vec, &fOffset, 1);
27
28 loc->fX += SkScalarRoundToInt(vec.fX);
29 loc->fY += SkScalarRoundToInt(vec.fY);
30 *result = src;
31 return true;
32}
33
34bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
35 SkIRect* dst) {
36 SkVector vec;
37 ctm.mapVectors(&vec, &fOffset, 1);
38
39 *dst = src;
40 dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
41 return true;
42}
43
djsollen@google.com54924242012-03-29 15:18:04 +000044void SkOffsetImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +000045 this->INHERITED::flatten(buffer);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000046 buffer.writePoint(fOffset);
reed@google.com32d25b62011-12-20 16:19:00 +000047}
48
49SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000050 buffer.readPoint(&fOffset);
reed@google.com32d25b62011-12-20 16:19:00 +000051}
52
reed@google.com32d25b62011-12-20 16:19:00 +000053///////////////////////////////////////////////////////////////////////////////
54
55SkComposeImageFilter::~SkComposeImageFilter() {
56 SkSafeUnref(fInner);
57 SkSafeUnref(fOuter);
58}
59
reed@google.com76dd2772012-01-05 21:15:07 +000060bool SkComposeImageFilter::onFilterImage(Proxy* proxy,
61 const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +000062 const SkMatrix& ctm,
63 SkBitmap* result,
64 SkIPoint* loc) {
65 if (!fOuter && !fInner) {
66 return false;
67 }
68
69 if (!fOuter || !fInner) {
reed@google.com76dd2772012-01-05 21:15:07 +000070 return (fOuter ? fOuter : fInner)->filterImage(proxy, src, ctm, result, loc);
reed@google.com32d25b62011-12-20 16:19:00 +000071 }
72
73 SkBitmap tmp;
reed@google.com76dd2772012-01-05 21:15:07 +000074 return fInner->filterImage(proxy, src, ctm, &tmp, loc) &&
75 fOuter->filterImage(proxy, tmp, ctm, result, loc);
reed@google.com32d25b62011-12-20 16:19:00 +000076}
77
78bool SkComposeImageFilter::onFilterBounds(const SkIRect& src,
79 const SkMatrix& ctm,
80 SkIRect* dst) {
81 if (!fOuter && !fInner) {
82 return false;
83 }
84
85 if (!fOuter || !fInner) {
86 return (fOuter ? fOuter : fInner)->filterBounds(src, ctm, dst);
87 }
88
89 SkIRect tmp;
90 return fInner->filterBounds(src, ctm, &tmp) &&
91 fOuter->filterBounds(tmp, ctm, dst);
92}
93
djsollen@google.com54924242012-03-29 15:18:04 +000094void SkComposeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +000095 this->INHERITED::flatten(buffer);
96
97 buffer.writeFlattenable(fOuter);
98 buffer.writeFlattenable(fInner);
99}
100
101SkComposeImageFilter::SkComposeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000102 fOuter = buffer.readFlattenableT<SkImageFilter>();
103 fInner = buffer.readFlattenableT<SkImageFilter>();
reed@google.com32d25b62011-12-20 16:19:00 +0000104}
105
reed@google.com32d25b62011-12-20 16:19:00 +0000106///////////////////////////////////////////////////////////////////////////////
107
108template <typename T> T* SkSafeRefReturn(T* obj) {
109 SkSafeRef(obj);
110 return obj;
111}
112
113void SkMergeImageFilter::initAlloc(int count, bool hasModes) {
114 if (count < 1) {
115 fFilters = NULL;
116 fModes = NULL;
117 fCount = 0;
118 } else {
119 int modeCount = hasModes ? count : 0;
120 size_t size = sizeof(SkImageFilter*) * count + sizeof(uint8_t) * modeCount;
121 if (size <= sizeof(fStorage)) {
122 fFilters = SkTCast<SkImageFilter**>(fStorage);
123 } else {
124 fFilters = SkTCast<SkImageFilter**>(sk_malloc_throw(size));
125 }
126 fModes = hasModes ? SkTCast<uint8_t*>(fFilters + count) : NULL;
127 fCount = count;
128 }
129}
130
131void SkMergeImageFilter::init(SkImageFilter* const filters[], int count,
132 const SkXfermode::Mode modes[]) {
133 this->initAlloc(count, !!modes);
134 for (int i = 0; i < count; ++i) {
135 fFilters[i] = SkSafeRefReturn(filters[i]);
136 if (modes) {
137 fModes[i] = SkToU8(modes[i]);
138 }
139 }
140}
141
142SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
143 SkXfermode::Mode mode) {
144 SkImageFilter* filters[] = { first, second };
145 SkXfermode::Mode modes[] = { mode, mode };
146 this->init(filters, 2, SkXfermode::kSrcOver_Mode == mode ? NULL : modes);
147}
148
149SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* const filters[], int count,
150 const SkXfermode::Mode modes[]) {
151 this->init(filters, count, modes);
152}
153
154SkMergeImageFilter::~SkMergeImageFilter() {
155 for (int i = 0; i < fCount; ++i) {
156 SkSafeUnref(fFilters[i]);
157 }
158
159 if (fFilters != SkTCast<SkImageFilter**>(fStorage)) {
160 sk_free(fFilters);
161 // fModes is allocated in the same block as fFilters, so no need to
162 // separately free it.
163 }
164}
165
166bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
167 SkIRect* dst) {
168 if (fCount < 1) {
169 return false;
170 }
171
172 SkIRect totalBounds;
173
174 for (int i = 0; i < fCount; ++i) {
175 SkImageFilter* filter = fFilters[i];
176 SkIRect r;
177 if (filter) {
178 if (!filter->filterBounds(src, ctm, &r)) {
179 return false;
180 }
181 } else {
182 r = src;
183 }
184 if (0 == i) {
185 totalBounds = r;
186 } else {
187 totalBounds.join(r);
188 }
189 }
190
191 // don't modify dst until now, so we don't accidentally change it in the
192 // loop, but then return false on the next filter.
193 *dst = totalBounds;
194 return true;
195}
196
reed@google.com76dd2772012-01-05 21:15:07 +0000197bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
198 const SkMatrix& ctm,
reed@google.com32d25b62011-12-20 16:19:00 +0000199 SkBitmap* result, SkIPoint* loc) {
200 if (fCount < 1) {
201 return false;
202 }
203
204 const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
205 src.width(), src.height());
206 SkIRect bounds;
207 if (!this->filterBounds(srcBounds, ctm, &bounds)) {
208 return false;
209 }
210
211 const int x0 = bounds.left();
212 const int y0 = bounds.top();
213
reed@google.com76dd2772012-01-05 21:15:07 +0000214 SkDevice* dst = proxy->createDevice(bounds.width(), bounds.height());
215 if (NULL == dst) {
216 return false;
217 }
218 OwnDeviceCanvas canvas(dst);
reed@google.com32d25b62011-12-20 16:19:00 +0000219 SkPaint paint;
220
221 for (int i = 0; i < fCount; ++i) {
222 SkBitmap tmp;
223 const SkBitmap* srcPtr;
224 SkIPoint pos = *loc;
225 SkImageFilter* filter = fFilters[i];
226 if (filter) {
reed@google.com76dd2772012-01-05 21:15:07 +0000227 if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
reed@google.com32d25b62011-12-20 16:19:00 +0000228 return false;
229 }
230 srcPtr = &tmp;
231 } else {
232 srcPtr = &src;
233 }
234
235 if (fModes) {
236 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
237 } else {
238 paint.setXfermode(NULL);
239 }
240 canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
241 }
242
243 loc->set(bounds.left(), bounds.top());
reed@google.com76dd2772012-01-05 21:15:07 +0000244 *result = dst->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000245 return true;
246}
247
djsollen@google.com54924242012-03-29 15:18:04 +0000248void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +0000249 this->INHERITED::flatten(buffer);
250
251 int storedCount = fCount;
252 if (fModes) {
253 // negative count signals we have modes
254 storedCount = -storedCount;
255 }
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000256 buffer.writeInt(storedCount);
reed@google.com32d25b62011-12-20 16:19:00 +0000257
258 if (fCount) {
259 for (int i = 0; i < fCount; ++i) {
260 buffer.writeFlattenable(fFilters[i]);
261 }
262 if (fModes) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000263 buffer.writeByteArray(fModes, fCount * sizeof(fModes[0]));
reed@google.com32d25b62011-12-20 16:19:00 +0000264 }
265 }
266}
267
268SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000269 int storedCount = buffer.readInt();
reed@google.com32d25b62011-12-20 16:19:00 +0000270 this->initAlloc(SkAbs32(storedCount), storedCount < 0);
271
272 for (int i = 0; i < fCount; ++i) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000273 fFilters[i] = buffer.readFlattenableT<SkImageFilter>();
reed@google.com32d25b62011-12-20 16:19:00 +0000274 }
275
276 if (fModes) {
277 SkASSERT(storedCount < 0);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000278 SkASSERT(buffer.getArrayCount() == fCount * sizeof(fModes[0]));
279 buffer.readByteArray(fModes);
reed@google.com32d25b62011-12-20 16:19:00 +0000280 } else {
281 SkASSERT(storedCount >= 0);
282 }
283}
284
reed@google.com32d25b62011-12-20 16:19:00 +0000285///////////////////////////////////////////////////////////////////////////////
286
287#include "SkColorFilter.h"
288
289SkColorFilterImageFilter::~SkColorFilterImageFilter() {
290 SkSafeUnref(fColorFilter);
291}
292
reed@google.com76dd2772012-01-05 21:15:07 +0000293bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +0000294 const SkMatrix& matrix,
295 SkBitmap* result,
296 SkIPoint* loc) {
reed@google.com32d25b62011-12-20 16:19:00 +0000297 SkColorFilter* cf = fColorFilter;
298 if (NULL == cf) {
299 *result = src;
300 return true;
301 }
302
reed@google.com76dd2772012-01-05 21:15:07 +0000303 SkDevice* dev = proxy->createDevice(src.width(), src.height());
304 if (NULL == dev) {
reed@google.com32d25b62011-12-20 16:19:00 +0000305 return false;
306 }
reed@google.com76dd2772012-01-05 21:15:07 +0000307 OwnDeviceCanvas canvas(dev);
308 SkPaint paint;
reed@google.com32d25b62011-12-20 16:19:00 +0000309
reed@google.com76dd2772012-01-05 21:15:07 +0000310 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
311 paint.setColorFilter(fColorFilter);
312 canvas.drawSprite(src, 0, 0, &paint);
313
314 *result = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000315 return true;
316}
317
djsollen@google.com54924242012-03-29 15:18:04 +0000318void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +0000319 this->INHERITED::flatten(buffer);
320
321 buffer.writeFlattenable(fColorFilter);
322}
323
324SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000325 fColorFilter = buffer.readFlattenableT<SkColorFilter>();
reed@google.com32d25b62011-12-20 16:19:00 +0000326}
327
reed@google.com32d25b62011-12-20 16:19:00 +0000328///////////////////////////////////////////////////////////////////////////////
329
reed@google.com76dd2772012-01-05 21:15:07 +0000330bool SkDownSampleImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +0000331 const SkMatrix& matrix,
332 SkBitmap* result, SkIPoint*) {
333 SkScalar scale = fScale;
334 if (scale > SK_Scalar1 || scale <= 0) {
335 return false;
336 }
337
338 int dstW = SkScalarRoundToInt(src.width() * scale);
339 int dstH = SkScalarRoundToInt(src.height() * scale);
340 if (dstW < 1) {
341 dstW = 1;
342 }
343 if (dstH < 1) {
344 dstH = 1;
345 }
reed@google.com76dd2772012-01-05 21:15:07 +0000346
347 SkBitmap tmp;
348
reed@google.com32d25b62011-12-20 16:19:00 +0000349 // downsample
350 {
reed@google.com76dd2772012-01-05 21:15:07 +0000351 SkDevice* dev = proxy->createDevice(dstW, dstH);
352 if (NULL == dev) {
353 return false;
354 }
355 OwnDeviceCanvas canvas(dev);
reed@google.com32d25b62011-12-20 16:19:00 +0000356 SkPaint paint;
reed@google.com76dd2772012-01-05 21:15:07 +0000357
reed@google.com32d25b62011-12-20 16:19:00 +0000358 paint.setFilterBitmap(true);
reed@google.com32d25b62011-12-20 16:19:00 +0000359 canvas.scale(scale, scale);
360 canvas.drawBitmap(src, 0, 0, &paint);
reed@google.com76dd2772012-01-05 21:15:07 +0000361 tmp = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000362 }
reed@google.com76dd2772012-01-05 21:15:07 +0000363
reed@google.com32d25b62011-12-20 16:19:00 +0000364 // upscale
365 {
reed@google.com76dd2772012-01-05 21:15:07 +0000366 SkDevice* dev = proxy->createDevice(src.width(), src.height());
367 if (NULL == dev) {
368 return false;
369 }
370 OwnDeviceCanvas canvas(dev);
371
372 SkRect r = SkRect::MakeWH(SkIntToScalar(src.width()),
373 SkIntToScalar(src.height()));
374 canvas.drawBitmapRect(tmp, NULL, r, NULL);
375 *result = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000376 }
377 return true;
378}
379
djsollen@google.com54924242012-03-29 15:18:04 +0000380void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +0000381 this->INHERITED::flatten(buffer);
382
383 buffer.writeScalar(fScale);
384}
385
386SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
387 fScale = buffer.readScalar();
388}
389
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000390SK_DEFINE_FLATTENABLE_REGISTRAR(SkOffsetImageFilter)
391SK_DEFINE_FLATTENABLE_REGISTRAR(SkComposeImageFilter)
392SK_DEFINE_FLATTENABLE_REGISTRAR(SkMergeImageFilter)
393SK_DEFINE_FLATTENABLE_REGISTRAR(SkColorFilterImageFilter)
394SK_DEFINE_FLATTENABLE_REGISTRAR(SkDownSampleImageFilter)