Put SkImageInfo on SkImage to avoid cost of reconstructing for queries.

Previously calling SkImage::alphaType(), for example, woult call
the virtual SkImage_Base::onImageInfo() which would construct
and return a temporary SkImageInfo. This often meant ref-ing a
SkColorSpace.


Change-Id: I54975a6b20dea5bc84739068df0c81c022a12067
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/202711
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 509b6f8..a7cdff0 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -32,13 +32,11 @@
 #endif
 #include "GrBackendSurface.h"
 
-SkImage::SkImage(int width, int height, uint32_t uniqueID)
-    : fWidth(width)
-    , fHeight(height)
-    , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
-{
-    SkASSERT(width > 0);
-    SkASSERT(height > 0);
+SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
+        : fInfo(info)
+        , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {
+    SkASSERT(info.width() > 0);
+    SkASSERT(info.height() > 0);
 }
 
 bool SkImage::peekPixels(SkPixmap* pm) const {
@@ -49,8 +47,8 @@
     return as_IB(this)->onPeekPixels(pm);
 }
 
-bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
-                           int srcX, int srcY, CachingHint chint) const {
+bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX,
+                         int srcY, CachingHint chint) const {
     return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
 }
 
@@ -76,21 +74,13 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-SkColorType SkImage::colorType() const {
-    return as_IB(this)->onImageInfo().colorType();
-}
+SkColorType SkImage::colorType() const { return fInfo.colorType(); }
 
-SkAlphaType SkImage::alphaType() const {
-    return as_IB(this)->onImageInfo().alphaType();
-}
+SkAlphaType SkImage::alphaType() const { return fInfo.alphaType(); }
 
-SkColorSpace* SkImage::colorSpace() const {
-    return as_IB(this)->onImageInfo().colorSpace();
-}
+SkColorSpace* SkImage::colorSpace() const { return fInfo.colorSpace(); }
 
