Pull texture-backed bitmap resampler out of GrTextureParamsAdjuster code into its own class.

Review URL: https://codereview.chromium.org/1420963008
diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp
index bf9bea0..e62c6a1 100644
--- a/src/core/SkImageCacherator.cpp
+++ b/src/core/SkImageCacherator.cpp
@@ -273,9 +273,9 @@
 
 #include "GrTextureParamsAdjuster.h"
 
-class Cacherator_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
+class Cacherator_GrTextureMaker : public GrTextureMaker {
 public:
-    Cacherator_GrTextureParamsAdjuster(SkImageCacherator* cacher, const SkImage* client)
+    Cacherator_GrTextureMaker(SkImageCacherator* cacher, const SkImage* client)
         : INHERITED(cacher->info().width(), cacher->info().height())
         , fCacher(cacher)
         , fClient(client)
@@ -312,7 +312,7 @@
     const SkImage*          fClient;
     GrUniqueKey             fOriginalKey;
 
-    typedef GrTextureParamsAdjuster INHERITED;
+    typedef GrTextureMaker INHERITED;
 };
 
 GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams& params,
@@ -321,7 +321,7 @@
         return nullptr;
     }
 
-    return Cacherator_GrTextureParamsAdjuster(this, client).refTextureForParams(ctx, params);
+    return Cacherator_GrTextureMaker(this, client).refTextureForParams(ctx, params);
 }
 
 #else
diff --git a/src/core/SkImageCacherator.h b/src/core/SkImageCacherator.h
index ac112d7..48a2814 100644
--- a/src/core/SkImageCacherator.h
+++ b/src/core/SkImageCacherator.h
@@ -86,7 +86,7 @@
     const SkIPoint      fOrigin;
     const uint32_t      fUniqueID;
 
-    friend class Cacherator_GrTextureParamsAdjuster;
+    friend class Cacherator_GrTextureMaker;
 };
 
 #endif
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 4970a63..439fe1b 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -56,7 +56,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool GrGpu::makeCopyForTextureParams(int width, int height, const GrTextureParams& textureParams,
-                                     GrTextureParamsAdjuster::CopyParams* copyParams) const {
+                                     GrTextureProducer::CopyParams* copyParams) const {
     const GrCaps& caps = *this->caps();
     if (textureParams.isTiled() && !caps.npotTextureTileSupport() &&
         (!SkIsPow2(width) || !SkIsPow2(height))) {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 1b11c18..a2d1faf 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -384,7 +384,7 @@
     // a given GrTextureParams. If so, the width, height and filter used for the copy are
     // output via the CopyParams.
     bool makeCopyForTextureParams(int width, int height, const GrTextureParams&,
-                                 GrTextureParamsAdjuster::CopyParams*) const;
+                                  GrTextureProducer::CopyParams*) const;
 
     // This is only to be used in GL-specific tests.
     virtual const GrGLContext* glContextForTesting() const { return nullptr; }
diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp
index ee3d135..b1faf14 100644
--- a/src/gpu/GrTextureParamsAdjuster.cpp
+++ b/src/gpu/GrTextureParamsAdjuster.cpp
@@ -11,24 +11,31 @@
 #include "GrContext.h"
 #include "GrDrawContext.h"
 #include "GrGpu.h"
+#include "GrGpuResourcePriv.h"
+#include "GrResourceKey.h"
 #include "GrTexture.h"
 #include "GrTextureParams.h"
 #include "GrTextureProvider.h"
 #include "SkCanvas.h"
 #include "SkGr.h"
 #include "SkGrPriv.h"
+#include "effects/GrTextureDomain.h"
 
-typedef GrTextureParamsAdjuster::CopyParams CopyParams;
+typedef GrTextureProducer::CopyParams CopyParams;
 
-static GrTexture* copy_on_gpu(GrTexture* inputTexture, const CopyParams& copyParams) {
+//////////////////////////////////////////////////////////////////////////////
+
+static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
+                              const CopyParams& copyParams) {
+    SkASSERT(!subset || !subset->isEmpty());
     GrContext* context = inputTexture->getContext();
     SkASSERT(context);
     const GrCaps* caps = context->caps();
 
     // Either it's a cache miss or the original wasn't cached to begin with.
     GrSurfaceDesc rtDesc = inputTexture->desc();
-    rtDesc.fFlags =  rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
-    rtDesc.fWidth  = copyParams.fWidth;
+    rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
+    rtDesc.fWidth = copyParams.fWidth;
     rtDesc.fHeight = copyParams.fHeight;
     rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
 
@@ -60,27 +67,107 @@
         return nullptr;
     }
 
+    // TODO: If no scaling is being performed then use copySurface.
+
     GrPaint paint;
 
-    // If filtering is not desired then we want to ensure all texels in the resampled image are
-    // copies of texels from the original.
-    GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
-    paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
+    SkScalar sx;
+    SkScalar sy;
+    if (subset) {
+        sx = 1.f / inputTexture->width();
+        sy = 1.f / inputTexture->height();
+    }
 
-    SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
-    SkRect localRect = SkRect::MakeWH(1.f, 1.f);
+    if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset &&
+        (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
+        SkRect domain;
+        domain.fLeft = (subset->fLeft + 0.5f) * sx;
+        domain.fTop = (subset->fTop + 0.5f)* sy;
+        domain.fRight = (subset->fRight - 0.5f) * sx;
+        domain.fBottom = (subset->fBottom - 0.5f) * sy;
+        // This would cause us to read values from outside the subset. Surely, the caller knows
+        // better!
+        SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode);
+        paint.addColorFragmentProcessor(
+            GrTextureDomainEffect::Create(inputTexture, SkMatrix::I(), domain,
+                                          GrTextureDomain::kClamp_Mode,
+                                          copyParams.fFilter))->unref();
+    } else {
+        GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
+        paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
+    }
+
+    SkRect localRect;
+    if (subset) {
+        localRect = SkRect::Make(*subset);
+        localRect.fLeft *= sx;
+        localRect.fTop *= sy;
+        localRect.fRight *= sx;
+        localRect.fBottom *= sy;
+    } else {
+        localRect = SkRect::MakeWH(1.f, 1.f);
+    }
 
     SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(copy->asRenderTarget()));
     if (!drawContext) {
         return nullptr;
     }
 
