1/*
2 * Copyright 2012 The Android Open Source Project
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 "SkImageFilter.h"
9
10#include "SkBitmap.h"
11#include "SkDevice.h"
12#include "SkReadBuffer.h"
13#include "SkWriteBuffer.h"
14#include "SkRect.h"
15#include "SkTDynamicHash.h"
16#include "SkValidationUtils.h"
17#if SK_SUPPORT_GPU
18#include "GrContext.h"
19#include "SkGrPixelRef.h"
20#include "SkGr.h"
21#endif
22
23SkImageFilter::Cache* gExternalCache;
24
25SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
26  : fInputCount(inputCount),
27    fInputs(new SkImageFilter*[inputCount]),
28    fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
29    for (int i = 0; i < inputCount; ++i) {
30        fInputs[i] = inputs[i];
31        SkSafeRef(fInputs[i]);
32    }
33}
34
35SkImageFilter::SkImageFilter(SkImageFilter* input, const CropRect* cropRect)
36  : fInputCount(1),
37    fInputs(new SkImageFilter*[1]),
38    fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
39    fInputs[0] = input;
40    SkSafeRef(fInputs[0]);
41}
42
43SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect)
44  : fInputCount(2), fInputs(new SkImageFilter*[2]),
45    fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
46    fInputs[0] = input1;
47    fInputs[1] = input2;
48    SkSafeRef(fInputs[0]);
49    SkSafeRef(fInputs[1]);
50}
51
52SkImageFilter::~SkImageFilter() {
53    for (int i = 0; i < fInputCount; i++) {
54        SkSafeUnref(fInputs[i]);
55    }
56    delete[] fInputs;
57}
58
59SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer) {
60    fInputCount = buffer.readInt();
61    if (buffer.validate((fInputCount >= 0) && ((inputCount < 0) || (fInputCount == inputCount)))) {
62        fInputs = new SkImageFilter*[fInputCount];
63        for (int i = 0; i < fInputCount; i++) {
64            if (buffer.readBool()) {
65                fInputs[i] = buffer.readImageFilter();
66            } else {
67                fInputs[i] = NULL;
68            }
69            if (!buffer.isValid()) {
70                fInputCount = i; // Do not use fInputs past that point in the destructor
71                break;
72            }
73        }
74        SkRect rect;
75        buffer.readRect(&rect);
76        if (buffer.isValid() && buffer.validate(SkIsValidRect(rect))) {
77            uint32_t flags = buffer.readUInt();
78            fCropRect = CropRect(rect, flags);
79        }
80    } else {
81        fInputCount = 0;
82        fInputs = NULL;
83    }
84}
85
86void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
87    buffer.writeInt(fInputCount);
88    for (int i = 0; i < fInputCount; i++) {
89        SkImageFilter* input = getInput(i);
90        buffer.writeBool(input != NULL);
91        if (input != NULL) {
92            buffer.writeFlattenable(input);
93        }
94    }
95    buffer.writeRect(fCropRect.rect());
96    buffer.writeUInt(fCropRect.flags());
97}
98
99bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
100                                const Context& context,
101                                SkBitmap* result, SkIPoint* offset) const {
102    Cache* cache = context.cache();
103    SkASSERT(result);
104    SkASSERT(offset);
105    SkASSERT(cache);
106    if (cache->get(this, result, offset)) {
107        return true;
108    }
109    /*
110     *  Give the proxy first shot at the filter. If it returns false, ask
111     *  the filter to do it.
112     */
113    if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
114        this->onFilterImage(proxy, src, context, result, offset)) {
115        cache->set(this, *result, *offset);
116        return true;
117    }
118    return false;
119}
120
121bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
122                                 SkIRect* dst) const {
123    SkASSERT(&src);
124    SkASSERT(dst);
125    if (SkImageFilter::GetExternalCache()) {
126        /*
127         *  When the external cache is active, do not intersect the saveLayer
128         *  bounds with the clip bounds. This is so that the cached result
129         *  is always the full size of the primitive's bounds,
130         *  regardless of the clip active on first draw.
131         */
132        *dst = SkIRect::MakeLargest();
133        return true;
134    }
135    return this->onFilterBounds(src, ctm, dst);
136}
137
138void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
139    if (0 == fInputCount) {
140        *dst = src;
141        return;
142    }
143    if (this->getInput(0)) {
144        this->getInput(0)->computeFastBounds(src, dst);
145    } else {
146        *dst = src;
147    }
148    for (int i = 1; i < fInputCount; i++) {
149        SkImageFilter* input = this->getInput(i);
150        if (input) {
151            SkRect bounds;
152            input->computeFastBounds(src, &bounds);
153            dst->join(bounds);
154        } else {
155            dst->join(src);
156        }
157    }
158}
159
160bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
161                                  SkBitmap*, SkIPoint*) const {
162    return false;
163}
164
165bool SkImageFilter::canFilterImageGPU() const {
166    return this->asNewEffect(NULL, NULL, SkMatrix::I(), SkIRect());
167}
168
169bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
170                                   SkBitmap* result, SkIPoint* offset) const {
171#if SK_SUPPORT_GPU
172    SkBitmap input = src;
173    SkASSERT(fInputCount == 1);
174    SkIPoint srcOffset = SkIPoint::Make(0, 0);
175    if (this->getInput(0) &&
176        !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
177        return false;
178    }
179    GrTexture* srcTexture = input.getTexture();
180    SkIRect bounds;
181    if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
182        return false;
183    }
184    SkRect srcRect = SkRect::Make(bounds);
185    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
186    GrContext* context = srcTexture->getContext();
187
188    GrTextureDesc desc;
189    desc.fFlags = kRenderTarget_GrTextureFlagBit,
190    desc.fWidth = bounds.width();
191    desc.fHeight = bounds.height();
192    desc.fConfig = kRGBA_8888_GrPixelConfig;
193
194    GrAutoScratchTexture dst(context, desc);
195    GrContext::AutoMatrix am;
196    am.setIdentity(context);
197    GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
198    GrContext::AutoClip acs(context, dstRect);
199    GrEffectRef* effect;
200    offset->fX = bounds.left();
201    offset->fY = bounds.top();
202    bounds.offset(-srcOffset);
203    SkMatrix matrix(ctx.ctm());
204    matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
205    this->asNewEffect(&effect, srcTexture, matrix, bounds);
206    SkASSERT(effect);
207    SkAutoUnref effectRef(effect);
208    GrPaint paint;
209    paint.addColorEffect(effect);
210    context->drawRectToRect(paint, dstRect, srcRect);
211
212    SkAutoTUnref<GrTexture> resultTex(dst.detach());
213    WrapTexture(resultTex, bounds.width(), bounds.height(), result);
214    return true;
215#else
216    return false;
217#endif
218}
219
220bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
221                                  const SkIPoint& srcOffset, SkIRect* bounds) const {
222    SkIRect srcBounds;
223    src.getBounds(&srcBounds);
224    srcBounds.offset(srcOffset);
225    SkRect cropRect;
226    ctx.ctm().mapRect(&cropRect, fCropRect.rect());
227    SkIRect cropRectI;
228    cropRect.roundOut(&cropRectI);
229    uint32_t flags = fCropRect.flags();
230    if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft;
231    if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop;
232    if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight;
233    if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom;
234    if (!srcBounds.intersect(ctx.clipBounds())) {
235        return false;
236    }
237    *bounds = srcBounds;
238    return true;
239}
240
241bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
242                                  SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
243    SkIRect srcBounds;
244    src.getBounds(&srcBounds);
245    srcBounds.offset(*srcOffset);
246    SkRect cropRect;
247    ctx.ctm().mapRect(&cropRect, fCropRect.rect());
248    SkIRect cropRectI;
249    cropRect.roundOut(&cropRectI);
250    uint32_t flags = fCropRect.flags();
251    *bounds = srcBounds;
252    if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft;
253    if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop;
254    if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight;
255    if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom;
256    if (!bounds->intersect(ctx.clipBounds())) {
257        return false;
258    }
259    if (srcBounds.contains(*bounds)) {
260        *dst = src;
261        return true;
262    } else {
263        SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
264        if (!device) {
265            return false;
266        }
267        SkCanvas canvas(device);
268        canvas.clear(0x00000000);
269        canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
270        *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
271        *dst = device->accessBitmap(false);
272        return true;
273    }
274}
275
276bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
277                                   SkIRect* dst) const {
278    if (fInputCount < 1) {
279        return false;
280    }
281
282    SkIRect bounds;
283    for (int i = 0; i < fInputCount; ++i) {
284        SkImageFilter* filter = this->getInput(i);
285        SkIRect rect = src;
286        if (filter && !filter->filterBounds(src, ctm, &rect)) {
287            return false;
288        }
289        if (0 == i) {
290            bounds = rect;
291        } else {
292            bounds.join(rect);
293        }
294    }
295
296    // don't modify dst until now, so we don't accidentally change it in the
297    // loop, but then return false on the next filter.
298    *dst = bounds;
299    return true;
300}
301
302bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&, const SkIRect&) const {
303    return false;
304}
305
306bool SkImageFilter::asColorFilter(SkColorFilter**) const {
307    return false;
308}
309
310void SkImageFilter::SetExternalCache(Cache* cache) {
311    SkRefCnt_SafeAssign(gExternalCache, cache);
312}
313
314SkImageFilter::Cache* SkImageFilter::GetExternalCache() {
315    return gExternalCache;
316}
317
318#if SK_SUPPORT_GPU
319
320void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
321    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
322    result->setInfo(info);
323    result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
324}
325
326bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy,
327                                      const SkBitmap& src, const Context& ctx,
328                                      SkBitmap* result, SkIPoint* offset) const {
329    // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
330    // matrix with no clip and that the matrix, clip, and render target set before this function was
331    // called are restored before we return to the caller.
332    GrContext* context = src.getTexture()->getContext();
333    GrContext::AutoWideOpenIdentityDraw awoid(context, NULL);
334    if (this->canFilterImageGPU()) {
335        return this->filterImageGPU(proxy, src, ctx, result, offset);
336    } else {
337        if (this->filterImage(proxy, src, ctx, result, offset)) {
338            if (!result->getTexture()) {
339                const SkImageInfo info = result->info();
340                if (kUnknown_SkColorType == info.colorType()) {
341                    return false;
342                }
343                GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL);
344                result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
345                GrUnlockAndUnrefCachedBitmapTexture(resultTex);
346            }
347            return true;
348        } else {
349            return false;
350        }
351    }
352}
353#endif
354
355static uint32_t compute_hash(const uint32_t* data, int count) {
356    uint32_t hash = 0;
357
358    for (int i = 0; i < count; ++i) {
359        uint32_t k = data[i];
360        k *= 0xcc9e2d51;
361        k = (k << 15) | (k >> 17);
362        k *= 0x1b873593;
363
364        hash ^= k;
365        hash = (hash << 13) | (hash >> 19);
366        hash *= 5;
367        hash += 0xe6546b64;
368    }
369
370    //    hash ^= size;
371    hash ^= hash >> 16;
372    hash *= 0x85ebca6b;
373    hash ^= hash >> 13;
374    hash *= 0xc2b2ae35;
375    hash ^= hash >> 16;
376
377    return hash;
378}
379
380class CacheImpl : public SkImageFilter::Cache {
381public:
382    explicit CacheImpl(int minChildren) : fMinChildren(minChildren) {}
383    virtual ~CacheImpl();
384    bool get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
385    void set(const SkImageFilter* key, const SkBitmap& result, const SkIPoint& offset) SK_OVERRIDE;
386    void remove(const SkImageFilter* key) SK_OVERRIDE;
387private:
388    typedef const SkImageFilter* Key;
389    struct Value {
390        Value(Key key, const SkBitmap& bitmap, const SkIPoint& offset)
391            : fKey(key), fBitmap(bitmap), fOffset(offset) {}
392        Key fKey;
393        SkBitmap fBitmap;
394        SkIPoint fOffset;
395        static const Key& GetKey(const Value& v) {
396            return v.fKey;
397        }
398        static uint32_t Hash(Key key) {
399            return compute_hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key) / sizeof(uint32_t));
400        }
401    };
402    SkTDynamicHash<Value, Key> fData;
403    int fMinChildren;
404};
405
406bool CacheImpl::get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) {
407    Value* v = fData.find(key);
408    if (v) {
409        *result = v->fBitmap;
410        *offset = v->fOffset;
411        return true;
412    }
413    return false;
414}
415
416void CacheImpl::remove(const SkImageFilter* key) {
417    Value* v = fData.find(key);
418    if (v) {
419        fData.remove(key);
420        delete v;
421    }
422}
423
424void CacheImpl::set(const SkImageFilter* key, const SkBitmap& result, const SkIPoint& offset) {
425    if (key->getRefCnt() >= fMinChildren) {
426        fData.add(new Value(key, result, offset));
427    }
428}
429
430SkImageFilter::Cache* SkImageFilter::Cache::Create(int minChildren) {
431    return new CacheImpl(minChildren);
432}
433
434CacheImpl::~CacheImpl() {
435    SkTDynamicHash<Value, Key>::Iter iter(&fData);
436
437    while (!iter.done()) {
438        Value* v = &*iter;
439        ++iter;
440        delete v;
441    }
442}
443