-sk_sp<SkColorSpace> SkImage::refColorSpace() const {
-    return as_IB(this)->onImageInfo().refColorSpace();
-}
+sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace(); }
 
 sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
                                     const SkMatrix* localMatrix) const {
@@ -192,10 +182,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID)
-    : INHERITED(width, height, uniqueID)
-    , fAddedToRasterCache(false)
-{}
+SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
+        : INHERITED(info, uniqueID), fAddedToRasterCache(false) {}
 
 SkImage_Base::~SkImage_Base() {
     if (fAddedToRasterCache.load()) {
@@ -234,7 +222,7 @@
 bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap) const {
     // As the base-class, all we can do is make a copy (regardless of mode).
     // Subclasses that want to be more optimal should override.
-    SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
+    SkImageInfo info = fInfo.makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
     if (!bitmap->tryAllocPixels(info)) {
         return false;
     }
@@ -282,8 +270,7 @@
 
     sk_sp<SkImageFilterCache> cache(
         SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
-    SkImageFilter::OutputProperties outputProperties(as_IB(this)->onImageInfo().colorType(),
-                                                     as_IB(this)->onImageInfo().colorSpace());
+    SkImageFilter::OutputProperties outputProperties(fInfo.colorType(), fInfo.colorSpace());
     SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties);
 
     sk_sp<SkSpecialImage> result = filter->filterImage(srcSpecialImage.get(), context, offset);
@@ -307,9 +294,7 @@
     return as_IB(this)->onIsLazyGenerated();
 }
 
-bool SkImage::isAlphaOnly() const {
-    return as_IB(this)->onImageInfo().colorType() == kAlpha_8_SkColorType;
-}
+bool SkImage::isAlphaOnly() const { return SkColorTypeIsAlphaOnly(fInfo.colorType()); }
 
 sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target) const {
     if (!target) {
@@ -374,20 +359,19 @@
         return sk_ref_sp(const_cast<SkImage*>(this));
     }
 
-    const SkImageInfo info = as_IB(this)->onImageInfo();
-    const size_t rowBytes = info.minRowBytes();
-    size_t size = info.computeByteSize(rowBytes);
+    const size_t rowBytes = fInfo.minRowBytes();
+    size_t size = fInfo.computeByteSize(rowBytes);
     if (SkImageInfo::ByteSizeOverflowed(size)) {
         return nullptr;
     }
 
     sk_sp<SkData> data = SkData::MakeUninitialized(size);
-    pm = { info.makeColorSpace(nullptr), data->writable_data(), info.minRowBytes() };
+    pm = {fInfo.makeColorSpace(nullptr), data->writable_data(), fInfo.minRowBytes()};
     if (!this->readPixels(pm, 0, 0)) {
         return nullptr;
     }
 
-    return SkImage::MakeRasterData(info, std::move(data), rowBytes);
+    return SkImage::MakeRasterData(fInfo, std::move(data), rowBytes);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -498,7 +482,7 @@
 sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src,
                                                         SkColorSpace* colorSpace) {
     // Read the pixels out of the source image, with no conversion
-    SkImageInfo info = as_IB(src)->onImageInfo();
+    const SkImageInfo& info = src->imageInfo();
     if (kUnknown_SkColorType == info.colorType()) {
         SkDEBUGFAIL("Unexpected color type");
         return nullptr;
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index bb1a981..e37a0b5 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -34,11 +34,6 @@
 public:
     virtual ~SkImage_Base();
 
-    // User: returns image info for this SkImage.
-    // Implementors: if you can not return the value, return an invalid ImageInfo with w=0 & h=0
-    // & unknown color space.
-    virtual SkImageInfo onImageInfo() const = 0;
-
     virtual SkIRect onGetSubset() const {
         return { 0, 0, this->width(), this->height() };
     }
@@ -104,7 +99,7 @@
     virtual sk_sp<SkImage> onMakeColorTypeAndColorSpace(GrRecordingContext*,
                                                         SkColorType, sk_sp<SkColorSpace>) const = 0;
 protected:
-    SkImage_Base(int width, int height, uint32_t uniqueID);
+    SkImage_Base(const SkImageInfo& info, uint32_t uniqueID);
 
 private:
     // Set true by caches when they cache content that's derived from the current pixels.
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 4fec2ea..ff81401 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -48,23 +48,22 @@
 #include "effects/GrYUVtoRGBEffect.h"
 #include "gl/GrGLTexture.h"
 
+static SkColorType proxy_color_type(GrTextureProxy* proxy) {
+    SkColorType colorType;
+    if (!GrPixelConfigToColorType(proxy->config(), &colorType)) {
+        colorType = kUnknown_SkColorType;
+    }
+    return colorType;
+}
+
 SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at,
                          sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace)
         : INHERITED(std::move(context), proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID,
-                    at, colorSpace)
+                    proxy_color_type(proxy.get()), at, colorSpace)
         , fProxy(std::move(proxy)) {}
 
 SkImage_Gpu::~SkImage_Gpu() {}
 
-SkImageInfo SkImage_Gpu::onImageInfo() const {
-    SkColorType colorType;
-    if (!GrPixelConfigToColorType(fProxy->config(), &colorType)) {
-        colorType = kUnknown_SkColorType;
-    }
-
-    return SkImageInfo::Make(fProxy->width(), fProxy->height(), colorType, fAlphaType, fColorSpace);
-}
-
 sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(GrRecordingContext* context,
                                                          SkColorType targetCT,
                                                          sk_sp<SkColorSpace> targetCS) const {
@@ -72,8 +71,8 @@
         return nullptr;
     }
 
-    auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), fAlphaType,
-                                               targetCS.get(), fAlphaType);
+    auto xform = GrColorSpaceXformEffect::Make(this->colorSpace(), this->alphaType(),
+                                               targetCS.get(), this->alphaType());
     SkASSERT(xform || targetCT != this->colorType());
 
     sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef(context);
@@ -105,7 +104,7 @@
     }
 
     // MDB: this call is okay bc we know 'renderTargetContext' was exact
