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
This commit is contained in:
parent
4b9596109a
commit
93c69fff53
@ -19,7 +19,6 @@
|
|||||||
'SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS',
|
'SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS',
|
||||||
'SK_SUPPORT_LEGACY_GRADIENT_DITHERING',
|
'SK_SUPPORT_LEGACY_GRADIENT_DITHERING',
|
||||||
'SK_IGNORE_GL_TEXTURE_TARGET',
|
'SK_IGNORE_GL_TEXTURE_TARGET',
|
||||||
'SK_LEGACY_PEEKER',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include "SkTypes.h"
|
#include "SkTypes.h"
|
||||||
|
|
||||||
class SkData;
|
class SkData;
|
||||||
class SkPngChunkReader;
|
|
||||||
class SkSampler;
|
class SkSampler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,24 +28,18 @@ public:
|
|||||||
* If this stream represents an encoded image that we know how to decode,
|
* If this stream represents an encoded image that we know how to decode,
|
||||||
* return an SkCodec that can decode it. Otherwise return NULL.
|
* 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
|
* If NULL is returned, the stream is deleted immediately. Otherwise, the
|
||||||
* SkCodec takes ownership of it, and will delete it when done with it.
|
* 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,
|
* If this data represents an encoded image that we know how to decode,
|
||||||
* return an SkCodec that can decode it. Otherwise return NULL.
|
* 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.
|
* 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();
|
virtual ~SkCodec();
|
||||||
|
|
||||||
|
@ -10,14 +10,11 @@
|
|||||||
|
|
||||||
#include "SkBitmap.h"
|
#include "SkBitmap.h"
|
||||||
#include "SkImage.h"
|
#include "SkImage.h"
|
||||||
#include "SkPngChunkReader.h"
|
|
||||||
#include "SkRect.h"
|
#include "SkRect.h"
|
||||||
#include "SkRefCnt.h"
|
#include "SkRefCnt.h"
|
||||||
#include "SkTRegistry.h"
|
#include "SkTRegistry.h"
|
||||||
#include "SkTypes.h"
|
#include "SkTypes.h"
|
||||||
|
|
||||||
//#define SK_LEGACY_PEEKER
|
|
||||||
|
|
||||||
class SkStream;
|
class SkStream;
|
||||||
class SkStreamRewindable;
|
class SkStreamRewindable;
|
||||||
|
|
||||||
@ -129,20 +126,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool getRequireUnpremultipliedColors() const { return fRequireUnpremultipliedColors; }
|
bool getRequireUnpremultipliedColors() const { return fRequireUnpremultipliedColors; }
|
||||||
|
|
||||||
#ifdef SK_LEGACY_PEEKER
|
/** \class Peeker
|
||||||
// Android subclasses SkImageDecoder::Peeker, which has been changed into SkPngChunkReader.
|
|
||||||
// Temporarily use this class until Android can be updated to directly inherit from
|
Base class for optional callbacks to retrieve meta/chunk data out of
|
||||||
// SkPngChunkReader.
|
an image as it is being decoded.
|
||||||
class Peeker : public SkPngChunkReader {
|
*/
|
||||||
|
class Peeker : public SkRefCnt {
|
||||||
public:
|
public:
|
||||||
bool readChunk(const char tag[], const void* data, size_t length) final {
|
/** Return true to continue decoding, or false to indicate an error, which
|
||||||
return this->peek(tag, data, length);
|
will cause the decoder to not return the image.
|
||||||
}
|
*/
|
||||||
virtual bool peek(const char tag[], const void* data, size_t length) = 0;
|
virtual bool peek(const char tag[], const void* data, size_t length) = 0;
|
||||||
|
private:
|
||||||
|
typedef SkRefCnt INHERITED;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
SkPngChunkReader* getPeeker() const { return fPeeker; }
|
Peeker* getPeeker() const { return fPeeker; }
|
||||||
SkPngChunkReader* setPeeker(SkPngChunkReader*);
|
Peeker* setPeeker(Peeker*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default, the codec will try to comply with the "pref" colortype
|
* 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
|
to allocate the memory from a cache, volatile memory, or even from
|
||||||
an existing bitmap's memory.
|
an existing bitmap's memory.
|
||||||
|
|
||||||
If an SkPngChunkReader is installed via setPeeker, it may be used to
|
If a Peeker is installed via setPeeker, it may be used to peek into
|
||||||
peek into meta data during the decode.
|
meta data during the decode.
|
||||||
*/
|
*/
|
||||||
Result decode(SkStream*, SkBitmap* bitmap, SkColorType pref, Mode);
|
Result decode(SkStream*, SkBitmap* bitmap, SkColorType pref, Mode);
|
||||||
Result decode(SkStream* stream, SkBitmap* bitmap, Mode mode) {
|
Result decode(SkStream* stream, SkBitmap* bitmap, Mode mode) {
|
||||||
@ -350,7 +350,7 @@ protected:
|
|||||||
SkColorType getPrefColorType(SrcDepth, bool hasAlpha) const;
|
SkColorType getPrefColorType(SrcDepth, bool hasAlpha) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkPngChunkReader* fPeeker;
|
Peeker* fPeeker;
|
||||||
SkBitmap::Allocator* fAllocator;
|
SkBitmap::Allocator* fAllocator;
|
||||||
int fSampleSize;
|
int fSampleSize;
|
||||||
SkColorType fDefaultPref; // use if fUsePrefTable is false
|
SkColorType fDefaultPref; // use if fUsePrefTable is false
|
||||||
|
@ -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
|
|
@ -25,6 +25,7 @@ struct DecoderProc {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const DecoderProc gDecoderProcs[] = {
|
static const DecoderProc gDecoderProcs[] = {
|
||||||
|
{ SkPngCodec::IsPng, SkPngCodec::NewFromStream },
|
||||||
#if !defined(GOOGLE3)
|
#if !defined(GOOGLE3)
|
||||||
{ SkJpegCodec::IsJpeg, SkJpegCodec::NewFromStream },
|
{ SkJpegCodec::IsJpeg, SkJpegCodec::NewFromStream },
|
||||||
#endif
|
#endif
|
||||||
@ -35,8 +36,7 @@ static const DecoderProc gDecoderProcs[] = {
|
|||||||
{ SkWbmpCodec::IsWbmp, SkWbmpCodec::NewFromStream }
|
{ SkWbmpCodec::IsWbmp, SkWbmpCodec::NewFromStream }
|
||||||
};
|
};
|
||||||
|
|
||||||
SkCodec* SkCodec::NewFromStream(SkStream* stream,
|
SkCodec* SkCodec::NewFromStream(SkStream* stream) {
|
||||||
SkPngChunkReader* chunkReader) {
|
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -44,24 +44,15 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream,
|
|||||||
SkAutoTDelete<SkStream> streamDeleter(stream);
|
SkAutoTDelete<SkStream> streamDeleter(stream);
|
||||||
|
|
||||||
SkAutoTDelete<SkCodec> codec(nullptr);
|
SkAutoTDelete<SkCodec> codec(nullptr);
|
||||||
// PNG is special, since we want to be able to supply an SkPngChunkReader.
|
for (uint32_t i = 0; i < SK_ARRAY_COUNT(gDecoderProcs); i++) {
|
||||||
// But this code follows the same pattern as the loop.
|
DecoderProc proc = gDecoderProcs[i];
|
||||||
const bool isPng = SkPngCodec::IsPng(stream);
|
const bool correctFormat = proc.IsFormat(stream);
|
||||||
if (!stream->rewind()) {
|
if (!stream->rewind()) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (isPng) {
|
if (correctFormat) {
|
||||||
codec.reset(SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader));
|
codec.reset(proc.NewFromStream(streamDeleter.detach()));
|
||||||
} else {
|
break;
|
||||||
for (DecoderProc proc : gDecoderProcs) {
|
|
||||||
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) {
|
if (!data) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return NewFromStream(new SkMemoryStream(data), reader);
|
return NewFromStream(new SkMemoryStream(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream)
|
SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream)
|
||||||
|
@ -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
|
// Helpers
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -219,29 +211,14 @@ bool SkPngCodec::IsPng(SkStream* stream) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads the header and initializes the output fields, if not NULL.
|
// Reads the header, and initializes the passed in fields, if not nullptr (except
|
||||||
//
|
// stream, which is passed to the read function).
|
||||||
// @param stream Input data. Will be read to get enough information to properly
|
// Returns true on success, in which case the caller is responsible for calling
|
||||||
// setup the codec.
|
// png_destroy_read_struct. If it returns false, the passed in fields (except
|
||||||
// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
|
// stream) are unchanged.
|
||||||
// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
|
static bool read_header(SkStream* stream, png_structp* png_ptrp,
|
||||||
// expected to continue to own it for the lifetime of the png_ptr.
|
png_infop* info_ptrp, SkImageInfo* imageInfo,
|
||||||
// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
|
int* bitDepthPtr, int* numberPassesPtr) {
|
||||||
// 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) {
|
|
||||||
// The image is known to be a PNG. Decode enough to know the SkImageInfo.
|
// 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,
|
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
|
||||||
sk_error_fn, sk_warning_fn);
|
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);
|
png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
|
||||||
|
|
||||||
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
// FIXME: This is where the old code hooks up the Peeker. Does it need to
|
||||||
// FIXME: Does this need to be installed so early?
|
// be set this early? (i.e. where are the user chunks? early in the stream,
|
||||||
// hookup our chunkReader so we can see any user-chunks the caller may be interested in
|
// potentially?)
|
||||||
if (chunkReader) {
|
// If it does, we need to figure out a way to set it here.
|
||||||
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
|
|
||||||
|
|
||||||
// The call to png_read_info() gives us all of the information from the
|
// The call to png_read_info() gives us all of the information from the
|
||||||
// PNG file before the first IDAT (image data chunk).
|
// PNG file before the first IDAT (image data chunk).
|
||||||
@ -383,10 +356,9 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
|
|||||||
return true;
|
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)
|
png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses)
|
||||||
: INHERITED(info, stream)
|
: INHERITED(info, stream)
|
||||||
, fPngChunkReader(SkSafeRef(chunkReader))
|
|
||||||
, fPng_ptr(png_ptr)
|
, fPng_ptr(png_ptr)
|
||||||
, fInfo_ptr(info_ptr)
|
, fInfo_ptr(info_ptr)
|
||||||
, fSrcConfig(SkSwizzler::kUnknown)
|
, fSrcConfig(SkSwizzler::kUnknown)
|
||||||
@ -481,8 +453,7 @@ bool SkPngCodec::onRewind() {
|
|||||||
|
|
||||||
png_structp png_ptr;
|
png_structp png_ptr;
|
||||||
png_infop info_ptr;
|
png_infop info_ptr;
|
||||||
if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr,
|
if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr, nullptr)) {
|
||||||
nullptr, nullptr, nullptr)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,8 +602,8 @@ bool SkPngCodec::onReallyHasAlpha() const {
|
|||||||
class SkPngScanlineDecoder : public SkPngCodec {
|
class SkPngScanlineDecoder : public SkPngCodec {
|
||||||
public:
|
public:
|
||||||
SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
|
SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
|
||||||
SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
|
png_structp png_ptr, png_infop info_ptr, int bitDepth)
|
||||||
: INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1)
|
: INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1)
|
||||||
, fAlphaState(kUnknown_AlphaState)
|
, fAlphaState(kUnknown_AlphaState)
|
||||||
, fSrcRow(nullptr)
|
, fSrcRow(nullptr)
|
||||||
{}
|
{}
|
||||||
@ -715,9 +686,8 @@ private:
|
|||||||
class SkPngInterlacedScanlineDecoder : public SkPngCodec {
|
class SkPngInterlacedScanlineDecoder : public SkPngCodec {
|
||||||
public:
|
public:
|
||||||
SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
|
SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
|
||||||
SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr,
|
png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses)
|
||||||
int bitDepth, int numberPasses)
|
: INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses)
|
||||||
: INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses)
|
|
||||||
, fAlphaState(kUnknown_AlphaState)
|
, fAlphaState(kUnknown_AlphaState)
|
||||||
, fHeight(-1)
|
, fHeight(-1)
|
||||||
, fCanSkipRewind(false)
|
, fCanSkipRewind(false)
|
||||||
@ -852,7 +822,7 @@ private:
|
|||||||
typedef SkPngCodec INHERITED;
|
typedef SkPngCodec INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
|
SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
|
||||||
SkAutoTDelete<SkStream> streamDeleter(stream);
|
SkAutoTDelete<SkStream> streamDeleter(stream);
|
||||||
png_structp png_ptr;
|
png_structp png_ptr;
|
||||||
png_infop info_ptr;
|
png_infop info_ptr;
|
||||||
@ -860,16 +830,15 @@ SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead
|
|||||||
int bitDepth;
|
int bitDepth;
|
||||||
int numberPasses;
|
int numberPasses;
|
||||||
|
|
||||||
if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth,
|
if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &numberPasses)) {
|
||||||
&numberPasses)) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1 == numberPasses) {
|
if (1 == numberPasses) {
|
||||||
return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
|
return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr, info_ptr,
|
||||||
png_ptr, info_ptr, bitDepth);
|
bitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
|
return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr,
|
||||||
png_ptr, info_ptr, bitDepth, numberPasses);
|
info_ptr, bitDepth, numberPasses);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include "SkCodec.h"
|
#include "SkCodec.h"
|
||||||
#include "SkColorTable.h"
|
#include "SkColorTable.h"
|
||||||
#include "SkPngChunkReader.h"
|
|
||||||
#include "SkEncodedFormat.h"
|
#include "SkEncodedFormat.h"
|
||||||
#include "SkImageInfo.h"
|
#include "SkImageInfo.h"
|
||||||
#include "SkRefCnt.h"
|
#include "SkRefCnt.h"
|
||||||
@ -22,7 +21,7 @@ public:
|
|||||||
static bool IsPng(SkStream*);
|
static bool IsPng(SkStream*);
|
||||||
|
|
||||||
// Assume IsPng was called and returned true.
|
// Assume IsPng was called and returned true.
|
||||||
static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL);
|
static SkCodec* NewFromStream(SkStream*);
|
||||||
|
|
||||||
virtual ~SkPngCodec();
|
virtual ~SkPngCodec();
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ protected:
|
|||||||
return fSwizzler;
|
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; }
|
png_structp png_ptr() { return fPng_ptr; }
|
||||||
SkSwizzler* swizzler() { return fSwizzler; }
|
SkSwizzler* swizzler() { return fSwizzler; }
|
||||||
@ -63,18 +62,17 @@ protected:
|
|||||||
virtual AlphaState alphaInScanlineDecode() const = 0;
|
virtual AlphaState alphaInScanlineDecode() const = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkAutoTUnref<SkPngChunkReader> fPngChunkReader;
|
png_structp fPng_ptr;
|
||||||
png_structp fPng_ptr;
|
png_infop fInfo_ptr;
|
||||||
png_infop fInfo_ptr;
|
|
||||||
|
|
||||||
// These are stored here so they can be used both by normal decoding and scanline decoding.
|
// These are stored here so they can be used both by normal decoding and scanline decoding.
|
||||||
SkAutoTUnref<SkColorTable> fColorTable; // May be unpremul.
|
SkAutoTUnref<SkColorTable> fColorTable; // May be unpremul.
|
||||||
SkAutoTDelete<SkSwizzler> fSwizzler;
|
SkAutoTDelete<SkSwizzler> fSwizzler;
|
||||||
|
|
||||||
SkSwizzler::SrcConfig fSrcConfig;
|
SkSwizzler::SrcConfig fSrcConfig;
|
||||||
const int fNumberPasses;
|
const int fNumberPasses;
|
||||||
int fBitDepth;
|
int fBitDepth;
|
||||||
AlphaState fAlphaState;
|
AlphaState fAlphaState;
|
||||||
|
|
||||||
bool decodePalette(bool premultiply, int* ctableCount);
|
bool decodePalette(bool premultiply, int* ctableCount);
|
||||||
void destroyReadStruct();
|
void destroyReadStruct();
|
||||||
|
@ -83,7 +83,7 @@ const char* SkImageDecoder::GetFormatName(Format format) {
|
|||||||
return "Unknown Format";
|
return "Unknown Format";
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPngChunkReader* SkImageDecoder::setPeeker(SkPngChunkReader* peeker) {
|
SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
|
||||||
SkRefCnt_SafeAssign(fPeeker, peeker);
|
SkRefCnt_SafeAssign(fPeeker, peeker);
|
||||||
return peeker;
|
return peeker;
|
||||||
}
|
}
|
||||||
|
@ -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
|
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
||||||
static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
|
static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
|
||||||
SkPngChunkReader* peeker = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
|
SkImageDecoder::Peeker* peeker =
|
||||||
// readChunk() returning true means continue decoding
|
(SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
|
||||||
return peeker->readChunk((const char*)chunk->name, chunk->data, chunk->size) ?
|
// peek() returning true means continue decoding
|
||||||
|
return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
|
||||||
1 : -1;
|
1 : -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,12 +12,8 @@
|
|||||||
#include "SkData.h"
|
#include "SkData.h"
|
||||||
#include "SkMD5.h"
|
#include "SkMD5.h"
|
||||||
#include "SkRandom.h"
|
#include "SkRandom.h"
|
||||||
#include "SkStream.h"
|
|
||||||
#include "SkPngChunkReader.h"
|
|
||||||
#include "Test.h"
|
#include "Test.h"
|
||||||
|
|
||||||
#include "png.h"
|
|
||||||
|
|
||||||
static SkStreamAsset* resource(const char path[]) {
|
static SkStreamAsset* resource(const char path[]) {
|
||||||
SkString fullPath = GetResourcePath(path);
|
SkString fullPath = GetResourcePath(path);
|
||||||
return SkStream::NewFromFile(fullPath.c_str());
|
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, "index8.png");
|
||||||
test_invalid_parameters(r, "mandrill.wbmp");
|
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
|
|
||||||
|
Loading…
Reference in New Issue
Block a user