Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(713)

Unified Diff: third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp

Issue 2386453003: WIP: Implement APNG (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698