Replace SkSpecialImage::makeTightSubset with asImage (take 2)

This is a reland of https://skia-review.googlesource.com/c/8498/ (Replace SkSpecialImage::makeTightSubset with asImage)

It must wait on https://codereview.chromium.org/2702703002/ (Add suppressions for upcoming Skia DEPS roll) due to minor layout test changes

This should allow the relanding of:

https://skia-review.googlesource.com/c/8450/ (Remove asTextureRef from SkSpecialImage & update effects accordingly (take 2))

Change-Id: I7086a419869dbeb62d9b9e9714c796d54e75ee49
Reviewed-on: https://skia-review.googlesource.com/8701
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index 0ae84d3..60259bb 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -18,6 +18,7 @@
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
 #include "GrSurfaceContext.h"
+#include "GrSurfaceProxyPriv.h"
 #include "GrTexture.h"
 #include "GrSamplerParams.h"
 #include "GrTextureProxy.h"
@@ -59,7 +60,7 @@
     virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
                                                   const SkISize& size, SkAlphaType at) const = 0;
 
-    virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
+    virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
 
     virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
                                                 const SkISize& size, SkAlphaType at) const = 0;
@@ -170,10 +171,11 @@
     return as_SIB(this)->onMakeSubset(subset);
 }
 
-sk_sp<SkImage> SkSpecialImage::makeTightSubset(const SkIRect& subset) const {
-    return as_SIB(this)->onMakeTightSubset(subset);
+sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
+    return as_SIB(this)->onAsImage(subset);
 }
 
+
 #ifdef SK_DEBUG
 static bool rect_fits(const SkIRect& rect, int width, int height) {
     if (0 == width && 0 == height) {
@@ -299,14 +301,18 @@
                                               &this->props());
     }
 
-    sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
-        SkBitmap subsetBM;
+    sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
+        if (subset) {
+            SkBitmap subsetBM;
 
-        if (!fBitmap.extractSubset(&subsetBM, subset)) {
-            return nullptr;
+            if (!fBitmap.extractSubset(&subsetBM, *subset)) {
+                return nullptr;
+            }
+
+            return SkImage::MakeFromBitmap(subsetBM);
         }
 
-        return SkImage::MakeFromBitmap(subsetBM);
+        return SkImage::MakeFromBitmap(fBitmap);
     }
 
     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
@@ -362,7 +368,9 @@
         return nullptr;
     }
 
-    return sk_make_sp<SkImage_Gpu>(proxy->width(), proxy->height(),
+    // Note that we're explicitly using the GrTexture's width & height here b.c. SkImages
+    // must be tight.
+    return sk_make_sp<SkImage_Gpu>(tex->width(), tex->height(),
                                    kNeedNewImageUniqueID, alphaType,
                                    sk_ref_sp(tex),
                                    std::move(colorSpace), SkBudgeted::kYes);
@@ -497,20 +505,25 @@
     }
 
     // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
-    sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
-        // TODO: this is problematic since the surfaceProxy could be loose
-        if (0 == subset.fLeft && 0 == subset.fTop &&
-            fTextureProxy->width() == subset.width() &&
-            fTextureProxy->height() == subset.height()) {
-            // The existing GrTexture is already tight so reuse it in the SkImage
-            return wrap_proxy_in_image(fContext, fTextureProxy.get(),
-                                       fAlphaType, fColorSpace);
+    sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
+        if (subset) {
+            // TODO: if this becomes a bottle neck we could base this logic on what the size
+            // will be when it is finally instantiated - but that is more fraught.
+            if (//fSurfaceProxy->priv().isExact() &&
+                0 == subset->fLeft && 0 == subset->fTop &&
+                fTextureProxy->width() == subset->width() &&
+                fTextureProxy->height() == subset->height()) {
+                // The existing GrTexture is already tight so reuse it in the SkImage
+                return wrap_proxy_in_image(fContext, fTextureProxy.get(), fAlphaType, fColorSpace);
+            }
+
+            sk_sp<GrTextureProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fTextureProxy.get(),
+                                                                   *subset, SkBudgeted::kYes));
+
+            return wrap_proxy_in_image(fContext, subsetProxy.get(), fAlphaType, fColorSpace);
         }
 
-        sk_sp<GrTextureProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fTextureProxy.get(),
-                                                               subset, SkBudgeted::kYes));
-
-        return wrap_proxy_in_image(fContext, subsetProxy.get(), fAlphaType, fColorSpace);
+        return wrap_proxy_in_image(fContext, fTextureProxy.get(), fAlphaType, fColorSpace);
     }
 
     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,