diff options
author | Leon Scroggins III <scroggo@google.com> | 2017-08-15 12:24:02 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-08-17 16:09:31 +0000 |
commit | 0741818e7ab4e9ea8505b8a8687412f0e3804c65 (patch) | |
tree | ac183b3107e97b0717319fd403f6d552fdbd840f | |
parent | de44c2df9469e70f57f05d262cd1a245b2ff5e90 (diff) |
Move calls to conversion_possible to SkCodec
Move common code into the base class, so subclasses need not call
conversion_possible.
Use SkEncodedInfo rather than SkImageInfo, and use the proper frame.
API Changes:
- SkAndroidCodec:
- Add getEncodedInfo(), for SkBitmapRegionCodec
- SkEncodedInfo:
- Add opaque() helper
- SkBitmapRegionDecoder:
- Remove unused conversionSupported
(Split off from skia-review.googlesource.com/c/25746)
Bug: skia:5601
Change-Id: If4a40d4b98a3dd0afde2b6058f92315a393a5baf
Reviewed-on: https://skia-review.googlesource.com/34361
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
-rw-r--r-- | dm/DM.cpp | 174 | ||||
-rw-r--r-- | dm/DMSrcSink.cpp | 4 | ||||
-rw-r--r-- | include/android/SkBitmapRegionDecoder.h | 5 | ||||
-rw-r--r-- | include/codec/SkAndroidCodec.h | 3 | ||||
-rw-r--r-- | include/codec/SkCodec.h | 7 | ||||
-rw-r--r-- | include/codec/SkEncodedInfo.h | 2 | ||||
-rw-r--r-- | src/android/SkBitmapRegionCodec.cpp | 5 | ||||
-rw-r--r-- | src/android/SkBitmapRegionCodec.h | 2 | ||||
-rw-r--r-- | src/codec/SkAndroidCodec.cpp | 6 | ||||
-rw-r--r-- | src/codec/SkBmpCodec.cpp | 4 | ||||
-rw-r--r-- | src/codec/SkCodec.cpp | 66 | ||||
-rw-r--r-- | src/codec/SkCodecPriv.h | 61 | ||||
-rw-r--r-- | src/codec/SkGifCodec.cpp | 4 | ||||
-rw-r--r-- | src/codec/SkIcoCodec.h | 6 | ||||
-rw-r--r-- | src/codec/SkJpegCodec.h | 6 | ||||
-rw-r--r-- | src/codec/SkPngCodec.cpp | 8 | ||||
-rw-r--r-- | src/codec/SkRawCodec.cpp | 4 | ||||
-rw-r--r-- | src/codec/SkWbmpCodec.cpp | 15 | ||||
-rw-r--r-- | src/codec/SkWbmpCodec.h | 2 | ||||
-rw-r--r-- | src/codec/SkWebpCodec.cpp | 17 | ||||
-rw-r--r-- | tests/CodecTest.cpp | 6 |
21 files changed, 195 insertions, 212 deletions
@@ -529,6 +529,65 @@ static void push_image_gen_src(Path path, ImageGenSrc::Mode mode, SkAlphaType al push_src("image", folder, src); } +static void push_brd_src(Path path, CodecSrc::DstColorType dstColorType, BRDSrc::Mode mode, + uint32_t sampleSize) { + SkString folder("brd_android_codec"); + switch (mode) { + case BRDSrc::kFullImage_Mode: + break; + case BRDSrc::kDivisor_Mode: + folder.append("_divisor"); + break; + default: + SkASSERT(false); + return; + } + + switch (dstColorType) { + case CodecSrc::kGetFromCanvas_DstColorType: + break; + case CodecSrc::kGrayscale_Always_DstColorType: + folder.append("_kGray"); + break; + default: + SkASSERT(false); + return; + } + + if (1 != sampleSize) { + folder.appendf("_%.3f", 1.0f / (float) sampleSize); + } + + BRDSrc* src = new BRDSrc(path, mode, dstColorType, sampleSize); + push_src("image", folder, src); +} + +static void push_brd_srcs(Path path, bool gray) { + if (gray) { + // Only run grayscale to one sampleSize and Mode. Though interesting + // to test grayscale, it should not reveal anything across various + // sampleSizes and Modes + // Arbitrarily choose Mode and sampleSize. + push_brd_src(path, CodecSrc::kGrayscale_Always_DstColorType, + BRDSrc::kFullImage_Mode, 2); + } + + // Test on a variety of sampleSizes, making sure to include: + // - 2, 4, and 8, which are natively supported by jpeg + // - multiples of 2 which are not divisible by 4 (analogous for 4) + // - larger powers of two, since BRD clients generally use powers of 2 + // We will only produce output for the larger sizes on large images. + const uint32_t sampleSizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32, 64 }; + + const BRDSrc::Mode modes[] = { BRDSrc::kFullImage_Mode, BRDSrc::kDivisor_Mode, }; + + for (uint32_t sampleSize : sampleSizes) { + for (BRDSrc::Mode mode : modes) { + push_brd_src(path, CodecSrc::kGetFromCanvas_DstColorType, mode, sampleSize); + } + } +} + static void push_codec_srcs(Path path) { sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str())); if (!encoded) { @@ -641,16 +700,31 @@ static void push_codec_srcs(Path path) { } } - static const char* const rawExts[] = { - "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", - "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", - }; + const char* ext = strrchr(path.c_str(), '.'); + if (ext) { + ext++; - // There is not currently a reason to test RAW images on image generator. - // If we want to enable these tests, we will need to fix skbug.com/5079. - for (const char* ext : rawExts) { - if (path.endsWith(ext)) { - return; + static const char* const rawExts[] = { + "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", + "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", + }; + for (const char* rawExt : rawExts) { + if (0 == strcmp(rawExt, ext)) { + // RAW is not supported by image generator (skbug.com/5079) or BRD. + return; + } + } + + static const char* const brdExts[] = { + "jpg", "jpeg", "png", "webp", + "JPG", "JPEG", "PNG", "WEBP", + }; + for (const char* brdExt : brdExts) { + if (0 == strcmp(brdExt, ext)) { + bool gray = codec->getEncodedInfo().color() == SkEncodedInfo::kGray_Color; + push_brd_srcs(path, gray); + break; + } } } @@ -678,80 +752,6 @@ static void push_codec_srcs(Path path) { } } -static void push_brd_src(Path path, CodecSrc::DstColorType dstColorType, BRDSrc::Mode mode, - uint32_t sampleSize) { - SkString folder("brd_android_codec"); - switch (mode) { - case BRDSrc::kFullImage_Mode: - break; - case BRDSrc::kDivisor_Mode: - folder.append("_divisor"); - break; - default: - SkASSERT(false); - return; - } - - switch (dstColorType) { - case CodecSrc::kGetFromCanvas_DstColorType: - break; - case CodecSrc::kGrayscale_Always_DstColorType: - folder.append("_kGray"); - break; - default: - SkASSERT(false); - return; - } - - if (1 != sampleSize) { - folder.appendf("_%.3f", 1.0f / (float) sampleSize); - } - - BRDSrc* src = new BRDSrc(path, mode, dstColorType, sampleSize); - push_src("image", folder, src); -} - -static void push_brd_srcs(Path path) { - // Only run grayscale to one sampleSize and Mode. Though interesting - // to test grayscale, it should not reveal anything across various - // sampleSizes and Modes - // Arbitrarily choose Mode and sampleSize. - push_brd_src(path, CodecSrc::kGrayscale_Always_DstColorType, BRDSrc::kFullImage_Mode, 2); - - - // Test on a variety of sampleSizes, making sure to include: - // - 2, 4, and 8, which are natively supported by jpeg - // - multiples of 2 which are not divisible by 4 (analogous for 4) - // - larger powers of two, since BRD clients generally use powers of 2 - // We will only produce output for the larger sizes on large images. - const uint32_t sampleSizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32, 64 }; - - const BRDSrc::Mode modes[] = { - BRDSrc::kFullImage_Mode, - BRDSrc::kDivisor_Mode, - }; - - for (uint32_t sampleSize : sampleSizes) { - for (BRDSrc::Mode mode : modes) { - push_brd_src(path, CodecSrc::kGetFromCanvas_DstColorType, mode, sampleSize); - } - } -} - -static bool brd_supported(const char* ext) { - static const char* const exts[] = { - "jpg", "jpeg", "png", "webp", - "JPG", "JPEG", "PNG", "WEBP", - }; - - for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { - if (0 == strcmp(exts[i], ext)) { - return true; - } - } - return false; -} - template <typename T> void gather_file_srcs(const SkCommandLineFlags::StringArray& flags, const char* ext) { for (int i = 0; i < flags.count(); i++) { @@ -785,14 +785,6 @@ static bool gather_srcs() { for (auto image : images) { push_codec_srcs(image); - if (FLAGS_simpleCodec) { - continue; - } - - const char* ext = strrchr(image.c_str(), '.'); - if (ext && brd_supported(ext+1)) { - push_brd_srcs(image); - } } SkTArray<SkString> colorImages; diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index e255dd3cdd..a862969e4a 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -152,10 +152,6 @@ Error BRDSrc::draw(SkCanvas* canvas) const { return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str())); } - if (!brd->conversionSupported(colorType)) { - return Error::Nonfatal("Cannot convert to color type."); - } - const uint32_t width = brd->width(); const uint32_t height = brd->height(); // Visually inspecting very small output images is not necessary. diff --git a/include/android/SkBitmapRegionDecoder.h b/include/android/SkBitmapRegionDecoder.h index df0c370338..c41d11247b 100644 --- a/include/android/SkBitmapRegionDecoder.h +++ b/include/android/SkBitmapRegionDecoder.h @@ -63,11 +63,6 @@ public: const SkIRect& desiredSubset, int sampleSize, SkColorType colorType, bool requireUnpremul, sk_sp<SkColorSpace> prefColorSpace = nullptr) = 0; - /* - * @param Requested destination color type - * @return true if we support the requested color type and false otherwise - */ - virtual bool conversionSupported(SkColorType colorType) = 0; virtual SkEncodedImageFormat getEncodedFormat() = 0; diff --git a/include/codec/SkAndroidCodec.h b/include/codec/SkAndroidCodec.h index 3571108edd..cc93bf18c4 100644 --- a/include/codec/SkAndroidCodec.h +++ b/include/codec/SkAndroidCodec.h @@ -41,8 +41,9 @@ public: */ static std::unique_ptr<SkAndroidCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr); - virtual ~SkAndroidCodec() {} + virtual ~SkAndroidCodec(); + const SkEncodedInfo& getEncodedInfo() const; const SkImageInfo& getInfo() const { return fInfo; } diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index fb4f165dbf..8ec44c8539 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -846,6 +846,13 @@ private: bool fStartedIncrementalDecode; /** + * Return whether {srcColor, srcIsOpaque, srcCS} can convert to dst. + * + * Will be called for the appropriate frame, prior to initializing the colorXform. + */ + virtual bool conversionSupported(const SkImageInfo& dst, SkEncodedInfo::Color srcColor, + bool srcIsOpaque, const SkColorSpace* srcCS) const; + /** * Return whether these dimensions are supported as a scale. * * The codec may choose to cache the information about scale and subset. diff --git a/include/codec/SkEncodedInfo.h b/include/codec/SkEncodedInfo.h index 3b1ce48713..dce88cadc1 100644 --- a/include/codec/SkEncodedInfo.h +++ b/include/codec/SkEncodedInfo.h @@ -156,6 +156,8 @@ public: Color color() const { return fColor; } Alpha alpha() const { return fAlpha; } + bool opaque() const { return fAlpha == kOpaque_Alpha; } + uint8_t bitsPerComponent() const { return fBitsPerComponent; } uint8_t bitsPerPixel() const { diff --git a/src/android/SkBitmapRegionCodec.cpp b/src/android/SkBitmapRegionCodec.cpp index e2ab423d27..f77c70264f 100644 --- a/src/android/SkBitmapRegionCodec.cpp +++ b/src/android/SkBitmapRegionCodec.cpp @@ -116,8 +116,3 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat return true; } - -bool SkBitmapRegionCodec::conversionSupported(SkColorType colorType) { - SkImageInfo dstInfo = fCodec->getInfo().makeColorType(colorType); - return conversion_possible(dstInfo, fCodec->getInfo()); -} diff --git a/src/android/SkBitmapRegionCodec.h b/src/android/SkBitmapRegionCodec.h index a7cfe33a91..94194c089f 100644 --- a/src/android/SkBitmapRegionCodec.h +++ b/src/android/SkBitmapRegionCodec.h @@ -28,8 +28,6 @@ public: SkColorType colorType, bool requireUnpremul, sk_sp<SkColorSpace> prefColorSpace) override; - bool conversionSupported(SkColorType colorType) override; - SkEncodedImageFormat getEncodedFormat() override { return fCodec->getEncodedFormat(); } SkColorType computeOutputColorType(SkColorType requestedColorType) override { diff --git a/src/codec/SkAndroidCodec.cpp b/src/codec/SkAndroidCodec.cpp index 3a57352113..d004eb8326 100644 --- a/src/codec/SkAndroidCodec.cpp +++ b/src/codec/SkAndroidCodec.cpp @@ -66,6 +66,12 @@ SkAndroidCodec::SkAndroidCodec(SkCodec* codec) , fCodec(codec) {} +SkAndroidCodec::~SkAndroidCodec() {} + +const SkEncodedInfo& SkAndroidCodec::getEncodedInfo() const { + return fCodec->getEncodedInfo(); +} + std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromStream(std::unique_ptr<SkStream> stream, SkPngChunkReader* chunkReader) { auto codec = SkCodec::MakeFromStream(std::move(stream), nullptr, chunkReader); if (nullptr == codec) { diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index 18f8768e0d..d8167efa08 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -620,9 +620,7 @@ int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const { SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options) { - if (!conversion_possible(dstInfo, this->getInfo()) || - !this->initializeColorXform(dstInfo, options.fPremulBehavior)) - { + if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { return kInvalidConversion; } diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 2b6108250c..84af2271f7 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -155,6 +155,29 @@ SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkCodec::~SkCodec() {} +bool SkCodec::conversionSupported(const SkImageInfo& dst, SkEncodedInfo::Color srcColor, + bool srcIsOpaque, const SkColorSpace* srcCS) const { + if (!valid_alpha(dst.alphaType(), srcIsOpaque)) { + return false; + } + + switch (dst.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + return true; + case kRGBA_F16_SkColorType: + return dst.colorSpace() && dst.colorSpace()->gammaIsLinear(); + case kRGB_565_SkColorType: + return srcIsOpaque; + case kGray_8_SkColorType: + return SkEncodedInfo::kGray_Color == srcColor && srcIsOpaque && + !needs_color_xform(dst, srcCS, false); + default: + return false; + } + +} + bool SkCodec::rewindIfNeeded() { // Store the value of fNeedsRewind so we can update it. Next read will // require a rewind. @@ -194,6 +217,10 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, const Options& options) { const int index = options.fFrameIndex; if (0 == index) { + if (!this->conversionSupported(info, fEncodedInfo.color(), fEncodedInfo.opaque(), + fSrcInfo.colorSpace())) { + return kInvalidConversion; + } return kSuccess; } @@ -213,6 +240,11 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, const auto* frame = frameHolder->getFrame(index); SkASSERT(frame); + if (!this->conversionSupported(info, fEncodedInfo.color(), !frame->hasAlpha(), + fSrcInfo.colorSpace())) { + return kInvalidConversion; + } + const int requiredFrame = frame->getRequiredFrame(); if (requiredFrame == kNone) { return kSuccess; @@ -278,10 +310,6 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t if (nullptr == options) { options = &optsStorage; } else { - const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, *options); - if (frameIndexResult != kSuccess) { - return frameIndexResult; - } if (options->fSubset) { SkIRect subset(*options->fSubset); if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) { @@ -292,6 +320,12 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t } } + const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, + *options); + if (frameIndexResult != kSuccess) { + return frameIndexResult; + } + // FIXME: Support subsets somehow? Note that this works for SkWebpCodec // because it supports arbitrary scaling/subset combinations. if (!this->dimensionsSupported(info.dimensions())) { @@ -350,10 +384,6 @@ SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* p if (nullptr == options) { options = &optsStorage; } else { - const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, *options); - if (frameIndexResult != kSuccess) { - return frameIndexResult; - } if (options->fSubset) { SkIRect size = SkIRect::MakeSize(info.dimensions()); if (!size.contains(*options->fSubset)) { @@ -368,6 +398,12 @@ SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* p } } + const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, + *options); + if (frameIndexResult != kSuccess) { + return frameIndexResult; + } + if (!this->dimensionsSupported(info.dimensions())) { return kInvalidScale; } @@ -418,6 +454,18 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, } } + // Scanline decoding only supports decoding the first frame. + if (options->fFrameIndex != 0) { + return kUnimplemented; + } + + // The void* dst and rowbytes in handleFrameIndex or only used for decoding prior + // frames, which is not supported here anyway, so it is safe to pass nullptr/0. + const Result frameIndexResult = this->handleFrameIndex(info, nullptr, 0, *options); + if (frameIndexResult != kSuccess) { + return frameIndexResult; + } + // FIXME: Support subsets somehow? if (!this->dimensionsSupported(info.dimensions())) { return kInvalidScale; @@ -567,7 +615,7 @@ bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, fXformOnDecode = false; bool needsColorCorrectPremul = needs_premul(dstInfo, fEncodedInfo) && SkTransferFunctionBehavior::kRespect == premulBehavior; - if (needs_color_xform(dstInfo, fSrcInfo, needsColorCorrectPremul)) { + if (needs_color_xform(dstInfo, fSrcInfo.colorSpace(), needsColorCorrectPremul)) { fColorXform = SkColorSpaceXform_Base::New(fSrcInfo.colorSpace(), dstInfo.colorSpace(), premulBehavior); if (!fColorXform) { diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h index cb7cd94979..a737fb7511 100644 --- a/src/codec/SkCodecPriv.h +++ b/src/codec/SkCodecPriv.h @@ -82,31 +82,20 @@ static inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaled return ((srcCoord - startCoord) % sampleFactor) == 0; } -static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) { +static inline bool valid_alpha(SkAlphaType dstAlpha, bool srcIsOpaque) { if (kUnknown_SkAlphaType == dstAlpha) { return false; } - if (srcAlpha != dstAlpha) { - if (kOpaque_SkAlphaType == srcAlpha) { - // If the source is opaque, we can support any. + if (srcIsOpaque) { + if (kOpaque_SkAlphaType != dstAlpha) { SkCodecPrintf("Warning: an opaque image should be decoded as opaque " "- it is being decoded as non-opaque, which will draw slower\n"); - return true; - } - - // The source is not opaque - switch (dstAlpha) { - case kPremul_SkAlphaType: - case kUnpremul_SkAlphaType: - // The source is not opaque, so either of these is okay - break; - default: - // We cannot decode a non-opaque image to opaque (or unknown) - return false; } + return true; } - return true; + + return dstAlpha != kOpaque_SkAlphaType; } /* @@ -287,7 +276,7 @@ static inline bool needs_premul(const SkImageInfo& dstInfo, const SkEncodedInfo& SkEncodedInfo::kUnpremul_Alpha == encodedInfo.alpha(); } -static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, +static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkColorSpace* srcCS, bool needsColorCorrectPremul) { // We never perform a color xform in legacy mode. if (!dstInfo.colorSpace()) { @@ -298,7 +287,7 @@ static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageIn bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType(); // Need a color xform when dst space does not match the src. - bool srcDstNotEqual = !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace()); + bool srcDstNotEqual = !SkColorSpace::Equals(srcCS, dstInfo.colorSpace()); return needsColorCorrectPremul || isF16 || srcDstNotEqual; } @@ -307,38 +296,4 @@ static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaTy return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType; } -/* - * Alpha Type Conversions - * - kOpaque to kOpaque, kUnpremul, kPremul is valid - * - kUnpremul to kUnpremul, kPremul is valid - * - * Color Type Conversions - * - Always support kRGBA_8888, kBGRA_8888 - * - Support kRGBA_F16 when there is a linear dst color space - * - Support k565 if kOpaque and color correction is not required - * - Support k565 if it matches the src, kOpaque, and color correction is not required - */ -static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { - // Ensure the alpha type is valid. - if (!valid_alpha(dst.alphaType(), src.alphaType())) { - return false; - } - - // Check for supported color types. - switch (dst.colorType()) { - case kRGBA_8888_SkColorType: - case kBGRA_8888_SkColorType: - return true; - case kRGBA_F16_SkColorType: - return dst.colorSpace() && dst.colorSpace()->gammaIsLinear(); - case kRGB_565_SkColorType: - return kOpaque_SkAlphaType == src.alphaType(); - case kGray_8_SkColorType: - return kGray_8_SkColorType == src.colorType() && - kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src, false); - default: - return false; - } -} - #endif // SkCodecPriv_DEFINED diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp index d54cbd558e..4bd0e17bd0 100644 --- a/src/codec/SkGifCodec.cpp +++ b/src/codec/SkGifCodec.cpp @@ -228,9 +228,7 @@ SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, const Op const auto at = frame->hasAlpha() ? kUnpremul_SkAlphaType : kOpaque_SkAlphaType; const auto srcInfo = this->getInfo().makeAlphaType(at); - if (!conversion_possible(dstInfo, srcInfo) || - !this->initializeColorXform(dstInfo, opts.fPremulBehavior)) - { + if (!this->initializeColorXform(dstInfo, opts.fPremulBehavior)) { return gif_error("Cannot convert input type to output type.\n", kInvalidConversion); } diff --git a/src/codec/SkIcoCodec.h b/src/codec/SkIcoCodec.h index aa19c9b935..62de20f9ff 100644 --- a/src/codec/SkIcoCodec.h +++ b/src/codec/SkIcoCodec.h @@ -48,6 +48,12 @@ protected: SkScanlineOrder onGetScanlineOrder() const override; + bool conversionSupported(const SkImageInfo&, SkEncodedInfo::Color, bool, + const SkColorSpace*) const override { + // This will be checked by the embedded codec. + return true; + } + private: Result onStartScanlineDecode(const SkImageInfo& dstInfo, diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h index 1409182a97..fd8ee63d6c 100644 --- a/src/codec/SkJpegCodec.h +++ b/src/codec/SkJpegCodec.h @@ -58,6 +58,12 @@ protected: bool onDimensionsSupported(const SkISize&) override; + bool conversionSupported(const SkImageInfo&, SkEncodedInfo::Color, bool, + const SkColorSpace*) const override { + // This class checks for conversion after creating colorXform. + return true; + } + private: /* diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index 13e45ab609..c5dae3ed4a 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -1086,10 +1086,6 @@ bool SkPngCodec::onRewind() { SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, const Options& options, int* rowsDecoded) { - if (!conversion_possible(dstInfo, this->getInfo())) { - return kInvalidConversion; - } - Result result = this->initializeXforms(dstInfo, options); if (kSuccess != result) { return result; @@ -1106,10 +1102,6 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, const SkCodec::Options& options) { - if (!conversion_possible(dstInfo, this->getInfo())) { - return kInvalidConversion; - } - Result result = this->initializeXforms(dstInfo, options); if (kSuccess != result) { return result; diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp index cf41d17e9b..93c6db56fb 100644 --- a/src/codec/SkRawCodec.cpp +++ b/src/codec/SkRawCodec.cpp @@ -696,9 +696,7 @@ std::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> st SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, int* rowsDecoded) { - if (!conversion_possible(dstInfo, this->getInfo()) || - !this->initializeColorXform(dstInfo, options.fPremulBehavior)) - { + if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp index 934d7d5b9a..bc796c4fcc 100644 --- a/src/codec/SkWbmpCodec.cpp +++ b/src/codec/SkWbmpCodec.cpp @@ -108,6 +108,11 @@ SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const { return SkEncodedImageFormat::kWBMP; } +bool SkWbmpCodec::conversionSupported(const SkImageInfo& dst, SkEncodedInfo::Color srcColor, + bool srcIsOpaque, const SkColorSpace* srcCS) const { + return valid_color_type(dst) && valid_alpha(dst.alphaType(), srcIsOpaque); +} + SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, void* dst, size_t rowBytes, @@ -118,10 +123,6 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, return kUnimplemented; } - if (!valid_color_type(info) || !valid_alpha(info.alphaType(), this->getInfo().alphaType())) { - return kInvalidConversion; - } - // Initialize the swizzler std::unique_ptr<SkSwizzler> swizzler(this->initializeSwizzler(info, options)); SkASSERT(swizzler); @@ -186,12 +187,6 @@ SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kUnimplemented; } - if (!valid_color_type(dstInfo) || - !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) - { - return kInvalidConversion; - } - // Initialize the swizzler fSwizzler.reset(this->initializeSwizzler(dstInfo, options)); SkASSERT(fSwizzler); diff --git a/src/codec/SkWbmpCodec.h b/src/codec/SkWbmpCodec.h index 03287710e0..f26967faa5 100644 --- a/src/codec/SkWbmpCodec.h +++ b/src/codec/SkWbmpCodec.h @@ -28,6 +28,8 @@ protected: Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*) override; bool onRewind() override; + bool conversionSupported(const SkImageInfo& dst, SkEncodedInfo::Color srcColor, + bool srcIsOpaque, const SkColorSpace* srcCS) const override; private: /* * Returns a swizzler on success, nullptr on failure diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp index 94fa175f82..38feb827e4 100644 --- a/src/codec/SkWebpCodec.cpp +++ b/src/codec/SkWebpCodec.cpp @@ -398,23 +398,14 @@ static void blend_line(SkColorType dstCT, void* dst, SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, const Options& options, int* rowsDecodedPtr) { + if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { + return kInvalidConversion; + } + const int index = options.fFrameIndex; SkASSERT(0 == index || index < fFrameHolder.size()); const auto& srcInfo = this->getInfo(); - { - auto info = srcInfo; - if (index > 0) { - auto alphaType = alpha_type(fFrameHolder.frame(index)->hasAlpha()); - info = info.makeAlphaType(alphaType); - } - if (!conversion_possible(dstInfo, info) || - !this->initializeColorXform(dstInfo, options.fPremulBehavior)) - { - return kInvalidConversion; - } - } - SkASSERT(0 == index || (!options.fSubset && dstInfo.dimensions() == srcInfo.dimensions())); WebPDecoderConfig config; diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp index 4e68cd1ac6..6ffc44874c 100644 --- a/tests/CodecTest.cpp +++ b/tests/CodecTest.cpp @@ -1138,14 +1138,16 @@ static void test_conversion_possible(skiatest::Reporter* r, const char* path, if (supportsScanlineDecoder) { REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); } else { - REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); + REPORTER_ASSERT(r, SkCodec::kUnimplemented == result + || SkCodec::kInvalidConversion == result); } result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes()); if (supportsIncrementalDecoder) { REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); } else { - REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); + REPORTER_ASSERT(r, SkCodec::kUnimplemented == result + || SkCodec::kInvalidConversion == result); } SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(infoF16.colorSpace())->type()); |