diff options
-rw-r--r-- | gyp/skia_for_android_framework_defines.gypi | 1 | ||||
-rw-r--r-- | include/codec/SkCodec.h | 11 | ||||
-rw-r--r-- | include/core/SkImageDecoder.h | 34 | ||||
-rw-r--r-- | include/core/SkPngChunkReader.h | 45 | ||||
-rw-r--r-- | src/codec/SkCodec.cpp | 35 | ||||
-rw-r--r-- | src/codec/SkCodec_libpng.cpp | 79 | ||||
-rw-r--r-- | src/codec/SkCodec_libpng.h | 22 | ||||
-rw-r--r-- | src/images/SkImageDecoder.cpp | 2 | ||||
-rw-r--r-- | src/images/SkImageDecoder_libpng.cpp | 7 | ||||
-rw-r--r-- | tests/CodexTest.cpp | 160 |
10 files changed, 71 insertions, 325 deletions
diff --git a/gyp/skia_for_android_framework_defines.gypi b/gyp/skia_for_android_framework_defines.gypi index 825429b9a0..773c530d0d 100644 --- a/gyp/skia_for_android_framework_defines.gypi +++ b/gyp/skia_for_android_framework_defines.gypi @@ -19,7 +19,6 @@ 'SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS', 'SK_SUPPORT_LEGACY_GRADIENT_DITHERING', 'SK_IGNORE_GL_TEXTURE_TARGET', - 'SK_LEGACY_PEEKER', ], }, } diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index dffab6b377..d90fea8ced 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -17,7 +17,6 @@ #include "SkTypes.h" class SkData; -class SkPngChunkReader; class SkSampler; /** @@ -29,24 +28,18 @@ public: * If this stream represents an encoded image that we know how to decode, * return an SkCodec that can decode it. Otherwise return NULL. * - * If SkPngChunkReader is not NULL, take a ref and pass it to libpng if - * the image is a png. - * * If NULL is returned, the stream is deleted immediately. Otherwise, the * SkCodec takes ownership of it, and will delete it when done with it. */ - static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL); + static SkCodec* NewFromStream(SkStream*); /** * If this data represents an encoded image that we know how to decode, * return an SkCodec that can decode it. Otherwise return NULL. * - * If SkPngChunkReader is not NULL, take a ref and pass it to libpng if - * the image is a png. - * * Will take a ref if it returns a codec, else will not affect the data. */ - static SkCodec* NewFromData(SkData*, SkPngChunkReader* = NULL); + static SkCodec* NewFromData(SkData*); virtual ~SkCodec(); diff --git a/include/core/SkImageDecoder.h b/include/core/SkImageDecoder.h index 30323b59ee..144878c166 100644 --- a/include/core/SkImageDecoder.h +++ b/include/core/SkImageDecoder.h @@ -10,14 +10,11 @@ #include "SkBitmap.h" #include "SkImage.h" -#include "SkPngChunkReader.h" #include "SkRect.h" #include "SkRefCnt.h" #include "SkTRegistry.h" #include "SkTypes.h" -//#define SK_LEGACY_PEEKER - class SkStream; class SkStreamRewindable; @@ -129,20 +126,23 @@ public: */ bool getRequireUnpremultipliedColors() const { return fRequireUnpremultipliedColors; } -#ifdef SK_LEGACY_PEEKER - // Android subclasses SkImageDecoder::Peeker, which has been changed into SkPngChunkReader. - // Temporarily use this class until Android can be updated to directly inherit from - // SkPngChunkReader. - class Peeker : public SkPngChunkReader { + /** \class Peeker + + Base class for optional callbacks to retrieve meta/chunk data out of + an image as it is being decoded. + */ + class Peeker : public SkRefCnt { public: - bool readChunk(const char tag[], const void* data, size_t length) final { - return this->peek(tag, data, length); - } + /** Return true to continue decoding, or false to indicate an error, which + will cause the decoder to not return the image. + */ virtual bool peek(const char tag[], const void* data, size_t length) = 0; + private: + typedef SkRefCnt INHERITED; }; -#endif - SkPngChunkReader* getPeeker() const { return fPeeker; } - SkPngChunkReader* setPeeker(SkPngChunkReader*); + + Peeker* getPeeker() const { return fPeeker; } + Peeker* setPeeker(Peeker*); /** * By default, the codec will try to comply with the "pref" colortype @@ -229,8 +229,8 @@ public: to allocate the memory from a cache, volatile memory, or even from an existing bitmap's memory. - If an SkPngChunkReader is installed via setPeeker, it may be used to - peek into meta data during the decode. + If a Peeker is installed via setPeeker, it may be used to peek into + meta data during the decode. */ Result decode(SkStream*, SkBitmap* bitmap, SkColorType pref, Mode); Result decode(SkStream* stream, SkBitmap* bitmap, Mode mode) { @@ -350,7 +350,7 @@ protected: SkColorType getPrefColorType(SrcDepth, bool hasAlpha) const; private: - SkPngChunkReader* fPeeker; + Peeker* fPeeker; SkBitmap::Allocator* fAllocator; int fSampleSize; SkColorType fDefaultPref; // use if fUsePrefTable is false diff --git a/include/core/SkPngChunkReader.h b/include/core/SkPngChunkReader.h deleted file mode 100644 index f424dd8cfc..0000000000 --- a/include/core/SkPngChunkReader.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPngChunkReader_DEFINED -#define SkPngChunkReader_DEFINED - -#include "SkTypes.h" -#include "SkRefCnt.h" - -/** - * SkPngChunkReader - * - * Base class for optional callbacks to retrieve meta/chunk data out of a PNG - * encoded image as it is being decoded. - * Used by SkImageDecoder and SkCodec. - */ -class SkPngChunkReader : public SkRefCnt { -public: - /** - * This will be called by the decoder when it sees an unknown chunk. - * - * Use by SkCodec: - * Depending on the location of the unknown chunks, this callback may be - * called by - * - the factory (NewFromStream/NewFromData) - * - getPixels - * - startScanlineDecode - * - the first call to getScanlines/skipScanlines - * The callback may be called from a different thread (e.g. if the SkCodec - * is passed to another thread), and it may be called multiple times, if - * the SkCodec is used multiple times. - * - * @param tag Name for this type of chunk. - * @param data Data to be interpreted by the subclass. - * @param length Number of bytes of data in the chunk. - * @return true to continue decoding, or false to indicate an error, which - * will cause the decoder to not return the image. - */ - virtual bool readChunk(const char tag[], const void* data, size_t length) = 0; -}; -#endif // SkPngChunkReader_DEFINED diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 11eb1f9847..071a4b8371 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -25,6 +25,7 @@ struct DecoderProc { }; static const DecoderProc gDecoderProcs[] = { + { SkPngCodec::IsPng, SkPngCodec::NewFromStream }, #if !defined(GOOGLE3) { SkJpegCodec::IsJpeg, SkJpegCodec::NewFromStream }, #endif @@ -35,8 +36,7 @@ static const DecoderProc gDecoderProcs[] = { { SkWbmpCodec::IsWbmp, SkWbmpCodec::NewFromStream } }; -SkCodec* SkCodec::NewFromStream(SkStream* stream, - SkPngChunkReader* chunkReader) { +SkCodec* SkCodec::NewFromStream(SkStream* stream) { if (!stream) { return nullptr; } @@ -44,24 +44,15 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream, SkAutoTDelete<SkStream> streamDeleter(stream); SkAutoTDelete<SkCodec> codec(nullptr); - // PNG is special, since we want to be able to supply an SkPngChunkReader. - // But this code follows the same pattern as the loop. - const bool isPng = SkPngCodec::IsPng(stream); - if (!stream->rewind()) { - return NULL; - } - if (isPng) { - codec.reset(SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader)); - } else { - for (DecoderProc proc : gDecoderProcs) { - const bool correctFormat = proc.IsFormat(stream); - if (!stream->rewind()) { - return nullptr; - } - if (correctFormat) { - codec.reset(proc.NewFromStream(streamDeleter.detach())); - break; - } + for (uint32_t i = 0; i < SK_ARRAY_COUNT(gDecoderProcs); i++) { + DecoderProc proc = gDecoderProcs[i]; + const bool correctFormat = proc.IsFormat(stream); + if (!stream->rewind()) { + return nullptr; + } + if (correctFormat) { + codec.reset(proc.NewFromStream(streamDeleter.detach())); + break; } } @@ -77,11 +68,11 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream, } } -SkCodec* SkCodec::NewFromData(SkData* data, SkPngChunkReader* reader) { +SkCodec* SkCodec::NewFromData(SkData* data) { if (!data) { return nullptr; } - return NewFromStream(new SkMemoryStream(data), reader); + return NewFromStream(new SkMemoryStream(data)); } SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream) diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp index 355d493309..82c952e97b 100644 --- a/src/codec/SkCodec_libpng.cpp +++ b/src/codec/SkCodec_libpng.cpp @@ -65,14 +65,6 @@ static void sk_read_fn(png_structp png_ptr, png_bytep data, } } -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { - SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr); - // readChunk() returning true means continue decoding - return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1; -} -#endif - /////////////////////////////////////////////////////////////////////////////// // Helpers /////////////////////////////////////////////////////////////////////////////// @@ -219,29 +211,14 @@ bool SkPngCodec::IsPng(SkStream* stream) { return true; } -// Reads the header and initializes the output fields, if not NULL. -// -// @param stream Input data. Will be read to get enough information to properly -// setup the codec. -// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. -// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is -// expected to continue to own it for the lifetime of the png_ptr. -// @param png_ptrp Optional output variable. If non-NULL, will be set to a new -// png_structp on success. -// @param info_ptrp Optional output variable. If non-NULL, will be set to a new -// png_infop on success; -// @param imageInfo Optional output variable. If non-NULL, will be set to -// reflect the properties of the encoded image on success. -// @param bitDepthPtr Optional output variable. If non-NULL, will be set to the -// bit depth of the encoded image on success. -// @param numberPassesPtr Optional output variable. If non-NULL, will be set to -// the number_passes of the encoded image on success. -// @return true on success, in which case the caller is responsible for calling -// png_destroy_read_struct(png_ptrp, info_ptrp). -// If it returns false, the passed in fields (except stream) are unchanged. -static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, - png_structp* png_ptrp, png_infop* info_ptrp, - SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPassesPtr) { +// Reads the header, and initializes the passed in fields, if not nullptr (except +// stream, which is passed to the read function). +// Returns true on success, in which case the caller is responsible for calling +// png_destroy_read_struct. If it returns false, the passed in fields (except +// stream) are unchanged. +static bool read_header(SkStream* stream, png_structp* png_ptrp, + png_infop* info_ptrp, SkImageInfo* imageInfo, + int* bitDepthPtr, int* numberPassesPtr) { // The image is known to be a PNG. Decode enough to know the SkImageInfo. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, sk_error_fn, sk_warning_fn); @@ -266,14 +243,10 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - // FIXME: Does this need to be installed so early? - // hookup our chunkReader so we can see any user-chunks the caller may be interested in - if (chunkReader) { - png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); - png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk); - } -#endif + // FIXME: This is where the old code hooks up the Peeker. Does it need to + // be set this early? (i.e. where are the user chunks? early in the stream, + // potentially?) + // If it does, we need to figure out a way to set it here. // The call to png_read_info() gives us all of the information from the // PNG file before the first IDAT (image data chunk). @@ -383,10 +356,9 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, return true; } -SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkReader* chunkReader, +SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses) : INHERITED(info, stream) - , fPngChunkReader(SkSafeRef(chunkReader)) , fPng_ptr(png_ptr) , fInfo_ptr(info_ptr) , fSrcConfig(SkSwizzler::kUnknown) @@ -481,8 +453,7 @@ bool SkPngCodec::onRewind() { png_structp png_ptr; png_infop info_ptr; - if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, - nullptr, nullptr, nullptr)) { + if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr, nullptr)) { return false; } @@ -631,8 +602,8 @@ bool SkPngCodec::onReallyHasAlpha() const { class SkPngScanlineDecoder : public SkPngCodec { public: SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, - SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth) - : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1) + png_structp png_ptr, png_infop info_ptr, int bitDepth) + : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1) , fAlphaState(kUnknown_AlphaState) , fSrcRow(nullptr) {} @@ -715,9 +686,8 @@ private: class SkPngInterlacedScanlineDecoder : public SkPngCodec { public: SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, - SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, - int bitDepth, int numberPasses) - : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses) + png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses) + : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses) , fAlphaState(kUnknown_AlphaState) , fHeight(-1) , fCanSkipRewind(false) @@ -852,7 +822,7 @@ private: typedef SkPngCodec INHERITED; }; -SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { +SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { SkAutoTDelete<SkStream> streamDeleter(stream); png_structp png_ptr; png_infop info_ptr; @@ -860,16 +830,15 @@ SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead int bitDepth; int numberPasses; - if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth, - &numberPasses)) { + if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &numberPasses)) { return nullptr; } if (1 == numberPasses) { - return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, - png_ptr, info_ptr, bitDepth); + return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr, info_ptr, + bitDepth); } - return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, - png_ptr, info_ptr, bitDepth, numberPasses); + return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr, + info_ptr, bitDepth, numberPasses); } diff --git a/src/codec/SkCodec_libpng.h b/src/codec/SkCodec_libpng.h index c2a5f4a707..9809b0c39a 100644 --- a/src/codec/SkCodec_libpng.h +++ b/src/codec/SkCodec_libpng.h @@ -7,7 +7,6 @@ #include "SkCodec.h" #include "SkColorTable.h" -#include "SkPngChunkReader.h" #include "SkEncodedFormat.h" #include "SkImageInfo.h" #include "SkRefCnt.h" @@ -22,7 +21,7 @@ public: static bool IsPng(SkStream*); // Assume IsPng was called and returned true. - static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL); + static SkCodec* NewFromStream(SkStream*); virtual ~SkPngCodec(); @@ -42,7 +41,7 @@ protected: return fSwizzler; } - SkPngCodec(const SkImageInfo&, SkStream*, SkPngChunkReader*, png_structp, png_infop, int, int); + SkPngCodec(const SkImageInfo&, SkStream*, png_structp, png_infop, int, int); png_structp png_ptr() { return fPng_ptr; } SkSwizzler* swizzler() { return fSwizzler; } @@ -63,18 +62,17 @@ protected: virtual AlphaState alphaInScanlineDecode() const = 0; private: - SkAutoTUnref<SkPngChunkReader> fPngChunkReader; - png_structp fPng_ptr; - png_infop fInfo_ptr; + png_structp fPng_ptr; + png_infop fInfo_ptr; // These are stored here so they can be used both by normal decoding and scanline decoding. - SkAutoTUnref<SkColorTable> fColorTable; // May be unpremul. - SkAutoTDelete<SkSwizzler> fSwizzler; + SkAutoTUnref<SkColorTable> fColorTable; // May be unpremul. + SkAutoTDelete<SkSwizzler> fSwizzler; - SkSwizzler::SrcConfig fSrcConfig; - const int fNumberPasses; - int fBitDepth; - AlphaState fAlphaState; + SkSwizzler::SrcConfig fSrcConfig; + const int fNumberPasses; + int fBitDepth; + AlphaState fAlphaState; bool decodePalette(bool premultiply, int* ctableCount); void destroyReadStruct(); diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp index 221faf74d5..d2ad553769 100644 --- a/src/images/SkImageDecoder.cpp +++ b/src/images/SkImageDecoder.cpp @@ -83,7 +83,7 @@ const char* SkImageDecoder::GetFormatName(Format format) { return "Unknown Format"; } -SkPngChunkReader* SkImageDecoder::setPeeker(SkPngChunkReader* peeker) { +SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) { SkRefCnt_SafeAssign(fPeeker, peeker); return peeker; } diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp index a03ed10453..47963b5543 100644 --- a/src/images/SkImageDecoder_libpng.cpp +++ b/src/images/SkImageDecoder_libpng.cpp @@ -124,9 +124,10 @@ static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { - SkPngChunkReader* peeker = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr); - // readChunk() returning true means continue decoding - return peeker->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? + SkImageDecoder::Peeker* peeker = + (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); + // peek() returning true means continue decoding + return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1; } #endif diff --git a/tests/CodexTest.cpp b/tests/CodexTest.cpp index b53cbe1a4d..febaf7d43b 100644 --- a/tests/CodexTest.cpp +++ b/tests/CodexTest.cpp @@ -12,12 +12,8 @@ #include "SkData.h" #include "SkMD5.h" #include "SkRandom.h" -#include "SkStream.h" -#include "SkPngChunkReader.h" #include "Test.h" -#include "png.h" - static SkStreamAsset* resource(const char path[]) { SkString fullPath = GetResourcePath(path); return SkStream::NewFromFile(fullPath.c_str()); @@ -689,159 +685,3 @@ DEF_TEST(Codec_Params, r) { test_invalid_parameters(r, "index8.png"); test_invalid_parameters(r, "mandrill.wbmp"); } - -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)) { - png_error(png_ptr, "sk_write_fn Error!"); - } -} - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -DEF_TEST(Codec_pngChunkReader, r) { - // Create a dummy bitmap. Use unpremul RGBA for libpng. - SkBitmap bm; - const int w = 1; - const int h = 1; - const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, - kUnpremul_SkAlphaType); - bm.setInfo(bmInfo); - bm.allocPixels(); - bm.eraseColor(SK_ColorBLUE); - SkMD5::Digest goodDigest; - md5(bm, &goodDigest); - - // Write to a png file. - png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - REPORTER_ASSERT(r, png); - if (!png) { - return; - } - - png_infop info = png_create_info_struct(png); - REPORTER_ASSERT(r, info); - if (!info) { - png_destroy_write_struct(&png, nullptr); - return; - } - - if (setjmp(png_jmpbuf(png))) { - ERRORF(r, "failed writing png"); - png_destroy_write_struct(&png, &info); - return; - } - - SkDynamicMemoryWStream wStream; - png_set_write_fn(png, (void*) (&wStream), codex_test_write_fn, nullptr); - - png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8, - PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - // Create some chunks that match the Android framework's use. - static png_unknown_chunk gUnknowns[] = { - { "npOl", (png_byte*)"outline", sizeof("outline"), PNG_HAVE_PLTE }, - { "npLb", (png_byte*)"layoutBounds", sizeof("layoutBounds"), PNG_HAVE_PLTE }, - { "npTc", (png_byte*)"ninePatchData", sizeof("ninePatchData"), PNG_HAVE_PLTE }, - }; - - png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"npOl\0npLb\0npTc\0", 3); - png_set_unknown_chunks(png, info, gUnknowns, SK_ARRAY_COUNT(gUnknowns)); -#if PNG_LIBPNG_VER < 10600 - /* Deal with unknown chunk location bug in 1.5.x and earlier */ - png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_PLTE); - png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_PLTE); -#endif - - png_write_info(png, info); - - for (int j = 0; j < h; j++) { - png_bytep row = (png_bytep)(bm.getAddr(0, j)); - png_write_rows(png, &row, 1); - } - png_write_end(png, info); - png_destroy_write_struct(&png, &info); - - class ChunkReader : public SkPngChunkReader { - public: - ChunkReader(skiatest::Reporter* r) - : fReporter(r) - { - this->reset(); - } - - bool readChunk(const char tag[], const void* data, size_t length) override { - for (size_t i = 0; i < SK_ARRAY_COUNT(gUnknowns); ++i) { - if (!strcmp(tag, (const char*) gUnknowns[i].name)) { - // Tag matches. This should have been the first time we see it. - REPORTER_ASSERT(fReporter, !fSeen[i]); - fSeen[i] = true; - - // Data and length should match - REPORTER_ASSERT(fReporter, length == gUnknowns[i].size); - REPORTER_ASSERT(fReporter, !strcmp((const char*) data, - (const char*) gUnknowns[i].data)); - return true; - } - } - ERRORF(fReporter, "Saw an unexpected unknown chunk."); - return true; - } - - bool allHaveBeenSeen() { - bool ret = true; - for (auto seen : fSeen) { - ret &= seen; - } - return ret; - } - - void reset() { - sk_bzero(fSeen, sizeof(fSeen)); - } - - private: - skiatest::Reporter* fReporter; // Unowned - bool fSeen[3]; - }; - - ChunkReader chunkReader(r); - - // Now read the file with SkCodec. - SkAutoTUnref<SkData> data(wStream.copyToData()); - SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data, &chunkReader)); - REPORTER_ASSERT(r, codec); - if (!codec) { - return; - } - - // Now compare to the original. - SkBitmap decodedBm; - decodedBm.setInfo(codec->getInfo()); - decodedBm.allocPixels(); - SkCodec::Result result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), - decodedBm.rowBytes()); - REPORTER_ASSERT(r, SkCodec::kSuccess == result); - - if (decodedBm.colorType() != bm.colorType()) { - SkBitmap tmp; - bool success = decodedBm.copyTo(&tmp, bm.colorType()); - REPORTER_ASSERT(r, success); - if (!success) { - return; - } - - tmp.swap(decodedBm); - } - - compare_to_good_digest(r, goodDigest, decodedBm); - REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen()); - - // Decoding again will read the chunks again. - chunkReader.reset(); - REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen()); - result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm.rowBytes()); - REPORTER_ASSERT(r, SkCodec::kSuccess == result); - REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen()); -} -#endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |