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); |
} |
} |