-    return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fAlphaType,
+    return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, this->alphaType(),
                                    renderTargetContext->asTextureProxyRef(), std::move(targetCS));
 }
 
@@ -469,7 +468,7 @@
     if (limitToMaxTextureSize &&
         (codecImage->width() > maxTextureSize || codecImage->height() > maxTextureSize)) {
         SkAutoPixmapStorage pmap;
-        SkImageInfo info = as_IB(codecImage)->onImageInfo();
+        SkImageInfo info = codecImage->imageInfo();
         if (!dstColorSpace) {
             info = info.makeColorSpace(nullptr);
         }
@@ -504,11 +503,9 @@
     GrGpu* gpu = context->priv().getGpu();
     sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
 
-    auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
-                                                    std::move(sema),
-                                                    as_IB(codecImage)->onImageInfo().colorType(),
-                                                    codecImage->alphaType(),
-                                                    codecImage->refColorSpace());
+    auto gen = GrBackendTextureImageGenerator::Make(
+            std::move(texture), proxy->origin(), std::move(sema), codecImage->colorType(),
+            codecImage->alphaType(), codecImage->refColorSpace());
     return SkImage::MakeFromGenerator(std::move(gen));
 }
 
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index 39ba49e..f381f22 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -26,8 +26,6 @@
                 sk_sp<SkColorSpace>);
     ~SkImage_Gpu() override;
 
-    SkImageInfo onImageInfo() const override;
-
     GrTextureProxy* peekProxy() const override {
         return fProxy.get();
     }
diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp
index fe3d5ba..12c4b54 100644
--- a/src/image/SkImage_GpuBase.cpp
+++ b/src/image/SkImage_GpuBase.cpp
@@ -23,11 +23,9 @@
 #include "effects/GrYUVtoRGBEffect.h"
 
 SkImage_GpuBase::SkImage_GpuBase(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
-                                 SkAlphaType at, sk_sp<SkColorSpace> cs)
-        : INHERITED(width, height, uniqueID)
-        , fContext(std::move(context))
-        , fAlphaType(at)
-        , fColorSpace(std::move(cs)) {}
+                                 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs)
+        : INHERITED(SkImageInfo::Make(width, height, ct, at, std::move(cs)), uniqueID)
+        , fContext(std::move(context)) {}
 
 SkImage_GpuBase::~SkImage_GpuBase() {}
 
@@ -79,18 +77,18 @@
     SkBitmapCache::RecPtr rec = nullptr;
     SkPixmap pmap;
     if (kAllow_CachingHint == chint) {
-        rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
+        rec = SkBitmapCache::Alloc(desc, this->imageInfo(), &pmap);
         if (!rec) {
             return false;
         }
     } else {
-        if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
+        if (!dst->tryAllocPixels(this->imageInfo()) || !dst->peekPixels(&pmap)) {
             return false;
         }
     }
 
     sk_sp<GrSurfaceContext> sContext = direct->priv().makeWrappedSurfaceContext(
-        this->asTextureProxyRef(direct), fColorSpace);
+            this->asTextureProxyRef(direct), this->refColorSpace());
     if (!sContext) {
         return false;
     }
@@ -137,7 +135,7 @@
     }
 
     // MDB: this call is okay bc we know 'sContext' was kExact
-    return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fAlphaType,
+    return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, this->alphaType(),
                                    sContext->asTextureProxyRef(), this->refColorSpace());
 }
 
@@ -171,7 +169,7 @@
         return false;
     }
 
-    if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
+    if (!SkImageInfoValidConversion(dstInfo, this->imageInfo())) {
         return false;
     }
 
@@ -183,7 +181,8 @@
     // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
     // GrRenderTargetContext::onReadPixels
     uint32_t flags = 0;
-    if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
+    if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() &&
+        kPremul_SkAlphaType == this->alphaType()) {
         // let the GPU perform this transformation for us
         flags = GrContextPriv::kUnpremul_PixelOpsFlag;
     }
@@ -206,7 +205,8 @@
     //
     // Should this be handled by Ganesh? todo:?
     //
