Chromium Code Reviews| Index: third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
| diff --git a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
| index dff41e392ebff0c2226f28f98a7fb5d92c734c52..52c9d7552743f5c8a921917711d90f914d719255 100644 |
| --- a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
| +++ b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
| @@ -38,10 +38,11 @@ |
| #include "platform/image-decoders/png/PNGImageDecoder.h" |
| +#include "platform/image-decoders/png/PNGImageReader.h" |
| #include "png.h" |
| -#include "wtf/PtrUtil.h" |
| #include <memory> |
| + |
| #if !defined(PNG_LIBPNG_VER_MAJOR) || !defined(PNG_LIBPNG_VER_MINOR) |
| #error version error: compile against a versioned libpng. |
| #endif |
| @@ -55,123 +56,63 @@ |
| #define JMPBUF(png_ptr) png_ptr->jmpbuf |
| #endif |
| -namespace { |
| -inline blink::PNGImageDecoder* imageDecoder(png_structp png) |
| -{ |
| - return static_cast<blink::PNGImageDecoder*>(png_get_progressive_ptr(png)); |
| -} |
| +namespace blink { |
| -void PNGAPI pngHeaderAvailable(png_structp png, png_infop) |
| +PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes, size_t offset) |
| + : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) |
| + , m_offset(offset) |
| + , m_frameCountDecoded(false) |
| + , m_frameCount(0) |
| { |
| - imageDecoder(png)->headerAvailable(); |
| } |
| -void PNGAPI pngRowAvailable(png_structp png, png_bytep row, png_uint_32 rowIndex, int state) |
| +PNGImageDecoder::~PNGImageDecoder() |
| { |
| - imageDecoder(png)->rowAvailable(row, rowIndex, state); |
| } |
| -void PNGAPI pngComplete(png_structp png, png_infop) |
| +size_t PNGImageDecoder::decodeFrameCount() |
| { |
| - imageDecoder(png)->complete(); |
| + if (m_frameCountDecoded) |
| + return m_frameCount; |
| + |
| + parse(PNGParseQuery::PNGFrameCountQuery); |
| + // Similar reasoning to GIFImageDecodeer. If decoding fails, we don't |
|
cblume
2016/10/01 12:01:14
Probably don't need to mention the GIF decoder.
Th
joostouwerling
2016/10/01 17:51:38
Acknowledged.
|
| + // return 0 but we return the existing number of frames. This prevents us |
| + // from reporting zero frames when decoding fails halfway through the image. |
| + return failed() ? m_frameBufferCache.size() : m_frameCount; |
| } |
| -void PNGAPI pngFailed(png_structp png, png_const_charp) |
| +inline bool isComplete(const PNGImageDecoder* decoder) |
| { |
| - longjmp(JMPBUF(png), 1); |
| + return decoder->frameIsCompleteAtIndex(0); |
|
cblume
2016/10/01 12:01:14
I think this shouldn't be index 0. Maybe?
The old
joostouwerling
2016/10/01 17:51:38
You're correct. This slipped through since it was
cblume
2016/10/02 19:55:43
I took a quick look at the GIF decoder and it does
joostouwerling
2016/10/03 14:39:10
Ack.
scroggo_chromium
2016/10/04 14:50:16
I would remove the method isComplete entirely. I d
|
| } |
| -} // namespace |
| - |
| -namespace blink { |
| - |
| -class PNGImageReader final { |
| - USING_FAST_MALLOC(PNGImageReader); |
| - WTF_MAKE_NONCOPYABLE(PNGImageReader); |
| -public: |
| - PNGImageReader(PNGImageDecoder* decoder, size_t readOffset) |
| - : m_decoder(decoder) |
| - , m_readOffset(readOffset) |
| - , m_currentBufferSize(0) |
| - , m_decodingSizeOnly(false) |
| - , m_hasAlpha(false) |
| -#if USE(QCMSLIB) |
| - , m_rowBuffer() |
| -#endif |
| - { |
| - m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, pngFailed, 0); |
| - m_info = png_create_info_struct(m_png); |
| - png_set_progressive_read_fn(m_png, m_decoder, pngHeaderAvailable, pngRowAvailable, pngComplete); |
| - } |
| - |
| - ~PNGImageReader() |
| - { |
| - png_destroy_read_struct(m_png ? &m_png : 0, m_info ? &m_info : 0, 0); |
| - ASSERT(!m_png && !m_info); |
| - |
| - m_readOffset = 0; |
| - } |
| - |
| - bool decode(const SegmentReader& data, bool sizeOnly) |
| - { |
| - m_decodingSizeOnly = sizeOnly; |
| - |
| - // We need to do the setjmp here. Otherwise bad things will happen. |
| - if (setjmp(JMPBUF(m_png))) |
| - return m_decoder->setFailed(); |
| - |
| - const char* segment; |
| - while (size_t segmentLength = data.getSomeData(segment, m_readOffset)) { |
| - m_readOffset += segmentLength; |
| - m_currentBufferSize = m_readOffset; |
| - png_process_data(m_png, m_info, reinterpret_cast<png_bytep>(const_cast<char*>(segment)), segmentLength); |
| - if (sizeOnly ? m_decoder->isDecodedSizeAvailable() : m_decoder->frameIsCompleteAtIndex(0)) |
| - return true; |
| - } |
| - |
| - return false; |
| - } |
| +void PNGImageDecoder::parse(PNGParseQuery query) |
| +{ |
| + if (failed()) |
| + return; |
| - png_structp pngPtr() const { return m_png; } |
| - png_infop infoPtr() const { return m_info; } |
| + if (!m_reader) |
| + m_reader = wrapUnique(new PNGImageReader(this, m_offset)); |
| - size_t getReadOffset() const { return m_readOffset; } |
| - void setReadOffset(size_t offset) { m_readOffset = offset; } |
| - size_t currentBufferSize() const { return m_currentBufferSize; } |
| - bool decodingSizeOnly() const { return m_decodingSizeOnly; } |
| - void setHasAlpha(bool hasAlpha) { m_hasAlpha = hasAlpha; } |
| - bool hasAlpha() const { return m_hasAlpha; } |
| + if (!m_reader->parse(*m_data, query)) |
| + setFailed(); |
| - png_bytep interlaceBuffer() const { return m_interlaceBuffer.get(); } |
| - void createInterlaceBuffer(int size) { m_interlaceBuffer = wrapArrayUnique(new png_byte[size]); } |
| -#if USE(QCMSLIB) |
| - png_bytep rowBuffer() const { return m_rowBuffer.get(); } |
| - void createRowBuffer(int size) { m_rowBuffer = wrapArrayUnique(new png_byte[size]); } |
| -#endif |
| + if (isComplete(this) || failed()) |
| + m_reader.reset(); |
| -private: |
| - png_structp m_png; |
| - png_infop m_info; |
| - PNGImageDecoder* m_decoder; |
| - size_t m_readOffset; |
| - size_t m_currentBufferSize; |
| - bool m_decodingSizeOnly; |
| - bool m_hasAlpha; |
| - std::unique_ptr<png_byte[]> m_interlaceBuffer; |
| -#if USE(QCMSLIB) |
| - std::unique_ptr<png_byte[]> m_rowBuffer; |
| -#endif |
| -}; |
| +} |
| -PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes, size_t offset) |
| - : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) |
| - , m_offset(offset) |
| +bool PNGImageDecoder::isDecodedFrameCountAvailable() const |
| { |
| + return !failed() && m_frameCountDecoded; |
| } |
| -PNGImageDecoder::~PNGImageDecoder() |
| +void PNGImageDecoder::animationControlAvailable(size_t numFrames, size_t numRepetitions) |
| { |
| + m_frameCount = numFrames; |
| + m_frameCountDecoded = true; |
| } |
| void PNGImageDecoder::headerAvailable() |
| @@ -285,6 +226,13 @@ void PNGImageDecoder::headerAvailable() |
| void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int) |
| { |
| + // If we see a frame, but the frame count has not yet been decoded, we are |
|
scroggo_chromium
2016/10/04 14:50:16
Nit: I would lean towards using the word "parsed"
|
| + // dealing with a non animated PNG. |
|
cblume
2016/10/01 12:01:14
When a GIF says it has 3 frames but it actually ha
joostouwerling
2016/10/01 17:51:39
This is similar to the discussion in issue 2045293
cblume
2016/10/02 19:55:43
On 2016/10/01 17:51:39, joostouwerling wrote:
scroggo_chromium
2016/10/04 14:50:16
GIF does not have any notion of number of frames (
joostouwerling
2016/10/04 17:48:31
If there is no fcTL before the IDAT chunk, it only
|
| + if (!m_frameCountDecoded) { |
| + m_frameCountDecoded = true; |
| + m_frameCount = 1; |
| + } |
| + |
| if (m_frameBufferCache.isEmpty()) |
| return; |
| @@ -417,27 +365,4 @@ void PNGImageDecoder::complete() |
| m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); |
| } |
| -inline bool isComplete(const PNGImageDecoder* decoder) |
| -{ |
| - return decoder->frameIsCompleteAtIndex(0); |
| -} |
| - |
| -void PNGImageDecoder::decode(bool onlySize) |
| -{ |
| - if (failed()) |
| - return; |
| - |
| - if (!m_reader) |
| - m_reader = wrapUnique(new PNGImageReader(this, m_offset)); |
| - |
| - // If we couldn't decode the image but have received all the data, decoding |
| - // has failed. |
| - if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) |
| - setFailed(); |
| - |
| - // If decoding is done or failed, we don't need the PNGImageReader anymore. |
| - if (isComplete(this) || failed()) |
| - m_reader.reset(); |
| -} |
| - |
| } // namespace blink |