diff --git a/gm/image.cpp b/gm/image.cpp index a67ed202db..400d421a40 100644 --- a/gm/image.cpp +++ b/gm/image.cpp @@ -303,8 +303,7 @@ DEF_GM( return new ScalePixelsGM; ) #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 fd20e5e0e5..bdcb5b0abe 100644 --- a/include/core/SkImage.h +++ b/include/core/SkImage.h @@ -166,7 +166,8 @@ public: 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 b8c89645b2..fa3580c175 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -106,6 +106,10 @@ void SkImage::preroll(GrContext* ctx) const { /////////////////////////////////////////////////////////////////////////////////////////////////// +SkAlphaType SkImage::alphaType() const { + return as_IB(this)->onAlphaType(); +} + sk_sp SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY, const SkMatrix* localMatrix) const { return SkImageShader::Make(sk_ref_sp(const_cast(this)), tileX, tileY, localMatrix); @@ -320,7 +324,7 @@ bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) con // 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 a1da0fa559..7ebedeb6f0 100644 --- a/src/image/SkImage_Base.h +++ b/src/image/SkImage_Base.h @@ -34,6 +34,7 @@ public: // 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 20f4863d82..412f573ba6 100644 --- a/src/image/SkImage_Generator.cpp +++ b/src/image/SkImage_Generator.cpp @@ -24,11 +24,13 @@ public: 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 onMakeSubset(const SkIRect&) const override; bool getROPixels(SkBitmap*, CachingHint) const override; GrTexture* asTextureRef(GrContext*, const GrTextureParams&, @@ -84,7 +86,7 @@ sk_sp SkImage_Generator::onMakeSubset(const SkIRect& subset) const { // 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 76f19bc31e..eba66f46ed 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -51,9 +51,8 @@ SkImageInfo SkImage_Gpu::onImageInfo() const { return SkImageInfo::Make(fTexture->width(), fTexture->height(), ct, fAlphaType, fColorSpace); } -static SkImageInfo make_info(int w, int h, bool isOpaque, sk_sp 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 colorSpace) { + return SkImageInfo::MakeN32(w, h, at, std::move(colorSpace)); } bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const { @@ -64,7 +63,7 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const { 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 @@ GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& para 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 @@ sk_sp SkImage::makeTextureImage(GrContext *context) const { if (GrTexture* peek = as_IB(this)->peekTexture()) { return peek->getContext() == context ? sk_ref_sp(const_cast(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 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox 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 44949a13ac..a9d9c33f2d 100644 --- a/src/image/SkImage_Gpu.h +++ b/src/image/SkImage_Gpu.h @@ -28,6 +28,7 @@ public: ~SkImage_Gpu() override; SkImageInfo onImageInfo() const override; + SkAlphaType onAlphaType() const override { return fAlphaType; } void applyBudgetDecision() const { if (SkBudgeted::kYes == fBudgeted) { @@ -47,7 +48,6 @@ public: *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 acfacea574..d334dfb326 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -79,6 +79,9 @@ public: 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 @@ public: 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 @@ const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) { 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 887bca4ab0..772745ca50 100644 --- a/src/pdf/SkPDFBitmap.cpp +++ b/src/pdf/SkPDFBitmap.cpp @@ -32,8 +32,7 @@ void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { } } // 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 ca4788c449..fa22641d9e 100644 --- a/tests/ImageTest.cpp +++ b/tests/ImageTest.cpp @@ -43,8 +43,7 @@ static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect // 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 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_newTextureImage, reporter, contextInf 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 @@ static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* ima 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 @@ static void check_images_same(skiatest::Reporter* reporter, const SkImage* a, co 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 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredTextureImage, reporter, ctxInfo) { 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 87c3a52fc9..2703b541fc 100644 --- a/tests/SurfaceTest.cpp +++ b/tests/SurfaceTest.cpp @@ -128,32 +128,31 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCanvasPeek_Gpu, reporter, ctxInfo) { #endif static void test_snapshot_alphatype(skiatest::Reporter* reporter, const sk_sp& surface, - bool expectOpaque) { + SkAlphaType expectedAlphaType) { REPORTER_ASSERT(reporter, surface); if (surface) { sk_sp 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); } } }