-    if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
+    if (kPremul_SkAlphaType == rec.fInfo.alphaType() &&
+        kUnpremul_SkAlphaType == this->alphaType()) {
         apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
     }
     return true;
@@ -220,8 +220,8 @@
         return nullptr;
     }
 
-    GrTextureAdjuster adjuster(fContext.get(), this->asTextureProxyRef(context), fAlphaType,
-                               this->uniqueID(), fColorSpace.get());
+    GrTextureAdjuster adjuster(fContext.get(), this->asTextureProxyRef(context), this->alphaType(),
+                               this->uniqueID(), this->colorSpace());
     return adjuster.refTextureProxyForParams(params, scaleAdjust);
 }
 
diff --git a/src/image/SkImage_GpuBase.h b/src/image/SkImage_GpuBase.h
index ad5fc1d..d5a3665 100644
--- a/src/image/SkImage_GpuBase.h
+++ b/src/image/SkImage_GpuBase.h
@@ -20,8 +20,8 @@
 
 class SkImage_GpuBase : public SkImage_Base {
 public:
-    SkImage_GpuBase(sk_sp<GrContext>, int width, int height, uint32_t uniqueID, SkAlphaType,
-                    sk_sp<SkColorSpace>);
+    SkImage_GpuBase(sk_sp<GrContext>, int width, int height, uint32_t uniqueID, SkColorType,
+                    SkAlphaType, sk_sp<SkColorSpace>);
     ~SkImage_GpuBase() override;
 
     GrContext* context() const final { return fContext.get(); }
@@ -94,9 +94,7 @@
                                  const sk_sp<GrTextureProxy> proxies[4],
                                  const SkYUVAIndex yuvaIndices[4]);
 
-    sk_sp<GrContext>      fContext;
-    const SkAlphaType     fAlphaType;  // alpha type for final image
-    sk_sp<SkColorSpace>   fColorSpace; // color space for final image
+    sk_sp<GrContext> fContext;
 
 private:
     typedef SkImage_Base INHERITED;
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index ffa801c..a53bfc7 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -27,15 +27,17 @@
 #include "SkYUVASizeInfo.h"
 #include "effects/GrYUVtoRGBEffect.h"
 
+static constexpr auto kAssumedColorType = kRGBA_8888_SkColorType;
+
 SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
                                  SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
                                  int numProxies, const SkYUVAIndex yuvaIndices[4],
                                  GrSurfaceOrigin origin, sk_sp<SkColorSpace> imageColorSpace)
