aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar scroggo <scroggo@google.com>2015-11-23 07:56:38 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-11-23 07:56:39 -0800
commit93c69fff535075e86596a2b224f52f454b060be3 (patch)
treea3e6990397278996df1d9c80d02a7a015e068a21
parent4b9596109a32ec61ef9ffbbf03684e9f99c3cbf7 (diff)
Revert of Add SkPngChunkReader. (patchset #9 id:160001 of https://codereview.chromium.org/1040453002/ )
Reason for revert: Busted Chromium builds: ../../third_party/skia/src/ports/SkImageDecoder_empty.cpp:63:17: error: no type named 'Peeker' in 'SkImageDecoder' SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker*) { ~~~~~~~~~~~~~~~~^ ../../third_party/skia/src/ports/SkImageDecoder_empty.cpp:63:51: error: unknown type name 'Peeker' SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker*) { Original issue's description: > Add SkPngChunkReader. > > This class allows a client of SkCodec to read chunks in the data > stream that are not recognized by libpng. This is used by Android > to specify ninepatch data. > > Taken from SkImageDecoder::Peeker. Modify the name of the class > and its method to be more specific to their use. Make > SkImageDecoder::Peeker a subclass of the new class, to help stage > the change in Android. > > Add a test to verify that it works. > > BUG=skia:4574 > BUG=skia:3257 > > Committed: https://skia.googlesource.com/skia/+/3389e00136188800b98ca69488c0418c374fd78b TBR=djsollen@google.com,reed@google.com,msarett@google.com NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=skia:4574 Review URL: https://codereview.chromium.org/1472863003
-rw-r--r--gyp/skia_for_android_framework_defines.gypi1
-rw-r--r--include/codec/SkCodec.h11
-rw-r--r--include/core/SkImageDecoder.h34
-rw-r--r--include/core/SkPngChunkReader.h45
-rw-r--r--src/codec/SkCodec.cpp35
-rw-r--r--src/codec/SkCodec_libpng.cpp79
-rw-r--r--src/codec/SkCodec_libpng.h22
-rw-r--r--src/images/SkImageDecoder.cpp2
-rw-r--r--src/images/SkImageDecoder_libpng.cpp7
-rw-r--r--tests/CodexTest.cpp160
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