Chromium Code Reviews| Index: src/core/SkImageFilter.cpp |
| diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp |
| index a38124b0e62b4db1894883e7654630cff0de9a1d..40dd05d7cd212c98cea3a5c0e0a93473343119a3 100644 |
| --- a/src/core/SkImageFilter.cpp |
| +++ b/src/core/SkImageFilter.cpp |
| @@ -16,6 +16,8 @@ |
| #include "SkOncePtr.h" |
| #include "SkReadBuffer.h" |
| #include "SkRect.h" |
| +#include "SkSpecialImage.h" |
| +#include "SkSpecialSurface.h" |
| #include "SkTDynamicHash.h" |
| #include "SkTInternalLList.h" |
| #include "SkValidationUtils.h" |
| @@ -231,6 +233,27 @@ void SkImageFilter::flatten(SkWriteBuffer& buffer) const { |
| buffer.writeUInt(fCropRect.flags()); |
| } |
| +SkSpecialImage* SkImageFilter::filterImage(SkSpecialImage* src, const Context& context, |
| + SkIPoint* offset) const { |
| + SkASSERT(src && offset); |
| + |
| + uint32_t srcGenID = fUsesSrcInput ? src->uniqueID() : 0; |
| + Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID); |
| + if (context.cache()) { |
| + SkSpecialImage* result = context.cache()->get(key, offset); |
| + if (result) { |
| + return SkRef(result); |
| + } |
| + } |
| + |
| + SkSpecialImage* result = this->onFilterImage(src, context, offset); |
| + if (result && context.cache()) { |
| + context.cache()->set(key, result, *offset); |
| + } |
| + |
| + return result; |
| +} |
| + |
| bool SkImageFilter::filterImageDeprecated(Proxy* proxy, const SkBitmap& src, |
| const Context& context, |
| SkBitmap* result, SkIPoint* offset) const { |
| @@ -436,6 +459,55 @@ bool SkImageFilter::applyCropRectDeprecated(const Context& ctx, Proxy* proxy, co |
| } |
| } |
| +// Return a larger (newWidth x newHeight) copy of 'src' with black padding |
| +// around it. |
| +static SkSpecialImage* pad_image(SkSpecialImage* src, |
| + int newWidth, int newHeight, int offX, int offY) { |
| + |
| + SkImageInfo info = SkImageInfo::MakeN32Premul(newWidth, newHeight); |
| + SkAutoTUnref<SkSpecialSurface> surf(src->newSurface(info)); |
| + if (!surf) { |
| + return nullptr; |
| + } |
| + |
| + SkCanvas* canvas = surf->getCanvas(); |
| + if (!canvas) { |
| + return nullptr; |
| + } |
| + |
| + canvas->clear(0x0); |
| + |
| + src->draw(canvas, offX, offY, nullptr); |
| + |
| + return surf->newImageSnapshot(); |
| +} |
| + |
| +SkSpecialImage* SkImageFilter::applyCropRect(const Context& ctx, |
| + SkSpecialImage* src, |
| + SkIPoint* srcOffset, |
| + SkIRect* bounds) const { |
| + SkIRect srcBounds; |
| + srcBounds = SkIRect::MakeXYWH(srcOffset->fX, srcOffset->fY, src->width(), src->height()); |
| + |
| + SkIRect dstBounds; |
| + this->onFilterNodeBounds(srcBounds, ctx.ctm(), &dstBounds, kForward_MapDirection); |
| + fCropRect.applyTo(dstBounds, ctx.ctm(), bounds); |
| + if (!bounds->intersect(ctx.clipBounds())) { |
| + return nullptr; |
| + } |
| + |
| + if (srcBounds.contains(*bounds)) { |
| + return SkRef(src); |
| + } else { |
| + SkSpecialImage* img = pad_image(src, |
| + bounds->width(), bounds->height(), |
| + srcOffset->x() - bounds->x(), |
| + srcOffset->y() - bounds->y()); |
| + *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); |
| + return img; |
| + } |
| +} |
| + |
| bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, |
| SkIRect* dst, MapDirection direction) const { |
| if (fInputCount < 1) { |
| @@ -494,6 +566,36 @@ SkImageFilter* SkImageFilter::newWithLocalMatrix(const SkMatrix& matrix) const { |
| return SkLocalMatrixImageFilter::Create(matrix, const_cast<SkImageFilter*>(this)); |
| } |
| +SkSpecialImage* SkImageFilter::filterInput(int index, |
| + SkSpecialImage* src, |
| + const Context& ctx, |
| + SkIPoint* offset) const { |
| + SkImageFilter* input = this->getInput(index); |
| + if (!input) { |
| + return SkRef(src); |
| + } |
| + |
| + if (input->supportsUnifiedFiltering()) { |
| + // Ensure that calls in filterImage below will see an identity |
| + // matrix with no clip and that the matrix and clip set before this function was |
| + // called are restored before we return to the caller. |
| + return input->filterImage(src, this->mapContext(ctx), offset); |
| + } else { |
| + SkBitmap tmpSrc, result; |
| + |
| + if (!src->internal_getBM(&tmpSrc)) { |
|
Stephen White
2016/02/18 17:56:17
Would it work to put this chunk of code into the b
robertphillips
2016/02/19 19:37:59
Done. It had to go in onFilterImage though. This d
Stephen White
2016/02/19 19:53:55
Sorry, that's actually what I meant!
|
| + return nullptr; |
| + } |
| + |
| + if (!input->filterImageDeprecated(src->internal_getProxy(), tmpSrc, |
| + this->mapContext(ctx), &result, offset)) { |
| + return nullptr; |
| + } |
| + |
| + return SkSpecialImage::internal_fromBM(src->internal_getProxy(), result); |
| + } |
| +} |
| + |
| #if SK_SUPPORT_GPU |
| bool SkImageFilter::filterInputGPUDeprecated(int index, SkImageFilter::Proxy* proxy, |
| @@ -531,9 +633,8 @@ namespace { |
| class CacheImpl : public SkImageFilter::Cache { |
| public: |
| - CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { |
| - } |
| - virtual ~CacheImpl() { |
| + CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { } |
| + ~CacheImpl() override { |
| SkTDynamicHash<Value, Key>::Iter iter(&fLookup); |
| while (!iter.done()) { |
| @@ -545,8 +646,12 @@ public: |
| struct Value { |
| Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset) |
| : fKey(key), fBitmap(bitmap), fOffset(offset) {} |
| + Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset) |
| + : fKey(key), fImage(SkRef(image)), fOffset(offset) {} |
| + |
| Key fKey; |
| SkBitmap fBitmap; |
| + SkAutoTUnref<SkSpecialImage> fImage; |
| SkIPoint fOffset; |
| static const Key& GetKey(const Value& v) { |
| return v.fKey; |
| @@ -556,6 +661,7 @@ public: |
| } |
| SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value); |
| }; |
| + |
| bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const override { |
| SkAutoMutexAcquire mutex(fMutex); |
| if (Value* v = fLookup.find(key)) { |
| @@ -569,10 +675,24 @@ public: |
| } |
| return false; |
| } |
| + |
| + SkSpecialImage* get(const Key& key, SkIPoint* offset) const override { |
| + SkAutoMutexAcquire mutex(fMutex); |
| + if (Value* v = fLookup.find(key)) { |
| + *offset = v->fOffset; |
| + if (v != fLRU.head()) { |
| + fLRU.remove(v); |
| + fLRU.addToHead(v); |
| + } |
| + return v->fImage; |
| + } |
| + return nullptr; |
| + } |
| + |
| void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override { |
| SkAutoMutexAcquire mutex(fMutex); |
| if (Value* v = fLookup.find(key)) { |
| - removeInternal(v); |
| + this->removeInternal(v); |
| } |
| Value* v = new Value(key, result, offset); |
| fLookup.add(v); |
| @@ -584,7 +704,26 @@ public: |
| if (tail == v) { |
| break; |
| } |
| - removeInternal(tail); |
| + this->removeInternal(tail); |
| + } |
| + } |
| + |
| + void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) override { |
| + SkAutoMutexAcquire mutex(fMutex); |
| + if (Value* v = fLookup.find(key)) { |
| + this->removeInternal(v); |
| + } |
| + Value* v = new Value(key, image, offset); |
| + fLookup.add(v); |
| + fLRU.addToHead(v); |
| + fCurrentBytes += image->getSize(); |
| + while (fCurrentBytes > fMaxBytes) { |
| + Value* tail = fLRU.tail(); |
| + SkASSERT(tail); |
| + if (tail == v) { |
| + break; |
| + } |
| + this->removeInternal(tail); |
| } |
| } |