Index: src/image/SkImage.cpp |
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp |
index af9c27592c527e1383136f999ba56ede955eb07d..3ad80043da2f49e841e546346efca82a0f712171 100644 |
--- a/src/image/SkImage.cpp |
+++ b/src/image/SkImage.cpp |
@@ -67,6 +67,81 @@ void SkImage::preroll(GrContext* ctx) const { |
} |
} |
+SkImage* SkImage::applyFilter(SkImageFilter* filter, SkIPoint* offset, |
+ bool forceResultToOriginalSize) const { |
+ if (!filter) { |
+ return nullptr; |
+ } |
+ |
+ SkIPoint offsetStorage; |
+ if (!offset) { |
+ offset = &offsetStorage; |
+ } |
+ return as_IB(this)->onApplyFilter(filter, offset, forceResultToOriginalSize); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+#include "SkImageFilter.h" |
+#include "SkBitmapDevice.h" |
+ |
+static SkIRect compute_fast_ibounds(SkImageFilter* filter, const SkIRect& srcBounds) { |
+ SkRect fastBounds; |
+ fastBounds.set(srcBounds); |
+ filter->computeFastBounds(fastBounds, &fastBounds); |
+ return fastBounds.roundOut(); |
+} |
+ |
+class SkRasterImageFilterProxy : public SkImageFilter::Proxy { |
+public: |
+ SkBaseDevice* createDevice(int width, int height) override { |
+ return SkBitmapDevice::Create(SkImageInfo::MakeN32Premul(width, height)); |
+ } |
+ |
+ bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&, |
+ SkBitmap*, SkIPoint*) override { |
+ return false; |
+ } |
+}; |
+ |
+SkImage* SkImage_Base::onApplyFilter(SkImageFilter* filter, SkIPoint* offsetResult, |
+ bool forceResultToOriginalSize) const { |
+ SkBitmap src; |
+ if (!this->getROPixels(&src)) { |
+ return nullptr; |
+ } |
+ |
+ const SkIRect srcBounds = SkIRect::MakeWH(this->width(), this->height()); |
+ |
+ if (forceResultToOriginalSize) { |
+ const SkIRect clipBounds = srcBounds; |
+ SkRasterImageFilterProxy proxy; |
+ SkImageFilter::Context ctx(SkMatrix::I(), clipBounds, SkImageFilter::Cache::Get()); |
+ |
+ SkBitmap dst; |
+ if (filter->filterImage(&proxy, src, ctx, &dst, offsetResult)) { |
+ dst.setImmutable(); |
+ return SkImage::NewFromBitmap(dst); |
+ } |
+ } else { |
+ const SkIRect dstR = compute_fast_ibounds(filter, srcBounds); |
+ |
+ SkImageInfo info = SkImageInfo::MakeN32Premul(dstR.width(), dstR.height()); |
+ SkAutoTUnref<SkSurface> surface(this->onNewSurface(info)); |
+ |
+ SkPaint paint; |
+ paint.setImageFilter(filter); |
+ surface->getCanvas()->drawImage(this, SkIntToScalar(-dstR.x()), SkIntToScalar(-dstR.y()), |
+ &paint); |
+ |
+ offsetResult->set(dstR.x(), dstR.y()); |
+ return surface->newImageSnapshot(); |
+ } |
+ return nullptr; |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
SkShader* SkImage::newShader(SkShader::TileMode tileX, |
SkShader::TileMode tileY, |
const SkMatrix* localMatrix) const { |