Fix recursive GPU processing for SkImageFilter.  Plumb through the
SkImageFilter::Proxy parameter to the GPU recursion path.  Extract
DeviceImageFilterProxy from SkCanvas.cpp into its own .h, and rename it.

https://codereview.appspot.com/6575059/



git-svn-id: http://skia.googlecode.com/svn/trunk@5720 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 851a167..f0aa8e0 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -389,7 +389,7 @@
     friend class SkDraw;
     friend class SkDrawIter;
     friend class SkDeviceFilteredPaint;
-    friend class DeviceImageFilterProxy;
+    friend class SkDeviceImageFilterProxy;
 
     friend class SkSurface_Raster;
     // used to change the backend's pixels (and possibly config/rowbytes)
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index dd5aecd..92a5a58 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -106,7 +106,7 @@
      *  size, and return it to the caller.  The default implementation returns
      *  NULL.
      */
-    virtual GrTexture* onFilterImageGPU(GrTexture* texture, const SkRect& rect);
+    virtual GrTexture* onFilterImageGPU(Proxy*, GrTexture* texture, const SkRect& rect);
 
 protected:
     SkImageFilter() {}
diff --git a/include/effects/SkBlendImageFilter.h b/include/effects/SkBlendImageFilter.h
index c13140f..be1be68 100644
--- a/include/effects/SkBlendImageFilter.h
+++ b/include/effects/SkBlendImageFilter.h
@@ -34,7 +34,7 @@
                                SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
     virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
-    virtual GrTexture* onFilterImageGPU(GrTexture* src, const SkRect& rect) SK_OVERRIDE;
+    virtual GrTexture* onFilterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) SK_OVERRIDE;
 #endif
 
 protected:
diff --git a/include/effects/SkBlurImageFilter.h b/include/effects/SkBlurImageFilter.h
index 9e86f7a..eeafbb9 100644
--- a/include/effects/SkBlurImageFilter.h
+++ b/include/effects/SkBlurImageFilter.h
@@ -26,7 +26,7 @@
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
 
     bool canFilterImageGPU() const SK_OVERRIDE { return true; }
-    virtual GrTexture* onFilterImageGPU(GrTexture* src, const SkRect& rect) SK_OVERRIDE;
+    virtual GrTexture* onFilterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) SK_OVERRIDE;
 
 private:
     SkSize   fSigma;
diff --git a/include/effects/SkMorphologyImageFilter.h b/include/effects/SkMorphologyImageFilter.h
index d1d43ba..edee221 100644
--- a/include/effects/SkMorphologyImageFilter.h
+++ b/include/effects/SkMorphologyImageFilter.h
@@ -38,7 +38,8 @@
     virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
-    virtual GrTexture* onFilterImageGPU(GrTexture* src, const SkRect& rect) SK_OVERRIDE;
+    virtual GrTexture* onFilterImageGPU(Proxy* proxy, GrTexture* src,
+                                        const SkRect& rect) SK_OVERRIDE;
 #endif
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter)
@@ -58,7 +59,8 @@
     virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
 #if SK_SUPPORT_GPU
-    virtual GrTexture* onFilterImageGPU(GrTexture* src, const SkRect& rect) SK_OVERRIDE;
+    virtual GrTexture* onFilterImageGPU(Proxy* proxy, GrTexture* src,
+                                        const SkRect& rect) SK_OVERRIDE;
 #endif
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter)
diff --git a/include/effects/SkSingleInputImageFilter.h b/include/effects/SkSingleInputImageFilter.h
index fd2c6aa..b29eca0 100644
--- a/include/effects/SkSingleInputImageFilter.h
+++ b/include/effects/SkSingleInputImageFilter.h
@@ -32,7 +32,7 @@
 #if SK_SUPPORT_GPU
     // Recurses on input (if non-NULL), and returns the processed result as
     // a texture, otherwise returns src.
-    GrTexture* getInputResultAsTexture(GrTexture* src, const SkRect& rect);
+    GrTexture* getInputResultAsTexture(Proxy* proxy, GrTexture* src, const SkRect& rect);
 #endif
 
     SkImageFilter* input() const { return fInput; }
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 28a2bc4..1f8d6af 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -10,6 +10,7 @@
 #include "SkCanvas.h"
 #include "SkBounder.h"
 #include "SkDevice.h"
+#include "SkDeviceImageFilterProxy.h"
 #include "SkDraw.h"
 #include "SkDrawFilter.h"
 #include "SkDrawLooper.h"
@@ -975,29 +976,6 @@
     this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
 }
 
