Index: tests/CodecTest.cpp |
diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp |
index 341433b379674b1db376765d80392bb650947dea..32482413f11d65da9723b90135d99b7599465685 100644 |
--- a/tests/CodecTest.cpp |
+++ b/tests/CodecTest.cpp |
@@ -22,6 +22,13 @@ |
#include "png.h" |
+#if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 5 |
+ // FIXME (scroggo): Google3 needs to be updated to use a newer version of libpng. In |
+ // the meantime, we had to break some pieces of SkPngCodec in order to support Google3. |
+ // The parts that are broken are likely not used by Google3. |
+ #define SK_PNG_DISABLE_TESTS |
+#endif |
+ |
static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { |
SkAutoLockPixels autoLockPixels(bm); |
SkASSERT(bm.getPixels()); |
@@ -79,6 +86,62 @@ SkIRect generate_random_subset(SkRandom* rand, int w, int h) { |
return rect; |
} |
+static void test_incremental_decode(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo& info, |
+ const SkMD5::Digest& goodDigest) { |
+ SkBitmap bm; |
+ bm.allocPixels(info); |
+ SkAutoLockPixels autoLockPixels(bm); |
+ |
+ REPORTER_ASSERT(r, SkCodec::kSuccess == codec->startIncrementalDecode(info, bm.getPixels(), |
+ bm.rowBytes())); |
+ |
+ REPORTER_ASSERT(r, SkCodec::kSuccess == codec->incrementalDecode()); |
+ |
+ compare_to_good_digest(r, goodDigest, bm); |
+} |
+ |
+// Test in stripes, similar to DM's kStripe_Mode |
+static void test_in_stripes(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo& info, |
+ const SkMD5::Digest& goodDigest) { |
+ SkBitmap bm; |
+ bm.allocPixels(info); |
+ bm.eraseColor(SK_ColorYELLOW); |
+ |
+ const int height = info.height(); |
+ // Note that if numStripes does not evenly divide height there will be an extra |
+ // stripe. |
+ const int numStripes = 4; |
+ |
+ if (numStripes > height) { |
+ // Image is too small. |
+ return; |
+ } |
+ |
+ const int stripeHeight = height / numStripes; |
+ |
+ // Iterate through the image twice. Once to decode odd stripes, and once for even. |
+ for (int oddEven = 1; oddEven >= 0; oddEven--) { |
+ for (int y = oddEven * stripeHeight; y < height; y += 2 * stripeHeight) { |
+ SkIRect subset = SkIRect::MakeLTRB(0, y, info.width(), |
+ SkTMin(y + stripeHeight, height)); |
+ SkCodec::Options options; |
+ options.fSubset = ⊂ |
+ if (SkCodec::kSuccess != codec->startIncrementalDecode(info, bm.getAddr(0, y), |
+ bm.rowBytes(), &options)) { |
+ ERRORF(r, "failed to start incremental decode!\ttop: %i\tbottom%i\n", |
+ subset.top(), subset.bottom()); |
+ return; |
+ } |
+ if (SkCodec::kSuccess != codec->incrementalDecode()) { |
+ ERRORF(r, "failed incremental decode starting from line %i\n", y); |
+ return; |
+ } |
+ } |
+ } |
+ |
+ compare_to_good_digest(r, goodDigest, bm); |
+} |
+ |
template<typename Codec> |
static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const SkImageInfo& info, |
const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* digest, |
@@ -187,12 +250,14 @@ static bool supports_partial_scanlines(const char path[]) { |
return false; |
} |
+// FIXME: Break up this giant function |
static void check(skiatest::Reporter* r, |
const char path[], |
SkISize size, |
bool supportsScanlineDecoding, |
bool supportsSubsetDecoding, |
- bool supportsIncomplete = true) { |
+ bool supportsIncomplete, |
+ bool supportsNewScanlineDecoding = false) { |
SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); |
if (!stream) { |
@@ -221,12 +286,15 @@ static void check(skiatest::Reporter* r, |
test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nullptr); |
// Scanline decoding follows. |
- // Need to call startScanlineDecode() first. |
- REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
- == 0); |
- REPORTER_ASSERT(r, codec->skipScanlines(1) |
- == 0); |
+ if (supportsNewScanlineDecoding && !isIncomplete) { |
+ test_incremental_decode(r, codec, info, codecDigest); |
+ test_in_stripes(r, codec, info, codecDigest); |
+ } |
+ |
+ // Need to call startScanlineDecode() first. |
+ REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) == 0); |
+ REPORTER_ASSERT(r, !codec->skipScanlines(1)); |
const SkCodec::Result startResult = codec->startScanlineDecode(info); |
if (supportsScanlineDecoding) { |
bm.eraseColor(SK_ColorYELLOW); |
@@ -321,7 +389,7 @@ static void check(skiatest::Reporter* r, |
} |
// SkAndroidCodec tests |
- if (supportsScanlineDecoding || supportsSubsetDecoding) { |
+ if (supportsScanlineDecoding || supportsSubsetDecoding || supportsNewScanlineDecoding) { |
SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); |
if (!stream) { |
@@ -359,6 +427,7 @@ static void check(skiatest::Reporter* r, |
REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes())); |
compare_to_good_digest(r, codecDigest, bm); |
+#ifndef SK_PNG_DISABLE_TESTS |
// Test using SkFrontBufferedStream, as Android does |
SkStream* bufferedStream = SkFrontBufferedStream::Create( |
new SkMemoryStream(std::move(fullData)), SkCodec::MinBufferedBytesNeeded()); |
@@ -368,26 +437,28 @@ static void check(skiatest::Reporter* r, |
if (codec) { |
test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest); |
} |
+#endif |
} |
// If we've just tested incomplete decodes, let's run the same test again on full decodes. |
if (isIncomplete) { |
- check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, false); |
+ check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, false, |
+ supportsNewScanlineDecoding); |
} |
} |
DEF_TEST(Codec, r) { |
// WBMP |
- check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false); |
+ check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false, true); |
// WEBP |
- check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true); |
- check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true); |
- check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true); |
+ check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true, true); |
+ check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true, true); |
+ check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true, true); |
// BMP |
- check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false); |
- check(r, "rle.bmp", SkISize::Make(320, 240), true, false); |
+ check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false, true); |
+ check(r, "rle.bmp", SkISize::Make(320, 240), true, false, true); |
// ICO |
// FIXME: We are not ready to test incomplete ICOs |
@@ -395,7 +466,7 @@ DEF_TEST(Codec, r) { |
// Decodes an embedded BMP image |
check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false); |
// Decodes an embedded PNG image |
- check(r, "google_chrome.ico", SkISize::Make(256, 256), true, false, false); |
+ check(r, "google_chrome.ico", SkISize::Make(256, 256), false, false, false, true); |
// GIF |
// FIXME: We are not ready to test incomplete GIFs |
@@ -405,30 +476,30 @@ DEF_TEST(Codec, r) { |
check(r, "randPixels.gif", SkISize::Make(8, 8), true, false, false); |
// JPG |
- check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false); |
- check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false); |
+ check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false, true); |
+ check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false, true); |
// grayscale.jpg is too small to test incomplete |
check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false); |
- check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false); |
+ check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false, true); |
// randPixels.jpg is too small to test incomplete |
check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false); |
// PNG |
- check(r, "arrow.png", SkISize::Make(187, 312), true, false, false); |
- check(r, "baby_tux.png", SkISize::Make(240, 246), true, false, false); |
- check(r, "color_wheel.png", SkISize::Make(128, 128), true, false, false); |
- check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), true, false, false); |
- check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false, false); |
- check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false, false); |
- check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false, false); |
- check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false, false); |
- check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false, false); |
- check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false, false); |
- check(r, "plane.png", SkISize::Make(250, 126), true, false, false); |
- // FIXME: We are not ready to test incomplete interlaced pngs |
- check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false, false); |
- check(r, "randPixels.png", SkISize::Make(8, 8), true, false, false); |
- check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false, false); |
+ check(r, "arrow.png", SkISize::Make(187, 312), false, false, true, true); |
+ check(r, "baby_tux.png", SkISize::Make(240, 246), false, false, true, true); |
+ check(r, "color_wheel.png", SkISize::Make(128, 128), false, false, true, true); |
+ // half-transparent-white-pixel.png is too small to test incomplete |
+ check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), false, false, false, true); |
+ check(r, "mandrill_128.png", SkISize::Make(128, 128), false, false, true, true); |
+ check(r, "mandrill_16.png", SkISize::Make(16, 16), false, false, true, true); |
+ check(r, "mandrill_256.png", SkISize::Make(256, 256), false, false, true, true); |
+ check(r, "mandrill_32.png", SkISize::Make(32, 32), false, false, true, true); |
+ check(r, "mandrill_512.png", SkISize::Make(512, 512), false, false, true, true); |
+ check(r, "mandrill_64.png", SkISize::Make(64, 64), false, false, true, true); |
+ check(r, "plane.png", SkISize::Make(250, 126), false, false, true, true); |
+ check(r, "plane_interlaced.png", SkISize::Make(250, 126), false, false, true, true); |
+ check(r, "randPixels.png", SkISize::Make(8, 8), false, false, true, true); |
+ check(r, "yellow_rose.png", SkISize::Make(400, 301), false, false, true, true); |
// RAW |
// Disable RAW tests for Win32. |
@@ -439,98 +510,6 @@ DEF_TEST(Codec, r) { |
#endif |
} |
-// Test interlaced PNG in stripes, similar to DM's kStripe_Mode |
-DEF_TEST(Codec_stripes, r) { |
- const char * path = "plane_interlaced.png"; |
- SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); |
- REPORTER_ASSERT(r, stream); |
- if (!stream) { |
- return; |
- } |
- |
- SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
- REPORTER_ASSERT(r, codec); |
- |
- if (!codec) { |
- return; |
- } |
- |
- switch (codec->getScanlineOrder()) { |
- case SkCodec::kBottomUp_SkScanlineOrder: |
- case SkCodec::kOutOfOrder_SkScanlineOrder: |
- ERRORF(r, "This scanline order will not match the original."); |
- return; |
- default: |
- break; |
- } |
- |
- // Baseline for what the image should look like, using N32. |
- const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
- |
- SkBitmap bm; |
- bm.allocPixels(info); |
- SkAutoLockPixels autoLockPixels(bm); |
- SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes()); |
- REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
- |
- SkMD5::Digest digest; |
- md5(bm, &digest); |
- |
- // Now decode in stripes |
- const int height = info.height(); |
- const int numStripes = 4; |
- int stripeHeight; |
- int remainingLines; |
- SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); |
- |
- bm.eraseColor(SK_ColorYELLOW); |
- |
- result = codec->startScanlineDecode(info); |
- REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
- |
- // Odd stripes |
- for (int i = 1; i < numStripes; i += 2) { |
- // Skip the even stripes |
- bool skipResult = codec->skipScanlines(stripeHeight); |
- REPORTER_ASSERT(r, skipResult); |
- |
- int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeight, |
- bm.rowBytes()); |
- REPORTER_ASSERT(r, linesDecoded == stripeHeight); |
- } |
- |
- // Even stripes |
- result = codec->startScanlineDecode(info); |
- REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
- |
- for (int i = 0; i < numStripes; i += 2) { |
- int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeight, |
- bm.rowBytes()); |
- REPORTER_ASSERT(r, linesDecoded == stripeHeight); |
- |
- // Skip the odd stripes |
- if (i + 1 < numStripes) { |
- bool skipResult = codec->skipScanlines(stripeHeight); |
- REPORTER_ASSERT(r, skipResult); |
- } |
- } |
- |
- // Remainder at the end |
- if (remainingLines > 0) { |
- result = codec->startScanlineDecode(info); |
- REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
- |
- bool skipResult = codec->skipScanlines(height - remainingLines); |
- REPORTER_ASSERT(r, skipResult); |
- |
- int linesDecoded = codec->getScanlines(bm.getAddr(0, height - remainingLines), |
- remainingLines, bm.rowBytes()); |
- REPORTER_ASSERT(r, linesDecoded == remainingLines); |
- } |
- |
- compare_to_good_digest(r, digest, bm); |
-} |
- |
static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_t len) { |
// Neither of these calls should return a codec. Bots should catch us if we leaked anything. |
SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, false)); |
@@ -670,26 +649,41 @@ static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { |
return; |
} |
SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); |
+ if (!decoder) { |
+ SkDebugf("Missing codec for %s\n", path); |
+ return; |
+ } |
+ |
+ const SkImageInfo info = decoder->getInfo().makeColorType(kIndex_8_SkColorType); |
// This should return kSuccess because kIndex8 is supported. |
SkPMColor colorStorage[256]; |
int colorCount; |
- SkCodec::Result result = decoder->startScanlineDecode( |
- decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorStorage, &colorCount); |
- REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
- // The rest of the test is uninteresting if kIndex8 is not supported |
- if (SkCodec::kSuccess != result) { |
+ SkCodec::Result result = decoder->startScanlineDecode(info, nullptr, colorStorage, |
+ &colorCount); |
+ if (SkCodec::kSuccess == result) { |
+ // This should return kInvalidParameters because, in kIndex_8 mode, we must pass in a valid |
+ // colorPtr and a valid colorCountPtr. |
+ result = decoder->startScanlineDecode(info, nullptr, nullptr, nullptr); |
+ REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
+ result = decoder->startScanlineDecode(info); |
+ REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
+ } else if (SkCodec::kUnimplemented == result) { |
+ // New method should be supported: |
+ SkBitmap bm; |
+ sk_sp<SkColorTable> colorTable(new SkColorTable(colorStorage, 256)); |
+ bm.allocPixels(info, nullptr, colorTable.get()); |
+ result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes(), nullptr, |
+ colorStorage, &colorCount); |
+ REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
+ result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes()); |
+ REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
+ } else { |
+ // The test is uninteresting if kIndex8 is not supported |
+ ERRORF(r, "Should not call test_invalid_parameters for non-Index8 file: %s\n", path); |
return; |
} |
- // This should return kInvalidParameters because, in kIndex_8 mode, we must pass in a valid |
- // colorPtr and a valid colorCountPtr. |
- result = decoder->startScanlineDecode( |
- decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, nullptr, nullptr); |
- REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
- result = decoder->startScanlineDecode( |
- decoder->getInfo().makeColorType(kIndex_8_SkColorType)); |
- REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
} |
DEF_TEST(Codec_Params, r) { |
@@ -697,6 +691,11 @@ DEF_TEST(Codec_Params, r) { |
test_invalid_parameters(r, "mandrill.wbmp"); |
} |
+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
+ |
+#ifndef SK_PNG_DISABLE_TESTS // reading chunks does not work properly with older versions. |
+ // It does not appear that anyone in Google3 is reading chunks. |
+ |
static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { |
SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); |
if (!sk_stream->write(data, len)) { |
@@ -704,7 +703,6 @@ static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t |
} |
} |
-#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
DEF_TEST(Codec_pngChunkReader, r) { |
// Create a dummy bitmap. Use unpremul RGBA for libpng. |
SkBitmap bm; |
@@ -850,6 +848,7 @@ DEF_TEST(Codec_pngChunkReader, r) { |
REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen()); |
} |
+#endif // SK_PNG_DISABLE_TESTS |
#endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
// Stream that can only peek up to a limit |
@@ -1167,7 +1166,8 @@ DEF_TEST(Codec_PngRoundTrip, r) { |
} |
static void test_conversion_possible(skiatest::Reporter* r, const char* path, |
- bool testScanlineDecoder) { |
+ bool supportsScanlineDecoder, |
+ bool supportsIncrementalDecoder) { |
SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); |
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); |
@@ -1176,22 +1176,129 @@ static void test_conversion_possible(skiatest::Reporter* r, const char* path, |
bm.allocPixels(infoF16); |
SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); |
REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
- if (testScanlineDecoder) { |
- result = codec->startScanlineDecode(infoF16); |
+ |
+ result = codec->startScanlineDecode(infoF16); |
+ if (supportsScanlineDecoder) { |
REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
+ } else { |
+ REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
+ } |
+ |
+ result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes()); |
+ if (supportsIncrementalDecoder) { |
+ REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
+ } else { |
+ REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
} |
infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); |
result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); |
REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
- if (testScanlineDecoder) { |
- result = codec->startScanlineDecode(infoF16); |
+ result = codec->startScanlineDecode(infoF16); |
+ if (supportsScanlineDecoder) { |
+ REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
+ } else { |
+ REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
+ } |
+ |
+ result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes()); |
+ if (supportsIncrementalDecoder) { |
REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
+ } else { |
+ REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
} |
} |
DEF_TEST(Codec_F16ConversionPossible, r) { |
- test_conversion_possible(r, "color_wheel.webp", false); |
- test_conversion_possible(r, "mandrill_512_q075.jpg", true); |
- test_conversion_possible(r, "yellow_rose.png", true); |
+ test_conversion_possible(r, "color_wheel.webp", false, false); |
+ test_conversion_possible(r, "mandrill_512_q075.jpg", true, false); |
+ test_conversion_possible(r, "yellow_rose.png", false, true); |
+} |
+ |
+// Only rewinds up to a limit. |
+class LimitedRewindingStream : public SkStream { |
+public: |
+ static SkStream* Make(const char path[], size_t limit) { |
+ SkStream* stream = GetResourceAsStream(path); |
+ if (!stream) { |
+ return nullptr; |
+ } |
+ return new LimitedRewindingStream(stream, limit); |
+ } |
+ |
+ size_t read(void* buffer, size_t size) override { |
+ const size_t bytes = fStream->read(buffer, size); |
+ fPosition += bytes; |
+ return bytes; |
+ } |
+ |
+ bool isAtEnd() const override { |
+ return fStream->isAtEnd(); |
+ } |
+ |
+ bool rewind() override { |
+ if (fPosition <= fLimit && fStream->rewind()) { |
+ fPosition = 0; |
+ return true; |
+ } |
+ |
+ return false; |
+ } |
+ |
+private: |
+ SkAutoTDelete<SkStream> fStream; |
+ const size_t fLimit; |
+ size_t fPosition; |
+ |
+ LimitedRewindingStream(SkStream* stream, size_t limit) |
+ : fStream(stream) |
+ , fLimit(limit) |
+ , fPosition(0) |
+ { |
+ SkASSERT(fStream); |
+ } |
+}; |
+ |
+DEF_TEST(Codec_fallBack, r) { |
+ // SkAndroidCodec needs to be able to fall back to scanline decoding |
+ // if incremental decoding does not work. Make sure this does not |
+ // require a rewind. |
+ |
+ // Formats that currently do not support incremental decoding |
+ auto files = { |
+ "box.gif", |
+ "CMYK.jpg", |
+ "color_wheel.ico", |
+ "mandrill.wbmp", |
+ "randPixels.bmp", |
+ }; |
+ for (auto file : files) { |
+ SkStream* stream = LimitedRewindingStream::Make(file, 14); |
+ if (!stream) { |
+ SkDebugf("Missing resources (%s). Set --resourcePath.\n", file); |
+ return; |
+ } |
+ |
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream)); |
+ if (!codec) { |
+ ERRORF(r, "Failed to create codec for %s,", file); |
+ continue; |
+ } |
+ |
+ SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
+ SkBitmap bm; |
+ bm.allocPixels(info); |
+ |
+ if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.getPixels(), |
+ bm.rowBytes())) { |
+ ERRORF(r, "Is scanline decoding now implemented for %s?", file); |
+ continue; |
+ } |
+ |
+ // Scanline decoding should not require a rewind. |
+ SkCodec::Result result = codec->startScanlineDecode(info); |
+ if (SkCodec::kSuccess != result) { |
+ ERRORF(r, "Scanline decoding failed for %s with %i", file, result); |
+ } |
+ } |
} |