-        : INHERITED(std::move(context), width, height, uniqueID,
+        : INHERITED(std::move(context), width, height, uniqueID, kAssumedColorType,
                     // If an alpha channel is present we always switch to kPremul. This is because,
                     // although the planar data is always un-premul, the final interleaved RGB image
                     // is/would-be premul.
-                    GetAlphaTypeFromYUVAIndices(yuvaIndices), imageColorSpace)
+                    GetAlphaTypeFromYUVAIndices(yuvaIndices), std::move(imageColorSpace))
         , fNumProxies(numProxies)
         , fYUVColorSpace(colorSpace)
         , fOrigin(origin) {
@@ -52,16 +54,19 @@
 
 // For onMakeColorSpace()
 SkImage_GpuYUVA::SkImage_GpuYUVA(const SkImage_GpuYUVA* image, sk_sp<SkColorSpace> targetCS)
-    : INHERITED(image->fContext, image->width(), image->height(), kNeedNewImageUniqueID,
-                // If an alpha channel is present we always switch to kPremul. This is because,
-                // although the planar data is always un-premul, the final interleaved RGB image
-                // is/would-be premul.
-                GetAlphaTypeFromYUVAIndices(image->fYUVAIndices), image->fColorSpace)
-    , fNumProxies(image->fNumProxies)
-    , fYUVColorSpace(image->fYUVColorSpace)
-    , fOrigin(image->fOrigin)
-    , fTargetColorSpace(targetCS) {
-        // The caller should have done this work, just verifying
+        : INHERITED(image->fContext, image->width(), image->height(), kNeedNewImageUniqueID,
+                    kAssumedColorType,
+                    // If an alpha channel is present we always switch to kPremul. This is because,
+                    // although the planar data is always un-premul, the final interleaved RGB image
+                    // is/would-be premul.
+                    GetAlphaTypeFromYUVAIndices(image->fYUVAIndices), std::move(targetCS))
+        , fNumProxies(image->fNumProxies)
+        , fYUVColorSpace(image->fYUVColorSpace)
+        , fOrigin(image->fOrigin)
+        // Since null fFromColorSpace means no GrColorSpaceXform, we turn a null
+        // image->refColorSpace() into an explicit SRGB.
+        , fFromColorSpace(image->colorSpace() ? image->refColorSpace() : SkColorSpace::MakeSRGB()) {
+    // The caller should have done this work, just verifying
     SkDEBUGCODE(int textureCount;)
         SkASSERT(SkYUVAIndex::AreValidIndices(image->fYUVAIndices, &textureCount));
     SkASSERT(textureCount == fNumProxies);
@@ -74,12 +79,6 @@
 
 SkImage_GpuYUVA::~SkImage_GpuYUVA() {}
 
-SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
-    // Note: this is the imageInfo for the flattened image, not the YUV planes
-    return SkImageInfo::Make(this->width(), this->height(), kRGBA_8888_SkColorType,
-                             fAlphaType, fTargetColorSpace ? fTargetColorSpace : fColorSpace);
-}
-
 bool SkImage_GpuYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const {
     if (!context || !fContext->priv().matches(context)) {
         return false;
@@ -118,19 +117,22 @@
     }
 
     const GrBackendFormat format =
-        fContext->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
+        fContext->priv().caps()->getBackendFormatFromColorType(kAssumedColorType);
 
     // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
     sk_sp<GrRenderTargetContext> renderTargetContext(
-        context->priv().makeDeferredRenderTargetContext(
-            format, SkBackingFit::kExact, this->width(), this->height(),
-            kRGBA_8888_GrPixelConfig, fColorSpace, 1, GrMipMapped::kNo, fOrigin));
+            context->priv().makeDeferredRenderTargetContext(
+                    format, SkBackingFit::kExact, this->width(), this->height(),
+                    kRGBA_8888_GrPixelConfig, this->refColorSpace(), 1, GrMipMapped::kNo, fOrigin));
     if (!renderTargetContext) {
         return nullptr;
     }
 
-    auto colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), fAlphaType,
-                                                    fTargetColorSpace.get(), fAlphaType);
+    sk_sp<GrColorSpaceXform> colorSpaceXform;
+    if (fFromColorSpace) {
+        colorSpaceXform = GrColorSpaceXform::Make(fFromColorSpace.get(), this->alphaType(),
+                                                  this->colorSpace(), this->alphaType());
+    }
     const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
     if (!RenderYUVAToRGBA(fContext.get(), renderTargetContext.get(), rect, fYUVColorSpace,
                           std::move(colorSpaceXform), fProxies, fYUVAIndices)) {
@@ -314,7 +316,7 @@
 
     SkAlphaType at = (-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex) ? kPremul_SkAlphaType
                                                                        : kOpaque_SkAlphaType;
-    SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kRGBA_8888_SkColorType,
+    SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kAssumedColorType,
                                          at, imageColorSpace);
     if (!SkImageInfoIsValid(info)) {
         return nullptr;
diff --git a/src/image/SkImage_GpuYUVA.h b/src/image/SkImage_GpuYUVA.h
index 4f01735..eb4783f 100644
--- a/src/image/SkImage_GpuYUVA.h
+++ b/src/image/SkImage_GpuYUVA.h
@@ -29,8 +29,6 @@
                     GrSurfaceOrigin, sk_sp<SkColorSpace>);
     ~SkImage_GpuYUVA() override;
 
-    SkImageInfo onImageInfo() const override;
-
     // This returns the single backing proxy if the YUV channels have already been flattened but
     // nullptr if they have not.
     GrTextureProxy* peekProxy() const override;