-#include "SkImageFilter.h"
-
-class DeviceImageFilterProxy : public SkImageFilter::Proxy {
-public:
-    DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
-
-    virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE {
-        return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
-                                               w, h, false);
-    }
-    virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE {
-        return fDevice->canHandleImageFilter(filter);
-    }
-    virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src,
-                             const SkMatrix& ctm,
-                             SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
-        return fDevice->filterImage(filter, src, ctm, result, offset);
-    }
-
-private:
-    SkDevice* fDevice;
-};
-
 void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y,
                                   const SkPaint* paint) {
     SkPaint tmp;
@@ -1013,7 +991,7 @@
         SkImageFilter* filter = paint->getImageFilter();
         SkIPoint pos = { x - iter.getX(), y - iter.getY() };
         if (filter && !dstDev->canHandleImageFilter(filter)) {
-            DeviceImageFilterProxy proxy(dstDev);
+            SkDeviceImageFilterProxy proxy(dstDev);
             SkBitmap dst;
             const SkBitmap& src = srcDev->accessBitmap(false);
             if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) {
@@ -1048,7 +1026,7 @@
         SkImageFilter* filter = paint->getImageFilter();
         SkIPoint pos = { x - iter.getX(), y - iter.getY() };
         if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
-            DeviceImageFilterProxy proxy(iter.fDevice);
+            SkDeviceImageFilterProxy proxy(iter.fDevice);
             SkBitmap dst;
             if (filter->filterImage(&proxy, bitmap, *iter.fMatrix,
                                     &dst, &pos)) {
diff --git a/src/core/SkDeviceImageFilterProxy.h b/src/core/SkDeviceImageFilterProxy.h
new file mode 100644
index 0000000..98a120c
--- /dev/null
+++ b/src/core/SkDeviceImageFilterProxy.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDeviceImageFilterProxy_DEFINED
+#define SkDeviceImageFilterProxy_DEFINED
+
+#include "SkImageFilter.h"
+
+class SkDeviceImageFilterProxy : public SkImageFilter::Proxy {
+public:
+    SkDeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
+
+    virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE {
+        return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
+                                               w, h, false);
+    }
+    virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE {
+        return fDevice->canHandleImageFilter(filter);
+    }
+    virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src,
+                             const SkMatrix& ctm,
+                             SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
+        return fDevice->filterImage(filter, src, ctm, result, offset);
+    }
+
+private:
+    SkDevice* fDevice;
+};
+
+#endif
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 21582bd..bb31b79 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -39,7 +39,7 @@
     return false;
 }
 
-GrTexture* SkImageFilter::onFilterImageGPU(GrTexture* texture, const SkRect& rect) {
+GrTexture* SkImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* texture, const SkRect& rect) {
     return NULL;
 }
 
diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp
index 2328d95..b604bc2 100644
--- a/src/effects/SkBlendImageFilter.cpp
+++ b/src/effects/SkBlendImageFilter.cpp
@@ -165,7 +165,8 @@
 };
 
 // FIXME:  This should be refactored with SkSingleInputImageFilter's version.
-static GrTexture* getInputResultAsTexture(SkImageFilter* input,
+static GrTexture* getInputResultAsTexture(SkImageFilter::Proxy* proxy,
+                                          SkImageFilter* input,
                                           GrTexture* src,
                                           const SkRect& rect) {
     GrTexture* resultTex;
@@ -173,13 +174,13 @@
         resultTex = src;
     } else if (input->canFilterImageGPU()) {
         // onFilterImageGPU() already refs the result, so just return it here.
-        return input->onFilterImageGPU(src, rect);
+        return input->onFilterImageGPU(proxy, src, rect);
     } else {
         SkBitmap srcBitmap, result;
         srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, src->width(), src->height());
         srcBitmap.setPixelRef(new SkGrPixelRef(src))->unref();
         SkIPoint offset;
-        if (input->filterImage(NULL, srcBitmap, SkMatrix(), &result, &offset)) {
+        if (input->filterImage(proxy, srcBitmap, SkMatrix(), &result, &offset)) {
             if (result.getTexture()) {
                 resultTex = (GrTexture*) result.getTexture();
             } else {
@@ -196,9 +197,9 @@
     return resultTex;
 }
 
-GrTexture* SkBlendImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
-    SkAutoTUnref<GrTexture> background(getInputResultAsTexture(fBackground, src, rect));
-    SkAutoTUnref<GrTexture> foreground(getInputResultAsTexture(fForeground, src, rect));
+GrTexture* SkBlendImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
+    SkAutoTUnref<GrTexture> background(getInputResultAsTexture(proxy, fBackground, src, rect));
+    SkAutoTUnref<GrTexture> foreground(getInputResultAsTexture(proxy, fForeground, src, rect));
     GrContext* context = src->getContext();
 
     GrTextureDesc desc;
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index 2a61460..fb76269 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -187,9 +187,9 @@
     return true;
 }
 
-GrTexture* SkBlurImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
+GrTexture* SkBlurImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
 #if SK_SUPPORT_GPU
-    SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
+    SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(proxy, src, rect));
     return src->getContext()->gaussianBlur(input.get(), false, rect,
                                            fSigma.width(), fSigma.height());
 #else
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 5bf9a99..b1ee602 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -478,13 +478,13 @@
 
 };
 