-    drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect);
+    SkRect dstRect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
+    drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), dstRect, localRect);
     return copy.detach();
 }
 
-GrTexture* GrTextureParamsAdjuster::refTextureForParams(GrContext* ctx,
-                                                        const GrTextureParams& params) {
+GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, const SkIRect& subset)
+    : fOriginal(original) {
+    if (subset.fLeft > 0 || subset.fTop > 0 ||
+        subset.fRight < original->width() || subset.fBottom < original->height()) {
+        fSubset.set(subset);
+    }
+}
+
+GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& params,
+                                                      SkIPoint* outOffset) {
+    GrTexture* texture = this->originalTexture();
+    GrContext* context = texture->getContext();
+    CopyParams copyParams;
+    const SkIRect* subset = this->subset();
+
+    if (!context->getGpu()->makeCopyForTextureParams(texture->width(), texture->height(), params,
+                                                     &copyParams)) {
+        if (outOffset) {
+            if (subset) {
+                outOffset->set(subset->fLeft, subset->fRight);
+            } else {
+                outOffset->set(0, 0);
+            }
+        }
+        return SkRef(texture);
+    }
+    GrUniqueKey key;
+    this->makeCopyKey(copyParams, &key);
+    if (key.isValid()) {
+        GrTexture* result = context->textureProvider()->findAndRefTextureByUniqueKey(key);
+        if (result) {
+            return result;
+        }
+    }
+    GrTexture* result = copy_on_gpu(texture, subset, copyParams);
+    if (result) {
+        if (key.isValid()) {
+            result->resourcePriv().setUniqueKey(key);
+            this->didCacheCopy(key);
+        }
+        if (outOffset) {
+            outOffset->set(0, 0);
+        }
+    }
+    return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTextureParams& params) {
     CopyParams copyParams;
     if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
                                                  &copyParams)) {
@@ -107,11 +194,10 @@
     return result;
 }
 
-GrTexture* GrTextureParamsAdjuster::generateTextureForParams(GrContext* ctx,
-                                                             const CopyParams& copyParams) {
+GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyParams& copyParams) {
     SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx));
     if (!original) {
         return nullptr;
     }
-    return copy_on_gpu(original, copyParams);
+    return copy_on_gpu(original, nullptr, copyParams);
 }
