blob: 2633b0959d427b88b64058f8e61f97914441608c [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.come7639512012-08-07 14:25:44 +00005// Simple helper canvas that "takes ownership" of the provided device, so that
6// when this canvas goes out of scope, so will its device. Could be replaced
7// with the following:
8//
9// SkCanvas canvas(device);
10// SkAutoTUnref<SkDevice> aur(device);
11//
reed@google.com76dd2772012-01-05 21:15:07 +000012class OwnDeviceCanvas : public SkCanvas {
13public:
14 OwnDeviceCanvas(SkDevice* device) : SkCanvas(device) {
15 SkSafeUnref(device);
16 }
17};
18
19bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +000020 const SkMatrix& matrix,
21 SkBitmap* result,
22 SkIPoint* loc) {
23 SkVector vec;
24 matrix.mapVectors(&vec, &fOffset, 1);
25
26 loc->fX += SkScalarRoundToInt(vec.fX);
27 loc->fY += SkScalarRoundToInt(vec.fY);
28 *result = src;
29 return true;
30}
31
32bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
33 SkIRect* dst) {
34 SkVector vec;
35 ctm.mapVectors(&vec, &fOffset, 1);
36
37 *dst = src;
38 dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
39 return true;
40}
41
djsollen@google.com54924242012-03-29 15:18:04 +000042void SkOffsetImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +000043 this->INHERITED::flatten(buffer);
44 buffer.writeScalar(fOffset.x());
45 buffer.writeScalar(fOffset.y());
46}
47
48SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
49 fOffset.fX = buffer.readScalar();
50 fOffset.fY = buffer.readScalar();
51}
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) {
102 fOuter = (SkImageFilter*)buffer.readFlattenable();
103 fInner = (SkImageFilter*)buffer.readFlattenable();
104}
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 }
256 buffer.write32(storedCount);
257
258 if (fCount) {
259 for (int i = 0; i < fCount; ++i) {
260 buffer.writeFlattenable(fFilters[i]);
261 }
262 if (fModes) {
263 buffer.write(fModes, fCount * sizeof(fModes[0]));
264 }
265 }
266}
267
268SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
269 int storedCount = buffer.readS32();
270 this->initAlloc(SkAbs32(storedCount), storedCount < 0);
271
272 for (int i = 0; i < fCount; ++i) {
273 fFilters[i] = (SkImageFilter*)buffer.readFlattenable();
274 }
275
276 if (fModes) {
277 SkASSERT(storedCount < 0);
278 buffer.read(fModes, fCount * sizeof(fModes[0]));
279 } else {
280 SkASSERT(storedCount >= 0);
281 }
282}
283
reed@google.com32d25b62011-12-20 16:19:00 +0000284///////////////////////////////////////////////////////////////////////////////
285
286#include "SkColorFilter.h"
287
288SkColorFilterImageFilter::~SkColorFilterImageFilter() {
289 SkSafeUnref(fColorFilter);
290}
291
reed@google.com76dd2772012-01-05 21:15:07 +0000292bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +0000293 const SkMatrix& matrix,
294 SkBitmap* result,
295 SkIPoint* loc) {
reed@google.com32d25b62011-12-20 16:19:00 +0000296 SkColorFilter* cf = fColorFilter;
297 if (NULL == cf) {
298 *result = src;
299 return true;
300 }
301
reed@google.com76dd2772012-01-05 21:15:07 +0000302 SkDevice* dev = proxy->createDevice(src.width(), src.height());
303 if (NULL == dev) {
reed@google.com32d25b62011-12-20 16:19:00 +0000304 return false;
305 }
reed@google.com76dd2772012-01-05 21:15:07 +0000306 OwnDeviceCanvas canvas(dev);
307 SkPaint paint;
reed@google.com32d25b62011-12-20 16:19:00 +0000308
reed@google.com76dd2772012-01-05 21:15:07 +0000309 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
310 paint.setColorFilter(fColorFilter);
311 canvas.drawSprite(src, 0, 0, &paint);
312
313 *result = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000314 return true;
315}
316
djsollen@google.com54924242012-03-29 15:18:04 +0000317void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +0000318 this->INHERITED::flatten(buffer);
319
320 buffer.writeFlattenable(fColorFilter);
321}
322
323SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
324 fColorFilter = (SkColorFilter*)buffer.readFlattenable();
325}
326
reed@google.com32d25b62011-12-20 16:19:00 +0000327///////////////////////////////////////////////////////////////////////////////
328
reed@google.com76dd2772012-01-05 21:15:07 +0000329bool SkDownSampleImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
reed@google.com32d25b62011-12-20 16:19:00 +0000330 const SkMatrix& matrix,
331 SkBitmap* result, SkIPoint*) {
332 SkScalar scale = fScale;
333 if (scale > SK_Scalar1 || scale <= 0) {
334 return false;
335 }
336
337 int dstW = SkScalarRoundToInt(src.width() * scale);
338 int dstH = SkScalarRoundToInt(src.height() * scale);
339 if (dstW < 1) {
340 dstW = 1;
341 }
342 if (dstH < 1) {
343 dstH = 1;
344 }
reed@google.com76dd2772012-01-05 21:15:07 +0000345
346 SkBitmap tmp;
347
reed@google.com32d25b62011-12-20 16:19:00 +0000348 // downsample
349 {
reed@google.com76dd2772012-01-05 21:15:07 +0000350 SkDevice* dev = proxy->createDevice(dstW, dstH);
351 if (NULL == dev) {
352 return false;
353 }
354 OwnDeviceCanvas canvas(dev);
reed@google.com32d25b62011-12-20 16:19:00 +0000355 SkPaint paint;
reed@google.com76dd2772012-01-05 21:15:07 +0000356
reed@google.com32d25b62011-12-20 16:19:00 +0000357 paint.setFilterBitmap(true);
reed@google.com32d25b62011-12-20 16:19:00 +0000358 canvas.scale(scale, scale);
359 canvas.drawBitmap(src, 0, 0, &paint);
reed@google.com76dd2772012-01-05 21:15:07 +0000360 tmp = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000361 }
reed@google.com76dd2772012-01-05 21:15:07 +0000362
reed@google.com32d25b62011-12-20 16:19:00 +0000363 // upscale
364 {
reed@google.com76dd2772012-01-05 21:15:07 +0000365 SkDevice* dev = proxy->createDevice(src.width(), src.height());
366 if (NULL == dev) {
367 return false;
368 }
369 OwnDeviceCanvas canvas(dev);
370
371 SkRect r = SkRect::MakeWH(SkIntToScalar(src.width()),
372 SkIntToScalar(src.height()));
373 canvas.drawBitmapRect(tmp, NULL, r, NULL);
374 *result = dev->accessBitmap(false);
reed@google.com32d25b62011-12-20 16:19:00 +0000375 }
376 return true;
377}
378
djsollen@google.com54924242012-03-29 15:18:04 +0000379void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@google.com32d25b62011-12-20 16:19:00 +0000380 this->INHERITED::flatten(buffer);
381
382 buffer.writeScalar(fScale);
383}
384
385SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
386 fScale = buffer.readScalar();
387}
388
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000389SK_DEFINE_FLATTENABLE_REGISTRAR(SkOffsetImageFilter)
390SK_DEFINE_FLATTENABLE_REGISTRAR(SkComposeImageFilter)
391SK_DEFINE_FLATTENABLE_REGISTRAR(SkMergeImageFilter)
392SK_DEFINE_FLATTENABLE_REGISTRAR(SkColorFilterImageFilter)
393SK_DEFINE_FLATTENABLE_REGISTRAR(SkDownSampleImageFilter)