-GrTexture* SkDilateImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
-    SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
+GrTexture* SkDilateImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
+    SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(proxy, src, rect));
     return apply_morphology(src, rect, GrMorphologyEffect::kDilate_MorphologyType, radius());
 }
 
-GrTexture* SkErodeImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
-    SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
+GrTexture* SkErodeImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) {
+    SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(proxy, src, rect));
     return apply_morphology(src, rect, GrMorphologyEffect::kErode_MorphologyType, radius());
 }
 
diff --git a/src/effects/SkSingleInputImageFilter.cpp b/src/effects/SkSingleInputImageFilter.cpp
index a1c4292..3dd9ef9 100644
--- a/src/effects/SkSingleInputImageFilter.cpp
+++ b/src/effects/SkSingleInputImageFilter.cpp
@@ -51,20 +51,21 @@
 }
 
 #if SK_SUPPORT_GPU
-GrTexture* SkSingleInputImageFilter::getInputResultAsTexture(GrTexture* src,
+GrTexture* SkSingleInputImageFilter::getInputResultAsTexture(Proxy* proxy,
+                                                             GrTexture* src,
                                                              const SkRect& rect) {
-    GrTexture* resultTex;
+    GrTexture* resultTex = NULL;
     if (!fInput) {
         resultTex = src;
     } else if (fInput->canFilterImageGPU()) {
         // onFilterImageGPU() already refs the result, so just return it here.
-        return fInput->onFilterImageGPU(src, rect);
+        return fInput->onFilterImageGPU(proxy, src, rect);
     } else {
         SkBitmap srcBitmap, result;
         srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, src->width(), src->height());
         srcBitmap.setPixelRef(new SkGrPixelRef(src))->unref();
         SkIPoint offset;
-        if (fInput->filterImage(NULL, srcBitmap, SkMatrix(), &result, &offset)) {
+        if (fInput->filterImage(proxy, srcBitmap, SkMatrix(), &result, &offset)) {
             if (result.getTexture()) {
                 resultTex = (GrTexture*) result.getTexture();
             } else {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 322748e..59a3b61 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -16,6 +16,7 @@
 #include "SkGrTexturePixelRef.h"
 
 #include "SkColorFilter.h"
+#include "SkDeviceImageFilterProxy.h"
 #include "SkDrawProcs.h"
 #include "SkGlyphCache.h"
 #include "SkImageFilter.h"
@@ -1514,9 +1515,11 @@
 
 };
 
-static GrTexture* filter_texture(GrContext* context, GrTexture* texture,
-                                 SkImageFilter* filter, const GrRect& rect) {
+static GrTexture* filter_texture(SkDevice* device, GrContext* context,
+                                 GrTexture* texture, SkImageFilter* filter,
+                                 const GrRect& rect) {
     GrAssert(filter);
+    SkDeviceImageFilterProxy proxy(device);
 
     GrTextureDesc desc;
     desc.fFlags = kRenderTarget_GrTextureFlagBit,
@@ -1526,7 +1529,7 @@
     GrCustomStage* stage;
 
     if (filter->canFilterImageGPU()) {
-        texture = filter->onFilterImageGPU(texture, rect);
+        texture = filter->onFilterImageGPU(&proxy, texture, rect);
     } else if (filter->asNewCustomStage(&stage, texture)) {
         GrAutoScratchTexture dst(context, desc);
         apply_custom_stage(context, texture, dst.texture(), rect, stage);
@@ -1567,7 +1570,7 @@
 
     SkImageFilter* filter = paint.getImageFilter();
     if (NULL != filter) {
-        GrTexture* filteredTexture = filter_texture(fContext, texture, filter,
+        GrTexture* filteredTexture = filter_texture(this, fContext, texture, filter,
                  GrRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)));
         if (filteredTexture) {
             grPaint.textureSampler(kBitmapTextureIdx)->setCustomStage(SkNEW_ARGS
@@ -1653,7 +1656,7 @@
     if (NULL != filter) {
         GrRect rect = GrRect::MakeWH(SkIntToScalar(devTex->width()),
                                      SkIntToScalar(devTex->height()));
-        GrTexture* filteredTexture = filter_texture(fContext, devTex, filter, rect);
+        GrTexture* filteredTexture = filter_texture(this, fContext, devTex, filter, rect);
         if (filteredTexture) {
             grPaint.textureSampler(kBitmapTextureIdx)->setCustomStage(SkNEW_ARGS
                 (GrSingleTextureEffect, (filteredTexture)))->unref();
@@ -1712,7 +1715,7 @@
     result->setConfig(src.config(), src.width(), src.height());
     GrRect rect = GrRect::MakeWH(SkIntToScalar(src.width()),
                                  SkIntToScalar(src.height()));
-    GrTexture* resultTexture = filter_texture(fContext, texture, filter, rect);
+    GrTexture* resultTexture = filter_texture(this, fContext, texture, filter, rect);
     if (resultTexture) {
         result->setPixelRef(SkNEW_ARGS(SkGrTexturePixelRef,
                                        (resultTexture)))->unref();