diff --git a/src/gpu/GrTextureParamsAdjuster.h b/src/gpu/GrTextureParamsAdjuster.h
index bc08c71..c9b90a5 100644
--- a/src/gpu/GrTextureParamsAdjuster.h
+++ b/src/gpu/GrTextureParamsAdjuster.h
@@ -10,6 +10,7 @@
 
 #include "GrTextureParams.h"
 #include "GrResourceKey.h"
+#include "SkTLazy.h"
 
 class GrContext;
 class GrTexture;
@@ -20,12 +21,12 @@
 /**
  * Different GPUs and API extensions have different requirements with respect to what texture
  * sampling parameters may be used with textures of various types. This class facilitates making
- * texture compatible with a given GrTextureParams. It abstracts the source of the original data
- * which may be an already existing texture, CPU pixels, a codec, ... so that various sources can
- * be used with common code that scales or copies the data to make it compatible with a
- * GrTextureParams.
+ * texture compatible with a given GrTextureParams. There are two immediate subclasses defined
+ * below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed
+ * SkImage). It supports subsetting the original texture. The other is for use cases where the
+ * source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...).
  */
-class GrTextureParamsAdjuster {
+class GrTextureProducer : public SkNoncopyable {
 public:
     struct CopyParams {
         GrTextureParams::FilterMode fFilter;
@@ -33,13 +34,85 @@
         int                         fHeight;
     };
 
-    GrTextureParamsAdjuster(int width, int height) : fWidth(width), fHeight(height) {}
-    virtual ~GrTextureParamsAdjuster() {}
+    virtual ~GrTextureProducer() {}
+
+protected:
+    /** Helper for creating a key for a copy from an original key. */
+    static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
+                                       const CopyParams& copyParams,
+                                       GrUniqueKey* copyKey) {
+        SkASSERT(!copyKey->isValid());
+        if (origKey.isValid()) {
+            static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+            GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
+            builder[0] = copyParams.fFilter;
+            builder[1] = copyParams.fWidth;
+            builder[2] = copyParams.fHeight;
+        }
+    }
+
+    /**
+    *  If we need to make a copy in order to be compatible with GrTextureParams producer is asked to
+    *  return a key that identifies its original content + the CopyParms parameter. If the producer
+    *  does not want to cache the stretched version (e.g. the producer is volatile), this should
+    *  simply return without initializing the copyKey.
+    */
+    virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0;
+
+    /**
+    *  If a stretched version of the texture is generated, it may be cached (assuming that
+    *  makeCopyKey() returns true). In that case, the maker is notified in case it
+    *  wants to note that for when the maker is destroyed.
+    */
+    virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+/** Base class for sources that start out as textures */
+class GrTextureAdjuster : public GrTextureProducer {
+public:
+    /** Makes the subset of the texture safe to use with the given texture parameters.
+        outOffset will be the top-left corner of the subset if a copy is not made. Otherwise,
+        the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size
+        does not match subset's dimensions then the contents are scaled to fit the copy.*/
+    GrTexture* refTextureSafeForParams(const GrTextureParams&, SkIPoint* outOffset);
+
+protected:
+    /** No subset, use the whole texture */
+    explicit GrTextureAdjuster(GrTexture* original): fOriginal(original) {}
+
+    GrTextureAdjuster(GrTexture* original, const SkIRect& subset);
+
+    GrTexture* originalTexture() { return fOriginal; }
+
+    /** Returns the subset or null for the whole original texture */
+    const SkIRect* subset() { return fSubset.getMaybeNull(); }
+
+private:
+    GrTexture* internalRefTextureSafeForParams(GrTexture*, const SkIRect* subset,
+                                               const GrTextureParams&, SkIPoint* outOffset);
+    SkTLazy<SkIRect>    fSubset;
+    GrTexture*          fOriginal;
+
+    typedef GrTextureProducer INHERITED;
+};
+
+/** 
+ * Base class for sources that start out as something other than a texture (encoded image,
+ * picture, ...).
+ */
+class GrTextureMaker : public GrTextureProducer {
+public:
+
+    GrTextureMaker(int width, int height) : fWidth(width), fHeight(height) {}
 
     int width() const { return fWidth; }
     int height() const { return fHeight; }
 
-    /** Returns a texture that is safe for use with the params */
+    /** Returns a texture that is safe for use with the params. If the size of the returned texture
+        does not match width()/height() then the contents of the original must be scaled to fit
+        the texture. */
     GrTexture* refTextureForParams(GrContext*, const GrTextureParams&);
 
 protected:
@@ -51,9 +124,9 @@
     virtual GrTexture* refOriginalTexture(GrContext*) = 0;
 
     /**
-     *  If we need to copy the maker's original texture, the maker is asked to return a key
+     *  If we need to copy the producer's original texture, the producer is asked to return a key
      *  that identifies its original + the CopyParms parameter. If the maker does not want to cache
-     *  the stretched version (e.g. the maker is volatile), this should simply return without
+     *  the stretched version (e.g. the producer is volatile), this should simply return without
      *  initializing the copyKey.
      */
     virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0;
@@ -70,30 +143,11 @@
      */
     virtual GrTexture* generateTextureForParams(GrContext*, const CopyParams&);
 
-    /**
-     *  If a stretched version of the texture is generated, it may be cached (assuming that
-     *  onMakeParamsKey() returns true). In that case, the maker is notified in case it
-     *  wants to note that for when the maker is destroyed.
-     */
-    virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0;
-
-    /** Helper for creating a key for a copy from an original key. */
-    static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
-                                       const CopyParams& copyParams,
-                                       GrUniqueKey* copyKey) {
-        SkASSERT(!copyKey->isValid());
-        if (origKey.isValid()) {
-            static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
-            GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
-            builder[0] = copyParams.fFilter;
-            builder[1] = copyParams.fWidth;
-            builder[2] = copyParams.fHeight;
-        }
-    }
-
 private:
     const int fWidth;
     const int fHeight;
+
+    typedef GrTextureProducer INHERITED;
 };
 
 #endif
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 1ffd256..4685c76 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -271,12 +271,26 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-class Bitmap_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
+static void install_bmp_key_invalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
+    class Invalidator : public SkPixelRef::GenIDChangeListener {
+    public:
+        explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
+    private:
+        GrUniqueKeyInvalidatedMessage fMsg;
+
+        void onChange() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
+    };
+
+    pixelRef->addGenIDChangeListener(new Invalidator(key));
+}
+
+class RasterBitmap_GrTextureMaker : public GrTextureMaker {
 public:
-    Bitmap_GrTextureParamsAdjuster(const SkBitmap& bitmap)
+    RasterBitmap_GrTextureMaker(const SkBitmap& bitmap)
         : INHERITED(bitmap.width(), bitmap.height())
         , fBitmap(bitmap)
     {
+        SkASSERT(!bitmap.getTexture());
         if (!bitmap.isVolatile()) {
             SkIPoint origin = bitmap.pixelRefOrigin();
             SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(),
@@ -287,10 +301,7 @@
 
 protected:
     GrTexture* refOriginalTexture(GrContext* ctx) override {
-        GrTexture* tex = fBitmap.getTexture();
-        if (tex) {
-            return SkRef(tex);
-        }
+        GrTexture* tex;
 
         if (fOriginalKey.isValid()) {
             tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey);
@@ -302,7 +313,7 @@
         tex = GrUploadBitmapToTexture(ctx, fBitmap);
         if (tex && fOriginalKey.isValid()) {
             tex->resourcePriv().setUniqueKey(fOriginalKey);
-            InstallInvalidator(fOriginalKey, fBitmap.pixelRef());
+            install_bmp_key_invalidator(fOriginalKey, fBitmap.pixelRef());
         }
         return tex;
     }
@@ -314,34 +325,51 @@
     }
 
     void didCacheCopy(const GrUniqueKey& copyKey) override {
-        InstallInvalidator(copyKey, fBitmap.pixelRef());
+        install_bmp_key_invalidator(copyKey, fBitmap.pixelRef());
     }
 
 private:
-    static void InstallInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
-        class Invalidator : public SkPixelRef::GenIDChangeListener {
-        public:
-            explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
-        private:
-            GrUniqueKeyInvalidatedMessage fMsg;
-
-            void onChange() override {
-                SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
-            }
-        };
-        Invalidator* listener = new Invalidator(key);
-        pixelRef->addGenIDChangeListener(listener);
-    }
-
     const SkBitmap  fBitmap;
     GrUniqueKey     fOriginalKey;
 
-    typedef GrTextureParamsAdjuster INHERITED;
+    typedef GrTextureMaker INHERITED;
+};
+
+class TextureBitmap_GrTextureAdjuster : public GrTextureAdjuster {
+public:
+    explicit TextureBitmap_GrTextureAdjuster(const SkBitmap* bmp)
+        : INHERITED(bmp->getTexture(), SkIRect::MakeWH(bmp->width(), bmp->height()))
+        , fBmp(bmp) {}
+
+private:
+    void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) override {
+        if (fBmp->isVolatile()) {
+            return;
+        }
+        // The texture subset must represent the whole bitmap. Texture-backed bitmaps don't support
+        // extractSubset(). Therefore, either the bitmap and the teture are the same size or the
+        // subset's dimensions are the bitmap's dimensions.
+        GrUniqueKey baseKey;
+        GrMakeKeyFromImageID(&baseKey, fBmp->getGenerationID(),
+                             SkIRect::MakeWH(fBmp->width(), fBmp->height()));
+        MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
+    }
+
+    void didCacheCopy(const GrUniqueKey& copyKey) override {
+        install_bmp_key_invalidator(copyKey, fBmp->pixelRef());
+    }
+
+    const SkBitmap* fBmp;
+
+    typedef GrTextureAdjuster INHERITED;
 };
 
 GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
                                     const GrTextureParams& params) {
-    return Bitmap_GrTextureParamsAdjuster(bitmap).refTextureForParams(ctx, params);
+    if (bitmap.getTexture()) {
+        return TextureBitmap_GrTextureAdjuster(&bitmap).refTextureSafeForParams(params, nullptr);
+    }
+    return RasterBitmap_GrTextureMaker(bitmap).refTextureForParams(ctx, params);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 8e5ce45..dd4bee3 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -14,7 +14,7 @@
 #include "effects/GrYUVtoRGBEffect.h"
 #include "SkCanvas.h"
 #include "SkGpuDevice.h"
-#include "SkGr.h"
+#include "SkGrPriv.h"
 #include "SkPixelRef.h"
 
 SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex,
@@ -67,47 +67,31 @@
     return true;
 }
 
