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 "SkChecksum.h"
12#include "SkDevice.h"
13#include "SkLazyPtr.h"
14#include "SkMatrixImageFilter.h"
15#include "SkReadBuffer.h"
16#include "SkWriteBuffer.h"
17#include "SkRect.h"
18#include "SkTDynamicHash.h"
19#include "SkTInternalLList.h"
20#include "SkValidationUtils.h"
21#if SK_SUPPORT_GPU
22#include "GrContext.h"
23#include "SkGrPixelRef.h"
24#include "SkGr.h"
25#endif
26
27#ifdef SK_BUILD_FOR_IOS
28  enum { kDefaultCacheSize = 2 * 1024 * 1024 };
29#else
30  enum { kDefaultCacheSize = 128 * 1024 * 1024 };
31#endif
32
33static int32_t next_image_filter_unique_id() {
34    static int32_t gImageFilterUniqueID;
35
36    // Never return 0.
37    int32_t id;
38    do {
39        id = sk_atomic_inc(&gImageFilterUniqueID) + 1;
40    } while (0 == id);
41    return id;
42}
43
44struct SkImageFilter::Cache::Key {
45    Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBounds, uint32_t srcGenID)
46      : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID(srcGenID) {
47        // Assert that Key is tightly-packed, since it is hashed.
48        SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + sizeof(SkIRect) +
49                                         sizeof(uint32_t), image_filter_key_tight_packing);
50        fMatrix.getType();  // force initialization of type, so hashes match
51    }
52    uint32_t fUniqueID;
53    SkMatrix fMatrix;
54    SkIRect fClipBounds;
55    uint32_t fSrcGenID;
56    bool operator==(const Key& other) const {
57        return fUniqueID == other.fUniqueID
58            && fMatrix == other.fMatrix
59            && fClipBounds == other.fClipBounds
60            && fSrcGenID == other.fSrcGenID;
61    }
62};
63
64SkImageFilter::Common::~Common() {
65    for (int i = 0; i < fInputs.count(); ++i) {
66        SkSafeUnref(fInputs[i]);
67    }
68}
69
70void SkImageFilter::Common::allocInputs(int count) {
71    const size_t size = count * sizeof(SkImageFilter*);
72    fInputs.reset(count);
73    sk_bzero(fInputs.get(), size);
74}
75
76void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) {
77    const size_t size = fInputs.count() * sizeof(SkImageFilter*);
78    memcpy(inputs, fInputs.get(), size);
79    sk_bzero(fInputs.get(), size);
80}
81
82bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
83    const int count = buffer.readInt();
84    if (!buffer.validate(count >= 0)) {
85        return false;
86    }
87    if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
88        return false;
89    }
90
91    this->allocInputs(count);
92    for (int i = 0; i < count; i++) {
93        if (buffer.readBool()) {
94            fInputs[i] = buffer.readImageFilter();
95        }
96        if (!buffer.isValid()) {
97            return false;
98        }
99    }
100    SkRect rect;
101    buffer.readRect(&rect);
102    if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
103        return false;
104    }
105
106    uint32_t flags = buffer.readUInt();
107    fCropRect = CropRect(rect, flags);
108    if (buffer.isVersionLT(SkReadBuffer::kImageFilterNoUniqueID_Version)) {
109
110        (void) buffer.readUInt();
111    }
112    return buffer.isValid();
113}
114
115///////////////////////////////////////////////////////////////////////////////////////////////////
116
117SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
118  : fInputCount(inputCount),
119    fInputs(new SkImageFilter*[inputCount]),
120    fUsesSrcInput(false),
121    fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)),
122    fUniqueID(next_image_filter_unique_id()) {
123    for (int i = 0; i < inputCount; ++i) {
124        if (NULL == inputs[i] || inputs[i]->usesSrcInput()) {
125            fUsesSrcInput = true;
126        }
127        fInputs[i] = inputs[i];
128        SkSafeRef(fInputs[i]);
129    }
130}
131
132SkImageFilter::~SkImageFilter() {
133    for (int i = 0; i < fInputCount; i++) {
134        SkSafeUnref(fInputs[i]);
135    }
136    delete[] fInputs;
137}
138
139SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
140  : fUsesSrcInput(false)
141  , fUniqueID(next_image_filter_unique_id()) {
142    Common common;
143    if (common.unflatten(buffer, inputCount)) {
144        fCropRect = common.cropRect();
145        fInputCount = common.inputCount();
146        fInputs = SkNEW_ARRAY(SkImageFilter*, fInputCount);
147        common.detachInputs(fInputs);
148        for (int i = 0; i < fInputCount; ++i) {
149            if (NULL == fInputs[i] || fInputs[i]->usesSrcInput()) {
150                fUsesSrcInput = true;
151            }
152        }
153    } else {
154        fInputCount = 0;
155        fInputs = NULL;
156    }
157}
158
159void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
160    buffer.writeInt(fInputCount);
161    for (int i = 0; i < fInputCount; i++) {
162        SkImageFilter* input = getInput(i);
163        buffer.writeBool(input != NULL);
164        if (input != NULL) {
165            buffer.writeFlattenable(input);
166        }
167    }
168    buffer.writeRect(fCropRect.rect());
169    buffer.writeUInt(fCropRect.flags());
170}
171
172bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
173                                const Context& context,
174                                SkBitmap* result, SkIPoint* offset) const {
175    SkASSERT(result);
176    SkASSERT(offset);
177    uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0;
178    Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID);
179    if (context.cache()) {
180        if (context.cache()->get(key, result, offset)) {
181            return true;
182        }
183    }
184    /*
185     *  Give the proxy first shot at the filter. If it returns false, ask
186     *  the filter to do it.
187     */
188    if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
189        this->onFilterImage(proxy, src, context, result, offset)) {
190        if (context.cache()) {
191            context.cache()->set(key, *result, *offset);
192        }
193        return true;
194    }
195    return false;
196}
197
198bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
199                                 SkIRect* dst) const {
200    SkASSERT(dst);
201    return this->onFilterBounds(src, ctm, dst);
202}
203
204void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
205    if (0 == fInputCount) {
206        *dst = src;
207        return;
208    }
209    if (this->getInput(0)) {
210        this->getInput(0)->computeFastBounds(src, dst);
211    } else {
212        *dst = src;
213    }
214    for (int i = 1; i < fInputCount; i++) {
215        SkImageFilter* input = this->getInput(i);
216        if (input) {
217            SkRect bounds;
218            input->computeFastBounds(src, &bounds);
219            dst->join(bounds);
220        } else {
221            dst->join(src);
222        }
223    }
224}
225
226bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
227                                  SkBitmap*, SkIPoint*) const {
228    return false;
229}
230
231bool SkImageFilter::canFilterImageGPU() const {
232    return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect());
233}
234
235bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
236                                   SkBitmap* result, SkIPoint* offset) const {
237#if SK_SUPPORT_GPU
238    SkBitmap input = src;
239    SkASSERT(fInputCount == 1);
240    SkIPoint srcOffset = SkIPoint::Make(0, 0);
241    if (this->getInput(0) &&
242        !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
243        return false;
244    }
245    GrTexture* srcTexture = input.getTexture();
246    SkIRect bounds;
247    if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
248        return false;
249    }
250    SkRect srcRect = SkRect::Make(bounds);
251    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
252    GrContext* context = srcTexture->getContext();
253
254    GrSurfaceDesc desc;
255    desc.fFlags = kRenderTarget_GrSurfaceFlag,
256    desc.fWidth = bounds.width();
257    desc.fHeight = bounds.height();
258    desc.fConfig = kRGBA_8888_GrPixelConfig;
259
260    SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(
261        desc, GrTextureProvider::kApprox_ScratchTexMatch));
262    if (!dst) {
263        return false;
264    }
265
266    // setup new clip
267    GrClip clip(dstRect);
268
269    GrFragmentProcessor* fp;
270    offset->fX = bounds.left();
271    offset->fY = bounds.top();
272    bounds.offset(-srcOffset);
273    SkMatrix matrix(ctx.ctm());
274    matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
275    if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
276        SkASSERT(fp);
277        GrPaint paint;
278        paint.addColorProcessor(fp)->unref();
279        context->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(), dstRect,
280                                     srcRect);
281
282        WrapTexture(dst, bounds.width(), bounds.height(), result);
283        return true;
284    }
285#endif
286    return false;
287}
288
289bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
290                                  const SkIPoint& srcOffset, SkIRect* bounds) const {
291    SkIRect srcBounds;
292    src.getBounds(&srcBounds);
293    srcBounds.offset(srcOffset);
294    SkRect cropRect;
295    ctx.ctm().mapRect(&cropRect, fCropRect.rect());
296    const SkIRect cropRectI = cropRect.roundOut();
297    uint32_t flags = fCropRect.flags();
298    if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft;
299    if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop;
300    if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight;
301    if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom;
302    if (!srcBounds.intersect(ctx.clipBounds())) {
303        return false;
304    }
305    *bounds = srcBounds;
306    return true;
307}
308
309bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
310                                  SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
311    SkIRect srcBounds;
312    src.getBounds(&srcBounds);
313    srcBounds.offset(*srcOffset);
314    SkRect cropRect;
315    ctx.ctm().mapRect(&cropRect, fCropRect.rect());
316    const SkIRect cropRectI = cropRect.roundOut();
317    uint32_t flags = fCropRect.flags();
318    *bounds = srcBounds;
319    if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft;
320    if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop;
321    if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight;
322    if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom;
323    if (!bounds->intersect(ctx.clipBounds())) {
324        return false;
325    }
326    if (srcBounds.contains(*bounds)) {
327        *dst = src;
328        return true;
329    } else {
330        SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
331        if (!device) {
332            return false;
333        }
334        SkCanvas canvas(device);
335        canvas.clear(0x00000000);
336        canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
337        *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
338        *dst = device->accessBitmap(false);
339        return true;
340    }
341}
342
343bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
344                                   SkIRect* dst) const {
345    if (fInputCount < 1) {
346        *dst = src;
347        return true;
348    }
349
350    SkIRect bounds;
351    for (int i = 0; i < fInputCount; ++i) {
352        SkImageFilter* filter = this->getInput(i);
353        SkIRect rect = src;
354        if (filter && !filter->filterBounds(src, ctm, &rect)) {
355            return false;
356        }
357        if (0 == i) {
358            bounds = rect;
359        } else {
360            bounds.join(rect);
361        }
362    }
363
364    // don't modify dst until now, so we don't accidentally change it in the
365    // loop, but then return false on the next filter.
366    *dst = bounds;
367    return true;
368}
369
370bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
371                                        const SkIRect&) const {
372    return false;
373}
374
375SkImageFilter* SkImageFilter::CreateMatrixFilter(const SkMatrix& matrix,
376                                                 SkFilterQuality filterQuality,
377                                                 SkImageFilter* input) {
378    return SkMatrixImageFilter::Create(matrix, filterQuality, input);
379}
380
381#if SK_SUPPORT_GPU
382
383void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
384    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
385    result->setInfo(info);
386    result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
387}
388
389bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy,
390                                      const SkBitmap& src, const Context& ctx,
391                                      SkBitmap* result, SkIPoint* offset) const {
392    // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
393    // matrix with no clip and that the matrix, clip, and render target set before this function was
394    // called are restored before we return to the caller.
395    GrContext* context = src.getTexture()->getContext();
396
397    if (this->canFilterImageGPU()) {
398        return this->filterImageGPU(proxy, src, ctx, result, offset);
399    } else {
400        if (this->filterImage(proxy, src, ctx, result, offset)) {
401            if (!result->getTexture()) {
402                const SkImageInfo info = result->info();
403                if (kUnknown_SkColorType == info.colorType()) {
404                    return false;
405                }
406                SkAutoTUnref<GrTexture> resultTex(GrRefCachedBitmapTexture(context, *result, NULL));
407                result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, resultTex)))->unref();
408            }
409            return true;
410        } else {
411            return false;
412        }
413    }
414}
415#endif
416
417namespace {
418
419class CacheImpl : public SkImageFilter::Cache {
420public:
421    CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) {
422    }
423    virtual ~CacheImpl() {
424        SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
425
426        while (!iter.done()) {
427            Value* v = &*iter;
428            ++iter;
429            delete v;
430        }
431    }
432    struct Value {
433        Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
434            : fKey(key), fBitmap(bitmap), fOffset(offset) {}
435        Key fKey;
436        SkBitmap fBitmap;
437        SkIPoint fOffset;
438        static const Key& GetKey(const Value& v) {
439            return v.fKey;
440        }
441        static uint32_t Hash(const Key& key) {
442            return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
443        }
444        SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
445    };
446    bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const override {
447        SkAutoMutexAcquire mutex(fMutex);
448        if (Value* v = fLookup.find(key)) {
449            *result = v->fBitmap;
450            *offset = v->fOffset;
451            if (v != fLRU.head()) {
452                fLRU.remove(v);
453                fLRU.addToHead(v);
454            }
455            return true;
456        }
457        return false;
458    }
459    void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override {
460        SkAutoMutexAcquire mutex(fMutex);
461        if (Value* v = fLookup.find(key)) {
462            removeInternal(v);
463        }
464        Value* v = new Value(key, result, offset);
465        fLookup.add(v);
466        fLRU.addToHead(v);
467        fCurrentBytes += result.getSize();
468        while (fCurrentBytes > fMaxBytes) {
469            Value* tail = fLRU.tail();
470            SkASSERT(tail);
471            if (tail == v) {
472                break;
473            }
474            removeInternal(tail);
475        }
476    }
477private:
478    void removeInternal(Value* v) {
479        fCurrentBytes -= v->fBitmap.getSize();
480        fLRU.remove(v);
481        fLookup.remove(v->fKey);
482        delete v;
483    }
484private:
485    SkTDynamicHash<Value, Key>         fLookup;
486    mutable SkTInternalLList<Value>    fLRU;
487    size_t                             fMaxBytes;
488    size_t                             fCurrentBytes;
489    mutable SkMutex                    fMutex;
490};
491
492SkImageFilter::Cache* CreateCache() {
493    return SkImageFilter::Cache::Create(kDefaultCacheSize);
494}
495
496} // namespace
497
498SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
499    return SkNEW_ARGS(CacheImpl, (maxBytes));
500}
501
502SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache);
503
504SkImageFilter::Cache* SkImageFilter::Cache::Get() {
505    return cache.get();
506}
507