@@ -86,7 +84,10 @@
     SkYUVAIndex                      fYUVAIndices[4];
     const SkYUVColorSpace            fYUVColorSpace;
     GrSurfaceOrigin                  fOrigin;
-    const sk_sp<SkColorSpace>        fTargetColorSpace;
+    // If this is non-null then the planar data should be converted from fFromColorSpace to
+    // this->colorSpace(). Otherwise we assume the planar data (post YUV->RGB conversion) is already
+    // in this->colorSpace().
+    const sk_sp<SkColorSpace> fFromColorSpace;
 
     // Repeated calls to onMakeColorSpace will result in a proliferation of unique IDs and
     // SkImage_GpuYUVA instances. Cache the result of the last successful onMakeColorSpace call.
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index ad69750..40f28c8 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -123,9 +123,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SkImage_Lazy::SkImage_Lazy(Validator* validator)
-        : INHERITED(validator->fInfo.width(), validator->fInfo.height(), validator->fUniqueID)
+        : INHERITED(validator->fInfo, validator->fUniqueID)
         , fSharedGenerator(std::move(validator->fSharedGenerator))
-        , fInfo(validator->fInfo)
         , fOrigin(validator->fOrigin) {
     SkASSERT(fSharedGenerator);
     fUniqueID = validator->fUniqueID;
@@ -193,7 +192,7 @@
 
     if (SkImage::kAllow_CachingHint == chint) {
         SkPixmap pmap;
-        SkBitmapCache::RecPtr cacheRec = SkBitmapCache::Alloc(desc, fInfo, &pmap);
+        SkBitmapCache::RecPtr cacheRec = SkBitmapCache::Alloc(desc, this->imageInfo(), &pmap);
         if (!cacheRec ||
             !generate_pixels(ScopedGenerator(fSharedGenerator), pmap,
                              fOrigin.x(), fOrigin.y())) {
@@ -202,9 +201,9 @@
         SkBitmapCache::Add(std::move(cacheRec), bitmap);
         this->notifyAddedToRasterCache();
     } else {
-        if (!bitmap->tryAllocPixels(fInfo) ||
-            !generate_pixels(ScopedGenerator(fSharedGenerator), bitmap->pixmap(),
-                             fOrigin.x(), fOrigin.y())) {
+        if (!bitmap->tryAllocPixels(this->imageInfo()) ||
+            !generate_pixels(ScopedGenerator(fSharedGenerator), bitmap->pixmap(), fOrigin.x(),
+                             fOrigin.y())) {
             return false;
         }
         bitmap->setImmutable();
@@ -252,12 +251,12 @@
 
 sk_sp<SkImage> SkImage_Lazy::onMakeSubset(GrRecordingContext* context,
                                           const SkIRect& subset) const {
-    SkASSERT(fInfo.bounds().contains(subset));
-    SkASSERT(fInfo.bounds() != subset);
+    SkASSERT(this->bounds().contains(subset));
+    SkASSERT(this->bounds() != subset);
 
     const SkIRect generatorSubset = subset.makeOffset(fOrigin.x(), fOrigin.y());
-    const SkColorType colorType = fInfo.colorType();
-    Validator validator(fSharedGenerator, &generatorSubset, &colorType, fInfo.refColorSpace());
+    const SkColorType colorType = this->colorType();
+    Validator validator(fSharedGenerator, &generatorSubset, &colorType, this->refColorSpace());
     return validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
 }
 
@@ -271,7 +270,7 @@
         return fOnMakeColorTypeAndSpaceResult;
     }
     const SkIRect generatorSubset =
-            SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height());
+            SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), this->width(), this->height());
     Validator validator(fSharedGenerator, &generatorSubset, &targetCT, targetCS);
     sk_sp<SkImage> result = validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
     if (result) {
@@ -414,7 +413,7 @@
                 SkImageGenerator::TexGenType::kCheap != generator->onCanGenerateTexture()) {
             return nullptr;
         }
