diff options
author | scroggo <scroggo@google.com> | 2015-12-08 18:54:13 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-08 18:54:13 -0800 |
commit | db30be2f9470d21fe37b63d145c1fcca9a6ad98c (patch) | |
tree | 885e9e207682233ab03acaba6461c34779c288ee /tests/CodexTest.cpp | |
parent | 0671b967eb02d44c8951dc4dc39df09fac15b097 (diff) |
Make SkCodec support peek() and read()
- Update SkCodec's dox to point out that some of the data must be
read twice in order to decode
- Add an accessor that reports how much is needed for reading twice
- Make SkCodec default to use peek()
If an input stream supports peek()ing, peek() instead of reading.
This way the stream need not implement rewind()
- Make SkCodec use read() + rewind() as a backup
So that streams without peek() implemented can still function
properly (assuming they can rewind).
- read everything we may need to determine the format once
In SkCodec::NewFromStream, peek()/read() 14 bytes, which is enough
to read all of the types we support. Pass the buffer to each subtype,
which will have enough info to determine whether it is the right
type. This simplifies the code and results in less reading and
rewinding.
- NOTE: SkWbmpCodec needs the following number of bytes for the header
+ 1 (type)
+ 1 (reserved)
+ 3 (width - bytes needed to support up to 0xFFFF)
+ 3 (height - bytes needed to support up to 0xFFFF)
= 8
- in SkWebpCodec, support using read + rewind as a backup if peek does
not work.
A change in Android will add peek() to JavaInputStreamAdapter.
BUG=skia:3257
Review URL: https://codereview.chromium.org/1472123002
Diffstat (limited to 'tests/CodexTest.cpp')
-rw-r--r-- | tests/CodexTest.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/tests/CodexTest.cpp b/tests/CodexTest.cpp index 03dd16f583..94eea65b93 100644 --- a/tests/CodexTest.cpp +++ b/tests/CodexTest.cpp @@ -848,6 +848,54 @@ DEF_TEST(Codec_pngChunkReader, r) { } #endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +// Stream that can only peek up to a limit +class LimitedPeekingMemStream : public SkStream { +public: + LimitedPeekingMemStream(SkData* data, size_t limit) + : fStream(data) + , fLimit(limit) {} + + size_t peek(void* buf, size_t bytes) const override { + return fStream.peek(buf, SkTMin(bytes, fLimit)); + } + size_t read(void* buf, size_t bytes) override { + return fStream.read(buf, bytes); + } + bool rewind() override { + return fStream.rewind(); + } + bool isAtEnd() const override { + return false; + } +private: + SkMemoryStream fStream; + const size_t fLimit; +}; + +// Test that even if webp_parse_header fails to peek enough, it will fall back to read() +// + rewind() and succeed. +DEF_TEST(Codec_webp_peek, r) { + const char* path = "baby_tux.webp"; + SkString fullPath(GetResourcePath(path)); + SkAutoTUnref<SkData> data(SkData::NewFromFileName(fullPath.c_str())); + if (!data) { + SkDebugf("Missing resource '%s'\n", path); + return; + } + + // The limit is less than webp needs to peek or read. + SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(new LimitedPeekingMemStream(data, 25))); + REPORTER_ASSERT(r, codec); + + test_info(r, codec, codec->getInfo(), SkCodec::kSuccess, nullptr); + + // Similarly, a stream which does not peek should still succeed. + codec.reset(SkCodec::NewFromStream(new LimitedPeekingMemStream(data, 0))); + REPORTER_ASSERT(r, codec); + + test_info(r, codec, codec->getInfo(), SkCodec::kSuccess, nullptr); +} + // SkCodec's wbmp decoder was initially more restrictive than SkImageDecoder. // It required the second byte to be zero. But SkImageDecoder allowed a couple // of bits to be 1 (so long as they do not overlap with 0x9F). Test that @@ -877,3 +925,32 @@ DEF_TEST(Codec_wbmp, r) { } test_info(r, codec, codec->getInfo(), SkCodec::kSuccess, nullptr); } + +// wbmp images have a header that can be arbitrarily large, depending on the +// size of the image. We cap the size at 65535, meaning we only need to look at +// 8 bytes to determine whether we can read the image. This is important +// because SkCodec only passes 14 bytes to SkWbmpCodec to determine whether the +// image is a wbmp. +DEF_TEST(Codec_wbmp_max_size, r) { + const unsigned char maxSizeWbmp[] = { 0x00, 0x00, // Header + 0x83, 0xFF, 0x7F, // W: 65535 + 0x83, 0xFF, 0x7F }; // H: 65535 + SkAutoTDelete<SkStream> stream(new SkMemoryStream(maxSizeWbmp, sizeof(maxSizeWbmp), false)); + SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach())); + + REPORTER_ASSERT(r, codec); + if (!codec) return; + + REPORTER_ASSERT(r, codec->getInfo().width() == 65535); + REPORTER_ASSERT(r, codec->getInfo().height() == 65535); + + // Now test an image which is too big. Any image with a larger header (i.e. + // has bigger width/height) is also too big. + const unsigned char tooBigWbmp[] = { 0x00, 0x00, // Header + 0x84, 0x80, 0x00, // W: 65536 + 0x84, 0x80, 0x00 }; // H: 65536 + stream.reset(new SkMemoryStream(tooBigWbmp, sizeof(tooBigWbmp), false)); + codec.reset(SkCodec::NewFromStream(stream.detach())); + + REPORTER_ASSERT(r, !codec); +} |