-static void make_raw_texture_stretched_key(uint32_t imageID,
-                                           const GrTextureParamsAdjuster::CopyParams& params,
-                                           GrUniqueKey* stretchedKey) {
-    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(stretchedKey, kDomain, 4);
-    builder[0] = imageID;
-    builder[1] = params.fFilter;
-    builder[2] = params.fWidth;
-    builder[3] = params.fHeight;
-}
-
-class Texture_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
+class GpuImage_GrTextureAdjuster : public GrTextureAdjuster {
 public:
-    Texture_GrTextureParamsAdjuster(const SkImage* image, GrTexture* unstretched)
-        : INHERITED(image->width(), image->height())
+    GpuImage_GrTextureAdjuster(const SkImage_Gpu* image)
+        : INHERITED(image->peekTexture())
         , fImage(image)
-        , fOriginal(unstretched)
     {}
 
 protected:
-    GrTexture* refOriginalTexture(GrContext* ctx) override {
-        return SkRef(fOriginal);
+    void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) override {
+        GrUniqueKey baseKey;
+        GrMakeKeyFromImageID(&baseKey, fImage->uniqueID(),
+                             SkIRect::MakeWH(fImage->width(), fImage->height()));
+        MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
     }
 
-    void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
-        make_raw_texture_stretched_key(fImage->uniqueID(), copyParams, copyKey);
-    }
-
-    void didCacheCopy(const GrUniqueKey& copyKey) override {
-        as_IB(fImage)->notifyAddedToCache();
-    }
+    void didCacheCopy(const GrUniqueKey& copyKey) override { as_IB(fImage)->notifyAddedToCache(); }
 
 private:
     const SkImage*  fImage;
-    GrTexture*      fOriginal;
 
-    typedef GrTextureParamsAdjuster INHERITED;
+    typedef GrTextureAdjuster INHERITED;
 };
 
 GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
-    return Texture_GrTextureParamsAdjuster(this, fTexture).refTextureForParams(ctx, params);
+    return GpuImage_GrTextureAdjuster(this).refTextureSafeForParams(params, nullptr);
 }
 
 bool SkImage_Gpu::isOpaque() const {