-        if ((proxy = generator->generateTexture(ctx, fInfo, fOrigin, willBeMipped))) {
+        if ((proxy = generator->generateTexture(ctx, this->imageInfo(), fOrigin, willBeMipped))) {
             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
                                      kLockTexturePathCount);
             set_key_on_proxy(proxyProvider, proxy.get(), nullptr, key);
@@ -429,9 +428,9 @@
     // 3. Ask the generator to return YUV planes, which the GPU can convert. If we will be mipping
     //    the texture we fall through here and have the CPU generate the mip maps for us.
     if (!proxy && !willBeMipped && !ctx->priv().options().fDisableGpuYUVConversion) {
-        const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(fInfo);
+        const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(this->imageInfo());
 
-        SkColorType colorType = fInfo.colorType();
+        SkColorType colorType = this->colorType();
         GrBackendFormat format =
                 ctx->priv().caps()->getBackendFormatFromColorType(colorType);
 
@@ -443,7 +442,7 @@
         // color space. To correct this, apply a color space conversion from the generator's color
         // space to this image's color space.
         SkColorSpace* generatorColorSpace = fSharedGenerator->fGenerator->getInfo().colorSpace();
-        SkColorSpace* thisColorSpace = fInfo.colorSpace();
+        SkColorSpace* thisColorSpace = this->colorSpace();
 
         // TODO: Update to create the mipped surface in the YUV generator and draw the base
         // layer directly into the mipped surface.
diff --git a/src/image/SkImage_Lazy.h b/src/image/SkImage_Lazy.h
index 8578558..6c9d2b7 100644
--- a/src/image/SkImage_Lazy.h
+++ b/src/image/SkImage_Lazy.h
@@ -35,12 +35,8 @@
     SkImage_Lazy(Validator* validator);
     ~SkImage_Lazy() override;
 
-    SkImageInfo onImageInfo() const override {
-        return fInfo;
-    }
-
     SkIRect onGetSubset() const override {
-        return SkIRect::MakeXYWH(fOrigin.fX, fOrigin.fY, fInfo.width(), fInfo.height());
+        return SkIRect::MakeXYWH(fOrigin.fX, fOrigin.fY, this->width(), this->height());
     }
 
     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY,
@@ -77,10 +73,10 @@
 private:
     class ScopedGenerator;
 
+    // Note that this->imageInfo() is not necessarily the info from the generator. It may be
+    // cropped by onMakeSubset and its color type/space may be changed by
+    // onMakeColorTypeAndColorSpace.
     sk_sp<SharedGenerator> fSharedGenerator;
-    // Note that fInfo is not necessarily the info from the generator. It may be cropped by
-    // onMakeSubset and its color type/space may be changed by onMakeColorTypeAndColorSpace.
-    const SkImageInfo      fInfo;
     const SkIPoint         fOrigin;
 
     uint32_t fUniqueID;
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 296f34a..8646e38 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -72,10 +72,6 @@
                    uint32_t id = kNeedNewImageUniqueID);
     ~SkImage_Raster() override;
 
-    SkImageInfo onImageInfo() const override {
-        return fBitmap.info();
-    }
-
     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
     bool onPeekPixels(SkPixmap*) const override;
     const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
@@ -93,11 +89,9 @@
     bool onAsLegacyBitmap(SkBitmap*) const override;
 
     SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
-        : INHERITED(bm.width(), bm.height(),
-                    is_not_subset(bm) ? bm.getGenerationID()
-                                      : (uint32_t)kNeedNewImageUniqueID)
-        , fBitmap(bm)
-    {
+            : INHERITED(bm.info(),
+                        is_not_subset(bm) ? bm.getGenerationID() : (uint32_t)kNeedNewImageUniqueID)
+            , fBitmap(bm) {
         SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
     }
 
@@ -141,8 +135,7 @@
 
 SkImage_Raster::SkImage_Raster(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes,
                                uint32_t id)
-    : INHERITED(info.width(), info.height(), id)
-{
+        : INHERITED(info, id) {
     void* addr = const_cast<void*>(data->data());
 
     fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());