summaryrefslogtreecommitdiff
path: root/package/libpng/patches
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2014-12-05 21:09:39 -0600
committerWaldemar Brodkorb <wbx@openadk.org>2014-12-05 21:09:52 -0600
commitb2bb927f188dc86b0fb852645a62ece5c319ad6b (patch)
tree84d7a0a20545487e2905be4d16e2b68f3e1624eb /package/libpng/patches
parent142b50071ac4ed5124c8172ca7d30e351e465768 (diff)
update to kodirc2 and libcec 2.2.0
Diffstat (limited to 'package/libpng/patches')
-rw-r--r--package/libpng/patches/libpng-1.6.14-apng.patch1701
1 files changed, 1701 insertions, 0 deletions
diff --git a/package/libpng/patches/libpng-1.6.14-apng.patch b/package/libpng/patches/libpng-1.6.14-apng.patch
new file mode 100644
index 000000000..c168b02cc
--- /dev/null
+++ b/package/libpng/patches/libpng-1.6.14-apng.patch
@@ -0,0 +1,1701 @@
+diff -Naru libpng-1.6.14.org/png.h libpng-1.6.14/png.h
+--- libpng-1.6.14.org/png.h 2014-10-23 23:57:22.656674917 +0900
++++ libpng-1.6.14/png.h 2014-10-23 23:57:22.729677456 +0900
+@@ -470,6 +470,10 @@
+ # include "pnglibconf.h"
+ #endif
+
++#define PNG_APNG_SUPPORTED
++#define PNG_READ_APNG_SUPPORTED
++#define PNG_WRITE_APNG_SUPPORTED
++
+ #ifndef PNG_VERSION_INFO_ONLY
+ /* Machine specific configuration. */
+ # include "pngconf.h"
+@@ -560,6 +564,17 @@
+ * See pngconf.h for base types that vary by machine/system
+ */
+
++#ifdef PNG_APNG_SUPPORTED
++/* dispose_op flags from inside fcTL */
++#define PNG_DISPOSE_OP_NONE 0x00
++#define PNG_DISPOSE_OP_BACKGROUND 0x01
++#define PNG_DISPOSE_OP_PREVIOUS 0x02
++
++/* blend_op flags from inside fcTL */
++#define PNG_BLEND_OP_SOURCE 0x00
++#define PNG_BLEND_OP_OVER 0x01
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* This triggers a compiler error in png.c, if png.c and png.h
+ * do not agree upon the version number.
+ */
+@@ -880,6 +895,10 @@
+ #define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
+ #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
+ #define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_INFO_acTL 0x10000
++#define PNG_INFO_fcTL 0x20000
++#endif
+
+ /* This is used for the transformation routines, as some of them
+ * change these values for the row. It also should enable using
+@@ -917,6 +936,10 @@
+ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
++#ifdef PNG_APNG_SUPPORTED
++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
++ png_uint_32));
++#endif
+
+ /* The following callback receives png_uint_32 row_number, int pass for the
+ * png_bytep data of the row. When transforming an interlaced image the
+@@ -3255,6 +3278,74 @@
+ /*******************************************************************************
+ * END OF HARDWARE AND SOFTWARE OPTIONS
+ ******************************************************************************/
++#ifdef PNG_APNG_SUPPORTED
++PNG_EXPORT(245, png_uint_32, png_get_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
++
++PNG_EXPORT(246, png_uint_32, png_set_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
++
++PNG_EXPORT(247, png_uint_32, png_get_num_frames, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(248, png_uint_32, png_get_num_plays, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(249, png_uint_32, png_get_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
++ png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
++ png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
++ png_byte *blend_op));
++
++PNG_EXPORT(250, png_uint_32, png_set_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
++ png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++ png_byte blend_op));
++
++PNG_EXPORT(251, png_uint_32, png_get_next_frame_width,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(252, png_uint_32, png_get_next_frame_height,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(253, png_uint_32, png_get_next_frame_x_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(254, png_uint_32, png_get_next_frame_y_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(255, png_uint_16, png_get_next_frame_delay_num,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(256, png_uint_16, png_get_next_frame_delay_den,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(257, png_byte, png_get_next_frame_dispose_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(258, png_byte, png_get_next_frame_blend_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(259, png_byte, png_get_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(260, png_uint_32, png_set_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_EXPORT(261, void, png_read_frame_head, (png_structp png_ptr,
++ png_infop info_ptr));
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_EXPORT(262, void, png_set_progressive_frame_fn, (png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn));
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_EXPORT(263, void, png_write_frame_head, (png_structp png_ptr,
++ png_infop info_ptr, png_bytepp row_pointers,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++ png_byte blend_op));
++
++PNG_EXPORT(264, void, png_write_frame_tail, (png_structp png_ptr,
++ png_infop info_ptr));
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
+
+ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+ * defs, and in scripts/symbols.def.
+@@ -3264,7 +3355,11 @@
+ * one to use is one more than this.)
+ */
+ #ifdef PNG_EXPORT_LAST_ORDINAL
++#ifdef PNG_APNG_SUPPORTED
++ PNG_EXPORT_LAST_ORDINAL(264);
++#else
+ PNG_EXPORT_LAST_ORDINAL(244);
++#endif /* PNG_APNG_SUPPORTED */
+ #endif
+
+ #ifdef __cplusplus
+diff -Naru libpng-1.6.14.org/pngget.c libpng-1.6.14/pngget.c
+--- libpng-1.6.14.org/pngget.c 2014-10-23 23:57:22.657674952 +0900
++++ libpng-1.6.14/pngget.c 2014-10-23 23:57:22.730677491 +0900
+@@ -1195,4 +1195,166 @@
+ # endif
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 *num_frames, png_uint_32 *num_plays)
++{
++ png_debug1(1, "in %s retrieval function", "acTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_acTL) &&
++ num_frames != NULL && num_plays != NULL)
++ {
++ *num_frames = info_ptr->num_frames;
++ *num_plays = info_ptr->num_plays;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_frames()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_frames);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_plays()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_plays);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 *width, png_uint_32 *height,
++ png_uint_32 *x_offset, png_uint_32 *y_offset,
++ png_uint_16 *delay_num, png_uint_16 *delay_den,
++ png_byte *dispose_op, png_byte *blend_op)
++{
++ png_debug1(1, "in %s retrieval function", "fcTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_fcTL) &&
++ width != NULL && height != NULL &&
++ x_offset != NULL && y_offset != NULL &&
++ delay_num != NULL && delay_den != NULL &&
++ dispose_op != NULL && blend_op != NULL)
++ {
++ *width = info_ptr->next_frame_width;
++ *height = info_ptr->next_frame_height;
++ *x_offset = info_ptr->next_frame_x_offset;
++ *y_offset = info_ptr->next_frame_y_offset;
++ *delay_num = info_ptr->next_frame_delay_num;
++ *delay_den = info_ptr->next_frame_delay_den;
++ *dispose_op = info_ptr->next_frame_dispose_op;
++ *blend_op = info_ptr->next_frame_blend_op;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_width()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_width);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_height()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_height);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_x_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_x_offset);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_y_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_y_offset);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_num()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_num);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_den()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_den);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_dispose_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_dispose_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_blend_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_blend_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr != NULL)
++ return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
++
++ PNG_UNUSED(info_ptr)
++
++ return 0;
++}
++#endif /* PNG_APNG_SUPPORTED */
+ #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
+diff -Naru libpng-1.6.14.org/pnginfo.h libpng-1.6.14/pnginfo.h
+--- libpng-1.6.14.org/pnginfo.h 2014-10-23 23:57:22.657674952 +0900
++++ libpng-1.6.14/pnginfo.h 2014-10-23 23:57:22.730677491 +0900
+@@ -256,5 +256,18 @@
+ png_bytepp row_pointers; /* the image bits */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames; /* including default image */
++ png_uint_32 num_plays;
++ png_uint_32 next_frame_width;
++ png_uint_32 next_frame_height;
++ png_uint_32 next_frame_x_offset;
++ png_uint_32 next_frame_y_offset;
++ png_uint_16 next_frame_delay_num;
++ png_uint_16 next_frame_delay_den;
++ png_byte next_frame_dispose_op;
++ png_byte next_frame_blend_op;
++#endif
++
+ };
+ #endif /* PNGINFO_H */
+diff -Naru libpng-1.6.14.org/pngpread.c libpng-1.6.14/pngpread.c
+--- libpng-1.6.14.org/pngpread.c 2014-10-23 23:57:22.657674952 +0900
++++ libpng-1.6.14/pngpread.c 2014-10-23 23:57:22.730677491 +0900
+@@ -219,6 +219,109 @@
+
+ chunk_name = png_ptr->chunk_name;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0 &&
++ png_ptr->num_frames_read < info_ptr->num_frames)
++ {
++ if (chunk_name == png_IDAT)
++ {
++ /* Discard trailing IDATs for the first frame */
++ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "out of place IDAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_push_crc_skip(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ else if (chunk_name == png_fdAT)
++ {
++ if (png_ptr->buffer_size < 4)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ensure_sequence_number(png_ptr, 4);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ {
++ /* Discard trailing fdATs for frames other than the first */
++ if (png_ptr->num_frames_read < 2)
++ png_error(png_ptr, "out of place fdAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_push_crc_skip(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ else
++ {
++ /* frame data follows */
++ png_ptr->idat_size = png_ptr->push_length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++ png_ptr->process_mode = PNG_READ_IDAT_MODE;
++
++ return;
++ }
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_read_reset(png_ptr);
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ png_error(png_ptr, "missing required fcTL chunk");
++
++ png_read_reinit(png_ptr, info_ptr);
++ png_progressive_read_reset(png_ptr);
++
++ if (png_ptr->frame_info_fn != NULL)
++ (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++
++ return;
++ }
++
++ else
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_push_crc_skip(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ return;
++ }
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ if (chunk_name == png_IDAT)
+ {
+ if (png_ptr->mode & PNG_AFTER_IDAT)
+@@ -283,6 +386,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+@@ -428,6 +534,30 @@
+ png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ #endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ else if (chunk_name == png_acTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++#endif /* PNG_READ_APNG_SUPPORTED */
+
+ else
+ {
+@@ -621,7 +751,11 @@
+ png_byte chunk_tag[4];
+
+ /* TODO: this code can be commoned up with the same code in push_read */
++#ifdef PNG_READ_APNG_SUPPORTED
++ PNG_PUSH_SAVE_BUFFER_IF_LT(12)
++#else
+ PNG_PUSH_SAVE_BUFFER_IF_LT(8)
++#endif
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
+ png_reset_crc(png_ptr);
+@@ -629,17 +763,64 @@
+ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
++ {
++ if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
++ {
++ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++ return;
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipping (ignoring) a chunk between "
++ "APNG chunks");
++ png_crc_finish(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ }
++ else
++#endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
++#else
+ if (png_ptr->chunk_name != png_IDAT)
++#endif
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+
+ if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
+ png_error(png_ptr, "Not enough compressed data");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++#endif
++
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0)
++ {
++ png_ensure_sequence_number(png_ptr, 4);
++ png_ptr->idat_size -= 4;
++ }
++#endif
+ }
+
+ if (png_ptr->idat_size && png_ptr->save_buffer_size)
+@@ -712,6 +893,15 @@
+ if (!(buffer_length > 0) || buffer == NULL)
+ png_error(png_ptr, "No IDAT data (internal error)");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ /* If the app is not APNG-aware, decode only the first frame */
++ if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
++ {
++ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++ return;
++ }
++#endif
++
+ /* This routine must process all the data it has been given
+ * before returning, calling the row callback as required to
+ * handle the uncompressed results.
+@@ -1154,6 +1344,18 @@
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+ }
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_set_progressive_frame_fn(png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn)
++{
++ png_ptr->frame_info_fn = frame_info_fn;
++ png_ptr->frame_end_fn = frame_end_fn;
++ png_ptr->apng_flags |= PNG_APNG_APP;
++}
++#endif
++
+ png_voidp PNGAPI
+ png_get_progressive_ptr(png_const_structrp png_ptr)
+ {
+diff -Naru libpng-1.6.14.org/pngpriv.h libpng-1.6.14/pngpriv.h
+--- libpng-1.6.14.org/pngpriv.h 2014-10-23 23:57:22.658674987 +0900
++++ libpng-1.6.14/pngpriv.h 2014-10-23 23:57:22.731677525 +0900
+@@ -555,6 +555,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+ /* 0x4000 (unused) */
+ #define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_HAVE_acTL 0x10000
++#define PNG_HAVE_fcTL 0x20000
++#endif
+
+ /* Flags for the transformations the PNG library does on the image data */
+ #define PNG_BGR 0x0001
+@@ -776,6 +780,16 @@
+ #define png_tRNS PNG_U32(116, 82, 78, 83)
+ #define png_zTXt PNG_U32(122, 84, 88, 116)
+
++#ifdef PNG_APNG_SUPPORTED
++#define png_acTL PNG_U32( 97, 99, 84, 76)
++#define png_fcTL PNG_U32(102, 99, 84, 76)
++#define png_fdAT PNG_U32(102, 100, 65, 84)
++
++/* For png_struct.apng_flags: */
++#define PNG_FIRST_FRAME_HIDDEN 0x0001
++#define PNG_APNG_APP 0x0002
++#endif
++
+ /* The following will work on (signed char*) strings, whereas the get_uint_32
+ * macro will fail on top-bit-set values because of the sign extension.
+ */
+@@ -1476,6 +1490,47 @@
+ */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den,
++ png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
++ png_infop info_ptr),PNG_EMPTY);
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den,
++ png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
++ png_const_bytep data, png_size_t length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* Added at libpng version 1.4.0 */
+ #ifdef PNG_COLORSPACE_SUPPORTED
+ /* These internal functions are for maintaining the colorspace structure within
+diff -Naru libpng-1.6.14.org/pngread.c libpng-1.6.14/pngread.c
+--- libpng-1.6.14.org/pngread.c 2014-10-23 23:57:22.659675022 +0900
++++ libpng-1.6.14/pngread.c 2014-10-23 23:57:22.732677560 +0900
+@@ -158,6 +158,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = length;
+ break;
+ }
+@@ -247,6 +250,17 @@
+ png_handle_iTXt(png_ptr, info_ptr, length);
+ #endif
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ else if (chunk_name == png_acTL)
++ png_handle_acTL(png_ptr, info_ptr, length);
++
++ else if (chunk_name == png_fcTL)
++ png_handle_fcTL(png_ptr, info_ptr, length);
++
++ else if (chunk_name == png_fdAT)
++ png_handle_fdAT(png_ptr, info_ptr, length);
++#endif
++
+ else
+ png_handle_unknown(png_ptr, info_ptr, length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
+@@ -254,6 +268,72 @@
+ }
+ #endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
++{
++ png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
++
++ png_debug(0, "Reading frame head");
++
++ if (!(png_ptr->mode & PNG_HAVE_acTL))
++ png_error(png_ptr, "attempt to png_read_frame_head() but "
++ "no acTL present");
++
++ /* do nothing for the main IDAT */
++ if (png_ptr->num_frames_read == 0)
++ return;
++
++ png_read_reset(png_ptr);
++ png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ have_chunk_after_DAT = 0;
++ for (;;)
++ {
++ png_uint_32 length = png_read_chunk_header(png_ptr);
++
++ if (png_ptr->chunk_name == png_IDAT)
++ {
++ /* discard trailing IDATs for the first frame */
++ if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
++ png_crc_finish(png_ptr, length);
++ }
++
++ else if (png_ptr->chunk_name == png_fcTL)
++ {
++ png_handle_fcTL(png_ptr, info_ptr, length);
++ have_chunk_after_DAT = 1;
++ }
++
++ else if (png_ptr->chunk_name == png_fdAT)
++ {
++ png_ensure_sequence_number(png_ptr, length);
++
++ /* discard trailing fdATs for frames other than the first */
++ if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
++ png_crc_finish(png_ptr, length - 4);
++ else if(png_ptr->mode & PNG_HAVE_fcTL)
++ {
++ png_ptr->idat_size = length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++
++ break;
++ }
++ else
++ png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
++ }
++ else
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_crc_finish(png_ptr, length);
++ }
++ }
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ /* Optional call to update the users info_ptr structure */
+ void PNGAPI
+ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
+diff -Naru libpng-1.6.14.org/pngrutil.c libpng-1.6.14/pngrutil.c
+--- libpng-1.6.14.org/pngrutil.c 2014-10-23 23:57:22.660675057 +0900
++++ libpng-1.6.14/pngrutil.c 2014-10-23 23:57:22.735677664 +0900
+@@ -817,6 +817,11 @@
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ /* Set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+@@ -2697,6 +2702,179 @@
+ }
+ #endif
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void /* PRIVATE */
++png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++ png_byte data[8];
++ png_uint_32 num_frames;
++ png_uint_32 num_plays;
++ png_uint_32 didSet;
++
++ png_debug(1, "in png_handle_acTL");
++
++ if (!(png_ptr->mode & PNG_HAVE_IHDR))
++ {
++ png_error(png_ptr, "Missing IHDR before acTL");
++ }
++ else if (png_ptr->mode & PNG_HAVE_IDAT)
++ {
++ png_warning(png_ptr, "Invalid acTL after IDAT skipped");
++ png_crc_finish(png_ptr, length);
++ return;
++ }
++ else if (png_ptr->mode & PNG_HAVE_acTL)
++ {
++ png_warning(png_ptr, "Duplicate acTL skipped");
++ png_crc_finish(png_ptr, length);
++ return;
++ }
++ else if (length != 8)
++ {
++ png_warning(png_ptr, "acTL with invalid length skipped");
++ png_crc_finish(png_ptr, length);
++ return;
++ }
++
++ png_crc_read(png_ptr, data, 8);
++ png_crc_finish(png_ptr, 0);
++
++ num_frames = png_get_uint_31(png_ptr, data);
++ num_plays = png_get_uint_31(png_ptr, data + 4);
++
++ /* the set function will do error checking on num_frames */
++ didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
++ if(didSet)
++ png_ptr->mode |= PNG_HAVE_acTL;
++}
++
++void /* PRIVATE */
++png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++ png_byte data[22];
++ png_uint_32 width;
++ png_uint_32 height;
++ png_uint_32 x_offset;
++ png_uint_32 y_offset;
++ png_uint_16 delay_num;
++ png_uint_16 delay_den;
++ png_byte dispose_op;
++ png_byte blend_op;
++
++ png_debug(1, "in png_handle_fcTL");
++
++ png_ensure_sequence_number(png_ptr, length);
++
++ if (!(png_ptr->mode & PNG_HAVE_IHDR))
++ {
++ png_error(png_ptr, "Missing IHDR before fcTL");
++ }
++ else if (png_ptr->mode & PNG_HAVE_IDAT)
++ {
++ /* for any frames other then the first this message may be misleading,
++ * but correct. PNG_HAVE_IDAT is unset before the frame head is read
++ * i can't think of a better message */
++ png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
++ png_crc_finish(png_ptr, length-4);
++ return;
++ }
++ else if (png_ptr->mode & PNG_HAVE_fcTL)
++ {
++ png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
++ png_crc_finish(png_ptr, length-4);
++ return;
++ }
++ else if (length != 26)
++ {
++ png_warning(png_ptr, "fcTL with invalid length skipped");
++ png_crc_finish(png_ptr, length-4);
++ return;
++ }
++
++ png_crc_read(png_ptr, data, 22);
++ png_crc_finish(png_ptr, 0);
++
++ width = png_get_uint_31(png_ptr, data);
++ height = png_get_uint_31(png_ptr, data + 4);
++ x_offset = png_get_uint_31(png_ptr, data + 8);
++ y_offset = png_get_uint_31(png_ptr, data + 12);
++ delay_num = png_get_uint_16(data + 16);
++ delay_den = png_get_uint_16(data + 18);
++ dispose_op = data[20];
++ blend_op = data[21];
++
++ if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
++ {
++ png_warning(png_ptr, "fcTL for the first frame must have zero offset");
++ return;
++ }
++
++ if (info_ptr != NULL)
++ {
++ if (png_ptr->num_frames_read == 0 &&
++ (width != info_ptr->width || height != info_ptr->height))
++ {
++ png_warning(png_ptr, "size in first frame's fcTL must match "
++ "the size in IHDR");
++ return;
++ }
++
++ /* The set function will do more error checking */
++ png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
++ x_offset, y_offset, delay_num, delay_den,
++ dispose_op, blend_op);
++
++ png_read_reinit(png_ptr, info_ptr);
++
++ png_ptr->mode |= PNG_HAVE_fcTL;
++ }
++}
++
++void /* PRIVATE */
++png_have_info(png_structp png_ptr, png_infop info_ptr)
++{
++ if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
++ {
++ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++ info_ptr->num_frames++;
++ }
++}
++
++void /* PRIVATE */
++png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++ png_ensure_sequence_number(png_ptr, length);
++
++ /* This function is only called from png_read_end(), png_read_info(),
++ * and png_push_read_chunk() which means that:
++ * - the user doesn't want to read this frame
++ * - or this is an out-of-place fdAT
++ * in either case it is safe to ignore the chunk with a warning */
++ png_warning(png_ptr, "ignoring fdAT chunk");
++ png_crc_finish(png_ptr, length - 4);
++ PNG_UNUSED(info_ptr)
++}
++
++void /* PRIVATE */
++png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
++{
++ png_byte data[4];
++ png_uint_32 sequence_number;
++
++ if (length < 4)
++ png_error(png_ptr, "invalid fcTL or fdAT chunk found");
++
++ png_crc_read(png_ptr, data, 4);
++ sequence_number = png_get_uint_31(png_ptr, data);
++
++ if (sequence_number != png_ptr->next_seq_num)
++ png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
++ "number found");
++
++ png_ptr->next_seq_num++;
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+ /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
+ static int
+@@ -3953,7 +4131,38 @@
+ {
+ uInt avail_in;
+ png_bytep buffer;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 bytes_to_skip = 0;
++
++ while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
++ {
++ png_crc_finish(png_ptr, bytes_to_skip);
++ bytes_to_skip = 0;
+
++ png_ptr->idat_size = png_read_chunk_header(png_ptr);
++ if (png_ptr->num_frames_read == 0)
++ {
++ if (png_ptr->chunk_name != png_IDAT)
++ png_error(png_ptr, "Not enough image data");
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->chunk_name != png_fdAT)
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ bytes_to_skip = png_ptr->idat_size;
++ continue;
++ }
++
++ png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
++
++ png_ptr->idat_size -= 4;
++ }
++ }
++#else
+ while (png_ptr->idat_size == 0)
+ {
+ png_crc_finish(png_ptr, 0);
+@@ -3965,7 +4174,7 @@
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
+ }
+-
++#endif /* PNG_READ_APNG_SUPPORTED */
+ avail_in = png_ptr->IDAT_read_size;
+
+ if (avail_in > png_ptr->idat_size)
+@@ -4028,6 +4237,9 @@
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->num_frames_read++;
++#endif
+
+ if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+ png_chunk_benign_error(png_ptr, "Extra compressed data");
+@@ -4465,4 +