Add alphaType() to SkImage

Keep isOpaque as a convenience method -- many places really only need to
know that for optimization purposes (SrcOver -> Src, etc...).

In all the places where we pull data back out or convert to another
object and need to supply an SkImageInfo, we can avoid losing information
about premulness.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2250663002

Review-Url: https://codereview.chromium.org/2250663002
diff --git a/gm/image.cpp b/gm/image.cpp
index a67ed20..400d421 100644
--- a/gm/image.cpp
+++ b/gm/image.cpp
@@ -303,8 +303,7 @@
 #include "SkImageGenerator.h"
 
 static SkImageInfo make_info(SkImage* img) {
-    return SkImageInfo::MakeN32(img->width(), img->height(),
-                                img->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+    return SkImageInfo::MakeN32(img->width(), img->height(), img->alphaType());
 }
 
 // Its simple, but I wonder if we should expose this formally?
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index fd20e5e..bdcb5b0 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -166,7 +166,8 @@
     SkISize dimensions() const { return SkISize::Make(fWidth, fHeight); }
     SkIRect bounds() const { return SkIRect::MakeWH(fWidth, fHeight); }
     uint32_t uniqueID() const { return fUniqueID; }
-    virtual bool isOpaque() const { return false; }
+    SkAlphaType alphaType() const;
+    bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); }
 
     /**
      * Extracts YUV planes from the SkImage and stores them in client-provided memory. The sizes
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index b8c8964..fa3580c 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -106,6 +106,10 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+SkAlphaType SkImage::alphaType() const {
+    return as_IB(this)->onAlphaType();
+}
+
 sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
                                     const SkMatrix* localMatrix) const {
     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tileX, tileY, localMatrix);
@@ -320,7 +324,7 @@
     // 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)
-            .makeAlphaType(this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+            .makeAlphaType(this->alphaType());
     if (!bitmap->tryAllocPixels(info)) {
         return false;
     }
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index a1da0fa..7ebedeb 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -34,6 +34,7 @@
     // 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 SkAlphaType onAlphaType() const = 0;
 
     virtual bool onPeekPixels(SkPixmap*) const { return false; }
 
diff --git a/src/image/SkImage_Generator.cpp b/src/image/SkImage_Generator.cpp
index 20f4863..412f573 100644
--- a/src/image/SkImage_Generator.cpp
+++ b/src/image/SkImage_Generator.cpp
@@ -24,11 +24,13 @@
     virtual SkImageInfo onImageInfo() const override {
         return fCache->info();
     }
+    SkAlphaType onAlphaType() const override {
+        return fCache->info().alphaType();
+    }
 
     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
     SkImageCacherator* peekCacherator() const override { return fCache; }
     SkData* onRefEncoded(GrContext*) const override;
-    bool isOpaque() const override { return fCache->info().isOpaque(); }
     sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
     bool getROPixels(SkBitmap*, CachingHint) const override;
     GrTexture* asTextureRef(GrContext*, const GrTextureParams&,
@@ -84,7 +86,7 @@
     // For now, we do effectively what we did before, make it a raster
 
     const SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(),
-                                      this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+                                                  this->alphaType());
     auto surface(SkSurface::MakeRaster(info));
     if (!surface) {
         return nullptr;
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 76f19bc..eba66f4 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -51,9 +51,8 @@
     return SkImageInfo::Make(fTexture->width(), fTexture->height(), ct, fAlphaType, fColorSpace);
 }
 
-static SkImageInfo make_info(int w, int h, bool isOpaque, sk_sp<SkColorSpace> colorSpace) {
-    return SkImageInfo::MakeN32(w, h, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
-                                std::move(colorSpace));
+static SkImageInfo make_info(int w, int h, SkAlphaType at, sk_sp<SkColorSpace> colorSpace) {
+    return SkImageInfo::MakeN32(w, h, at, std::move(colorSpace));
 }
 
 bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const {
@@ -64,7 +63,7 @@
         return true;
     }
 
-    if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->isOpaque(),
+    if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->alphaType(),
                                        this->fColorSpace))) {
         return false;
     }
@@ -88,10 +87,6 @@
     return adjuster.refTextureSafeForParams(params, gammaTreatment, nullptr);
 }
 
-bool SkImage_Gpu::isOpaque() const {
-    return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
-}
-
 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
     switch (info.colorType()) {
         case kRGBA_8888_SkColorType:
@@ -309,17 +304,15 @@
     if (GrTexture* peek = as_IB(this)->peekTexture()) {
         return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
     }
-    // No way to check whether a image is premul or not?
-    SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
 
     if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
         GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
-        return create_image_from_maker(&maker, at, this->uniqueID());
+        return create_image_from_maker(&maker, this->alphaType(), this->uniqueID());
     }
 
     if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
         GrBitmapTextureMaker maker(context, *bmp);
-        return create_image_from_maker(&maker, at, this->uniqueID());
+        return create_image_from_maker(&maker, this->alphaType(), this->uniqueID());
     }
     return nullptr;
 }
@@ -445,8 +438,7 @@
         if (!data && !this->peekPixels(nullptr)) {
             return 0;
         }
-        SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
-        info = SkImageInfo::MakeN32(scaledSize.width(), scaledSize.height(), at);
+        info = SkImageInfo::MakeN32(scaledSize.width(), scaledSize.height(), this->alphaType());
         pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
         if (fillMode) {
             pixmap.alloc(info);
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index 44949a1..a9d9c33 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -28,6 +28,7 @@
     ~SkImage_Gpu() override;
 
     SkImageInfo onImageInfo() const override;
+    SkAlphaType onAlphaType() const override { return fAlphaType; }
 
     void applyBudgetDecision() const {
         if (SkBudgeted::kYes == fBudgeted) {
@@ -47,7 +48,6 @@
         *uniqueID = this->uniqueID();
         return sk_ref_sp(fTexture.get());
     }
-    bool isOpaque() const override;
     bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes,
                       int srcX, int srcY, CachingHint) const override;
 
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index acfacea..d334dfb 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -79,6 +79,9 @@
     SkImageInfo onImageInfo() const override {
         return fBitmap.info();
     }
+    SkAlphaType onAlphaType() const override {
+        return fBitmap.alphaType();
+    }
 
     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
     bool onPeekPixels(SkPixmap*) const override;
@@ -95,7 +98,6 @@
 
     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
 
-    bool isOpaque() const override;
     bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
 
     SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
@@ -359,10 +361,6 @@
     return ((const SkImage_Raster*)image)->getPixelRef();
 }
 
-bool SkImage_Raster::isOpaque() const {
-    return fBitmap.isOpaque();
-}
-
 bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
     if (kRO_LegacyBitmapMode == mode) {
         // When we're a snapshot from a surface, our bitmap may not be marked immutable
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
index 887bca4..772745c 100644
--- a/src/pdf/SkPDFBitmap.cpp
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -32,8 +32,7 @@
         }
     }
     // no pixels or wrong size: fill with zeros.
-    SkAlphaType at = image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
-    dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), at));
+    dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
 }
 
 bool image_compute_is_opaque(const SkImage* image) {
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index ca4788c..fa22641 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -43,8 +43,7 @@
     // see https://bug.skia.org/3965
     //REPORTER_ASSERT(reporter, a->isOpaque() == b->isOpaque());
 
-    SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA,
-                                        a->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+    SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA, a->alphaType());
     SkAutoPixmapStorage pmapA, pmapB;
     pmapA.alloc(info);
     pmapB.alloc(info);
@@ -505,8 +504,8 @@
         if (image->width() != texImage->width() || image->height() != texImage->height()) {
             ERRORF(reporter, "newTextureImage changed the image size.");
         }
-        if (image->isOpaque() != texImage->isOpaque()) {
-            ERRORF(reporter, "newTextureImage changed image opaqueness.");
+        if (image->alphaType() != texImage->alphaType()) {
+            ERRORF(reporter, "newTextureImage changed image alpha type.");
         }
     }
 }
@@ -669,7 +668,7 @@
                                 const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) {
     REPORTER_ASSERT(reporter, image->width() == bitmap.width());
     REPORTER_ASSERT(reporter, image->height() == bitmap.height());
-    REPORTER_ASSERT(reporter, image->isOpaque() == bitmap.isOpaque());
+    REPORTER_ASSERT(reporter, image->alphaType() == bitmap.alphaType());
 
     if (SkImage::kRO_LegacyBitmapMode == mode) {
         REPORTER_ASSERT(reporter, bitmap.isImmutable());
@@ -812,8 +811,8 @@
         ERRORF(reporter, "Images must have the same size");
         return;
     }
-    if (a->isOpaque() != b->isOpaque()) {
-        ERRORF(reporter, "Images must have the same opaquness");
+    if (a->alphaType() != b->alphaType()) {
+        ERRORF(reporter, "Images must have the same alpha type");
         return;
     }
 
@@ -948,9 +947,9 @@
                     if (newImage) {
                         // Scale the image in software for comparison.
                         SkImageInfo scaled_info = SkImageInfo::MakeN32(
-                                image->width() / testCase.fExpectedScaleFactor,
-                                image->height() / testCase.fExpectedScaleFactor,
-                                image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+                                                    image->width() / testCase.fExpectedScaleFactor,
+                                                    image->height() / testCase.fExpectedScaleFactor,
+                                                    image->alphaType());
                         SkAutoPixmapStorage scaled;
                         scaled.alloc(scaled_info);
                         image->scalePixels(scaled, testCase.fExpectedQuality);
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 87c3a52..2703b54 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -128,32 +128,31 @@
 #endif
 
 static void test_snapshot_alphatype(skiatest::Reporter* reporter, const sk_sp<SkSurface>& surface,
-                                    bool expectOpaque) {
+                                    SkAlphaType expectedAlphaType) {
     REPORTER_ASSERT(reporter, surface);
     if (surface) {
         sk_sp<SkImage> image(surface->makeImageSnapshot());
         REPORTER_ASSERT(reporter, image);
         if (image) {
-            REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(expectOpaque));
+            REPORTER_ASSERT(reporter, image->alphaType() == expectedAlphaType);
         }
     }
 }
 DEF_TEST(SurfaceSnapshotAlphaType, reporter) {
     for (auto& surface_func : { &create_surface, &create_direct_surface }) {
-        for (auto& isOpaque : { true, false }) {
-            SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
-            auto surface(surface_func(alphaType, nullptr));
-            test_snapshot_alphatype(reporter, surface, isOpaque);
+        for (auto& at: { kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
+            auto surface(surface_func(at, nullptr));
+            test_snapshot_alphatype(reporter, surface, at);
         }
     }
 }
 #if SK_SUPPORT_GPU
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceSnapshotAlphaType_Gpu, reporter, ctxInfo) {
     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
-        for (auto& isOpaque : { true, false }) {
-            SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
-            auto surface(surface_func(ctxInfo.grContext(), alphaType, nullptr));
-            test_snapshot_alphatype(reporter, surface, isOpaque);
+        // GPU doesn't support creating unpremul surfaces, so only test opaque + premul
+        for (auto& at : { kOpaque_SkAlphaType, kPremul_SkAlphaType }) {
+            auto surface(surface_func(ctxInfo.grContext(), at, nullptr));
+            test_snapshot_alphatype(reporter, surface, at);
         }
     }
 }