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);
}
}
}