APNG. bug 257197. patch by Andrew Smith <asmith15@learn.senecac.on.ca>. r=biesi sr=pavlov
This commit is contained in:
Родитель
a5665d68bc
Коммит
13c8e24bf8
|
@ -4004,8 +4004,11 @@ fi
|
|||
if test -z "$PNG_DIR" -o "$PNG_DIR" = no; then
|
||||
SYSTEM_PNG=
|
||||
else
|
||||
_SAVE_PNG_LIBS=$PNG_LIBS
|
||||
AC_CHECK_LIB(png, png_get_valid, [SYSTEM_PNG=1 PNG_LIBS="-lpng $PNG_LIBS"],
|
||||
SYSTEM_PNG=, $PNG_LIBS)
|
||||
AC_CHECK_LIB(png, png_get_acTl, ,
|
||||
[SYSTEM_PNG= PNG_LIBS=$_SAVE_PNG_LIBS], $_SAVE_PNG_LIBS)
|
||||
fi
|
||||
if test "$SYSTEM_PNG" = 1; then
|
||||
LIBS="$PNG_LIBS $LIBS"
|
||||
|
|
|
@ -51,6 +51,9 @@ PNG_tEXt;
|
|||
PNG_tIME;
|
||||
PNG_tRNS;
|
||||
PNG_zTXt;
|
||||
PNG_acTl;
|
||||
PNG_fcTl;
|
||||
PNG_fdAt;
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
|
||||
|
|
|
@ -900,6 +900,18 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
|
|||
png_fixed_point int_y_blue;
|
||||
#endif
|
||||
|
||||
#if defined(PNG_APNG_SUPPORTED)
|
||||
png_uint_32 num_frames;
|
||||
png_uint_32 num_iterations;
|
||||
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_render_op;
|
||||
#endif
|
||||
|
||||
} png_info;
|
||||
|
||||
typedef png_info FAR * png_infop;
|
||||
|
@ -1001,6 +1013,8 @@ typedef png_info FAR * FAR * png_infopp;
|
|||
#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
|
||||
#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
|
||||
#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */
|
||||
#define PNG_INFO_acTl 0x10000L
|
||||
#define PNG_INFO_fcTl 0x20000L
|
||||
|
||||
/* This is used for the transformation routines, as some of them
|
||||
* change these values for the row. It also should enable using
|
||||
|
@ -1041,6 +1055,10 @@ typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop))
|
|||
typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop));
|
||||
typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
|
||||
png_uint_32, int));
|
||||
#if defined(PNG_APNG_SUPPORTED)
|
||||
typedef void (PNGAPI *png_progressive_frame_ptr) PNGARG((png_structp,
|
||||
png_uint_32));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
|
||||
|
@ -1367,8 +1385,39 @@ struct png_struct_def
|
|||
png_uint_32 user_height_max;
|
||||
#endif
|
||||
|
||||
#if defined(PNG_APNG_SUPPORTED)
|
||||
png_uint_32 apng_flags;
|
||||
png_uint_32 IHDR_crc; /* read or written */
|
||||
png_uint_32 PLTE_crc; /* read or written */
|
||||
png_uint_32 next_seq_num; /* next fcTl/fdAt chunk sequence number */
|
||||
png_uint_32 first_frame_width;
|
||||
png_uint_32 first_frame_height;
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
png_uint_32 num_frames_read; /* incremented after all image data of */
|
||||
/* a frame is read */
|
||||
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
|
||||
png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
|
||||
png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
png_uint_32 num_frames_to_write; /* copy of info_ptr->num_frames */
|
||||
png_uint_32 num_frames_written;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/* For png_struct.apng_flags: */
|
||||
#define PNG_FIRST_FRAME_HIDDEN 0x0001
|
||||
|
||||
/* dispose_op flags from render_op inside fcTl */
|
||||
#define PNG_RENDER_OP_DISPOSE_MASK 0x07
|
||||
#define PNG_RENDER_OP_DISPOSE_NONE 0x01
|
||||
#define PNG_RENDER_OP_DISPOSE_BACKGROUND 0x02
|
||||
#define PNG_RENDER_OP_DISPOSE_PREVIOUS 0x04
|
||||
|
||||
/* This triggers a compiler error in png.c, if png.c and png.h
|
||||
* do not agree upon the version number.
|
||||
|
@ -1688,6 +1737,18 @@ extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
|
|||
extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
|
||||
png_bytepp image));
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
extern PNG_EXPORT (void,png_write_frame_head) PNGARG((png_structp png_ptr,
|
||||
png_infop png_info, 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 render_op,
|
||||
png_byte first_frame_hidden));
|
||||
|
||||
extern PNG_EXPORT (void,png_write_frame_tail) PNGARG((png_structp png_ptr,
|
||||
png_infop png_info));
|
||||
#endif
|
||||
|
||||
/* writes the end of the PNG file. */
|
||||
extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr));
|
||||
|
@ -1936,6 +1997,11 @@ extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
|
|||
png_voidp progressive_ptr,
|
||||
png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
|
||||
png_progressive_end_ptr end_fn));
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
extern PNG_EXPORT(void,png_set_progressive_frame_fn) PNGARG((png_structp png_ptr,
|
||||
png_progressive_frame_ptr frame_info_fn,
|
||||
png_progressive_frame_ptr frame_end_fn));
|
||||
#endif
|
||||
|
||||
/* returns the user pointer associated with the push read functions */
|
||||
extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
|
||||
|
@ -2364,6 +2430,53 @@ extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr,
|
|||
#endif
|
||||
#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */
|
||||
|
||||
#if defined(PNG_APNG_SUPPORTED)
|
||||
extern PNG_EXPORT(png_uint_32,png_get_acTl) PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_iterations));
|
||||
extern PNG_EXPORT(png_uint_32,png_set_acTl) PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_iterations));
|
||||
extern PNG_EXPORT(png_uint_32,png_get_num_frames) PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_uint_32,png_get_num_iterations)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
|
||||
extern PNG_EXPORT(png_uint_32,png_get_next_frame_fcTl)
|
||||
PNGARG((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 *render_op));
|
||||
extern PNG_EXPORT(png_uint_32,png_set_next_frame_fcTl)
|
||||
PNGARG((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 render_op));
|
||||
extern PNG_EXPORT(void,png_ensure_fcTl_is_valid)
|
||||
PNGARG((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 render_op));
|
||||
extern PNG_EXPORT(png_uint_32,png_get_next_frame_width)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_uint_32,png_get_next_frame_height)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_uint_32,png_get_next_frame_x_offset)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_uint_32,png_get_next_frame_y_offset)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_num)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_den)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_byte,png_get_next_frame_render_op)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
extern PNG_EXPORT(png_byte,png_first_frame_is_hidden)
|
||||
PNGARG((png_structp png_ptr, png_infop info_ptr));
|
||||
#endif /* PNG_APNG_SUPPORTED */
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
extern PNG_EXPORT(void,png_read_frame_head) PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr));
|
||||
#endif
|
||||
|
||||
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
|
||||
/* provide a list of chunks and how they are to be handled, if the built-in
|
||||
handling or default unknown chunk handling is not desired. Any chunks not
|
||||
|
@ -2667,6 +2780,8 @@ extern PNG_EXPORT(void,png_save_uint_16)
|
|||
#define PNG_BACKGROUND_IS_GRAY 0x800
|
||||
#define PNG_HAVE_PNG_SIGNATURE 0x1000
|
||||
#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
|
||||
#define PNG_HAVE_acTl 0x4000
|
||||
#define PNG_HAVE_fcTl 0x8000L
|
||||
|
||||
/* flags for the transformations the PNG library does on the image data */
|
||||
#define PNG_BGR 0x0001
|
||||
|
@ -2810,6 +2925,9 @@ extern PNG_EXPORT(void,png_save_uint_16)
|
|||
#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'}
|
||||
#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'}
|
||||
#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'}
|
||||
#define PNG_acTl const png_byte png_acTl[5] = { 97, 99, 84, 108, '\0'}
|
||||
#define PNG_fcTl const png_byte png_fcTl[5] = {102, 99, 84, 108, '\0'}
|
||||
#define PNG_fdAt const png_byte png_fdAt[5] = {102, 100, 65, 116, '\0'}
|
||||
|
||||
#ifdef PNG_USE_GLOBAL_ARRAYS
|
||||
PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5];
|
||||
|
@ -2833,6 +2951,9 @@ PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5];
|
|||
PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5];
|
||||
PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5];
|
||||
PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5];
|
||||
PNG_EXPORT_VAR (const png_byte FARDATA) png_acTl[5];
|
||||
PNG_EXPORT_VAR (const png_byte FARDATA) png_fcTl[5];
|
||||
PNG_EXPORT_VAR (const png_byte FARDATA) png_fdAt[5];
|
||||
#endif /* PNG_USE_GLOBAL_ARRAYS */
|
||||
|
||||
#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
|
||||
|
@ -3107,6 +3228,16 @@ PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr,
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
PNG_EXTERN void png_write_acTl PNGARG((png_structp png_ptr,
|
||||
png_uint_32 num_frames, png_uint_32 num_iterations));
|
||||
|
||||
PNG_EXTERN void png_write_fcTl PNGARG((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 render_op));
|
||||
#endif
|
||||
|
||||
/* Called when finished processing a row of data */
|
||||
PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
|
||||
|
||||
|
@ -3158,6 +3289,20 @@ PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
|
|||
PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr));
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
/* private, reset some things to become ready for reading next frame */
|
||||
PNG_EXTERN void png_read_reset PNGARG((png_structp png_ptr));
|
||||
PNG_EXTERN void png_read_reinit PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr));
|
||||
PNG_EXTERN void png_progressive_read_reset PNGARG((png_structp png_ptr));
|
||||
#endif
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
/* private, reset some things to become ready for writing next frame */
|
||||
PNG_EXTERN void png_write_reset PNGARG((png_structp png_ptr));
|
||||
PNG_EXTERN void png_write_reinit PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr, png_uint_32 width, png_uint_32 height));
|
||||
#endif
|
||||
|
||||
/* these are the functions that do the transformations */
|
||||
#if defined(PNG_READ_FILLER_SUPPORTED)
|
||||
PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
|
||||
|
@ -3373,6 +3518,17 @@ PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
|
|||
png_uint_32 length));
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
PNG_EXTERN void png_handle_acTl PNGARG((png_structp png_ptr, png_infop info_ptr,
|
||||
png_uint_32 length));
|
||||
PNG_EXTERN void png_handle_fcTl PNGARG((png_structp png_ptr, png_infop info_ptr,
|
||||
png_uint_32 length));
|
||||
PNG_EXTERN void png_handle_fdAt PNGARG((png_structp png_ptr, png_infop info_ptr,
|
||||
png_uint_32 length));
|
||||
PNG_EXTERN void png_ensure_sequence_number PNGARG((png_structp png_ptr,
|
||||
png_uint_32 length));
|
||||
#endif
|
||||
|
||||
PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
|
||||
png_infop info_ptr, png_uint_32 length));
|
||||
|
||||
|
|
|
@ -896,6 +896,10 @@
|
|||
# define PNG_READ_zTXt_SUPPORTED
|
||||
# define PNG_zTXt_SUPPORTED
|
||||
#endif
|
||||
#ifndef PNG_NO_READ_APNG
|
||||
# define PNG_READ_APNG_SUPPORTED
|
||||
# define PNG_APNG_SUPPORTED
|
||||
#endif
|
||||
#ifndef PNG_NO_READ_UNKNOWN_CHUNKS
|
||||
# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
||||
# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
|
||||
|
@ -1038,6 +1042,12 @@
|
|||
# define PNG_zTXt_SUPPORTED
|
||||
# endif
|
||||
#endif
|
||||
#ifndef PNG_NO_WRITE_APNG
|
||||
# define PNG_WRITE_APNG_SUPPORTED
|
||||
# ifndef PNG_APNG_SUPPORTED
|
||||
# define PNG_APNG_SUPPORTED
|
||||
# endif
|
||||
#endif
|
||||
#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS
|
||||
# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
|
||||
|
|
|
@ -794,6 +794,157 @@ png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(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_iterations)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function\n", "acTl");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->valid & PNG_INFO_acTl) &&
|
||||
num_frames != NULL && num_iterations != NULL)
|
||||
{
|
||||
*num_frames = info_ptr->num_frames;
|
||||
*num_iterations = info_ptr->num_iterations;
|
||||
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()\n");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL)
|
||||
return (info_ptr->num_frames);
|
||||
return (0);
|
||||
}
|
||||
|
||||
png_uint_32 PNGAPI
|
||||
png_get_num_iterations(png_structp png_ptr, png_infop info_ptr)
|
||||
{
|
||||
png_debug(1, "in png_get_num_iterations()\n");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL)
|
||||
return (info_ptr->num_iterations);
|
||||
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 *render_op)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function\n", "fcTl");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->valid & PNG_INFO_fcTl) &&
|
||||
width != NULL && height != NULL &&
|
||||
x_offset != NULL && x_offset != NULL &&
|
||||
delay_num != NULL && delay_den != NULL && render_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;
|
||||
*render_op = info_ptr->next_frame_render_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()\n");
|
||||
|
||||
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()\n");
|
||||
|
||||
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()\n");
|
||||
|
||||
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()\n");
|
||||
|
||||
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()\n");
|
||||
|
||||
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()\n");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL)
|
||||
return (info_ptr->next_frame_delay_den);
|
||||
return (0);
|
||||
}
|
||||
|
||||
png_byte PNGAPI
|
||||
png_get_next_frame_render_op(png_structp png_ptr, png_infop info_ptr)
|
||||
{
|
||||
png_debug(1, "in png_get_next_frame_render_op()\n");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL)
|
||||
return (info_ptr->next_frame_render_op);
|
||||
return (0);
|
||||
}
|
||||
|
||||
png_byte PNGAPI
|
||||
png_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
|
||||
{
|
||||
png_debug(1, "in png_first_frame_is_hidden()\n");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
info_ptr->valid & PNG_INFO_acTl &&
|
||||
!(info_ptr->valid & PNG_INFO_fcTl))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* PNG_APNG_SUPPORTED */
|
||||
|
||||
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
|
||||
png_uint_32 PNGAPI
|
||||
png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr,
|
||||
|
|
|
@ -190,6 +190,11 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
|
|||
#if defined(PNG_READ_zTXt_SUPPORTED)
|
||||
PNG_zTXt;
|
||||
#endif
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
PNG_acTl;
|
||||
PNG_fcTl;
|
||||
PNG_fdAt;
|
||||
#endif
|
||||
#endif /* PNG_USE_LOCAL_ARRAYS */
|
||||
/* First we make sure we have enough data for the 4 byte chunk name
|
||||
* and the 4 byte chunk length before proceeding with decoding the
|
||||
|
@ -213,7 +218,104 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
|
|||
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
|
||||
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
|
||||
}
|
||||
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
if (png_ptr->num_frames_read > 0 &&
|
||||
png_ptr->num_frames_read < info_ptr->num_frames)
|
||||
{
|
||||
if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
|
||||
{
|
||||
/* 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 (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
|
||||
{
|
||||
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(!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
|
||||
{
|
||||
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 (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
|
||||
if(png_ptr->mode & PNG_AFTER_IDAT)
|
||||
png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
|
||||
|
@ -488,6 +590,35 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
|
|||
png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
#endif
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_acTl, 4))
|
||||
{
|
||||
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 (!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
|
||||
{
|
||||
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
|
||||
{
|
||||
png_push_save_buffer(png_ptr);
|
||||
return;
|
||||
}
|
||||
png_handle_fdAt(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
#endif /* PNG_READ_APNG_SUPPORTED */
|
||||
else
|
||||
{
|
||||
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
|
||||
|
@ -658,12 +789,16 @@ png_push_read_IDAT(png_structp png_ptr)
|
|||
{
|
||||
#ifdef PNG_USE_LOCAL_ARRAYS
|
||||
PNG_IDAT;
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
PNG_fdAt;
|
||||
PNG_IEND;
|
||||
#endif
|
||||
#endif
|
||||
if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
|
||||
{
|
||||
png_byte chunk_length[4];
|
||||
|
||||
if (png_ptr->buffer_size < 8)
|
||||
if (png_ptr->buffer_size < 12)
|
||||
{
|
||||
png_push_save_buffer(png_ptr);
|
||||
return;
|
||||
|
@ -675,15 +810,59 @@ png_push_read_IDAT(png_structp png_ptr)
|
|||
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
|
||||
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
|
||||
|
||||
if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_fdAt, 4)
|
||||
&& png_ptr->num_frames_read > 0)
|
||||
{
|
||||
if (png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)
|
||||
{
|
||||
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_memcmp(png_ptr->chunk_name, png_IEND, 4))
|
||||
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
|
||||
if ( png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)
|
||||
&& (png_ptr->num_frames_read == 0) )
|
||||
{
|
||||
png_ptr->process_mode = PNG_READ_CHUNK_MODE;
|
||||
if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
|
||||
png_error(png_ptr, "Not enough compressed data");
|
||||
#if defined(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;
|
||||
|
||||
#if defined(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)
|
||||
{
|
||||
|
@ -1570,6 +1749,17 @@ png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
|
|||
png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
|
||||
}
|
||||
|
||||
#if defined(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;
|
||||
}
|
||||
#endif
|
||||
|
||||
png_voidp PNGAPI
|
||||
png_get_progressive_ptr(png_structp png_ptr)
|
||||
{
|
||||
|
|
|
@ -397,6 +397,11 @@ png_read_info(png_structp png_ptr, png_infop info_ptr)
|
|||
#if defined(PNG_READ_zTXt_SUPPORTED)
|
||||
PNG_zTXt;
|
||||
#endif
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
PNG_acTl;
|
||||
PNG_fcTl;
|
||||
PNG_fdAt;
|
||||
#endif
|
||||
#endif /* PNG_USE_LOCAL_ARRAYS */
|
||||
png_byte chunk_length[4];
|
||||
png_uint_32 length;
|
||||
|
@ -521,6 +526,14 @@ png_read_info(png_structp png_ptr, png_infop info_ptr)
|
|||
#if defined(PNG_READ_iTXt_SUPPORTED)
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
|
||||
png_handle_iTXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_acTl, 4))
|
||||
png_handle_acTl(png_ptr, info_ptr, length);
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
|
||||
png_handle_fcTl(png_ptr, info_ptr, length);
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
|
||||
png_handle_fdAt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
else
|
||||
png_handle_unknown(png_ptr, info_ptr, length);
|
||||
|
@ -528,6 +541,83 @@ png_read_info(png_structp png_ptr, png_infop info_ptr)
|
|||
}
|
||||
#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
|
||||
|
||||
#if defined(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\n");
|
||||
|
||||
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_crc_finish(png_ptr, 0); /* CRC from last IDAT or fdAt chunk */
|
||||
|
||||
png_read_reset(png_ptr);
|
||||
png_ptr->mode &= ~PNG_HAVE_fcTl;
|
||||
|
||||
have_chunk_after_DAT = 0;
|
||||
for (;;)
|
||||
{
|
||||
#ifdef PNG_USE_LOCAL_ARRAYS
|
||||
PNG_IDAT;
|
||||
PNG_fdAt;
|
||||
PNG_fcTl;
|
||||
#endif
|
||||
png_byte chunk_length[4];
|
||||
png_uint_32 length;
|
||||
|
||||
png_read_data(png_ptr, chunk_length, 4);
|
||||
length = png_get_uint_31(png_ptr, chunk_length);
|
||||
|
||||
png_reset_crc(png_ptr);
|
||||
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
|
||||
|
||||
if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
|
||||
{
|
||||
/* 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_memcmp(png_ptr->chunk_name, png_fcTl, 4))
|
||||
{
|
||||
png_handle_fcTl(png_ptr, info_ptr, length);
|
||||
have_chunk_after_DAT = 1;
|
||||
}
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
|
||||
{
|
||||
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_structp png_ptr, png_infop info_ptr)
|
||||
|
@ -562,6 +652,10 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
|
|||
{
|
||||
#ifdef PNG_USE_LOCAL_ARRAYS
|
||||
PNG_IDAT;
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
PNG_fdAt;
|
||||
PNG_IEND;
|
||||
#endif
|
||||
const int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
|
||||
const int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
|
||||
#endif
|
||||
|
@ -689,19 +783,46 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
|
|||
{
|
||||
if (!(png_ptr->zstream.avail_in))
|
||||
{
|
||||
while (!png_ptr->idat_size)
|
||||
png_uint_32 bytes_to_skip = 0;
|
||||
|
||||
while (!png_ptr->idat_size || bytes_to_skip != 0)
|
||||
{
|
||||
png_byte chunk_length[4];
|
||||
|
||||
png_crc_finish(png_ptr, 0);
|
||||
|
||||
png_crc_finish(png_ptr, bytes_to_skip);
|
||||
bytes_to_skip = 0;
|
||||
|
||||
png_read_data(png_ptr, chunk_length, 4);
|
||||
png_ptr->idat_size = png_get_uint_31(png_ptr,chunk_length);
|
||||
|
||||
|
||||
png_reset_crc(png_ptr);
|
||||
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
|
||||
if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
|
||||
png_error(png_ptr, "Not enough image data");
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
if (png_ptr->num_frames_read == 0)
|
||||
{
|
||||
#endif
|
||||
if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
|
||||
png_error(png_ptr, "Not enough image data");
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
|
||||
png_error(png_ptr, "Not enough image data");
|
||||
if (png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
|
||||
{
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
|
||||
png_ptr->zstream.next_in = png_ptr->zbuf;
|
||||
|
@ -719,6 +840,9 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
|
|||
png_error(png_ptr, "Extra compressed data");
|
||||
png_ptr->mode |= PNG_AFTER_IDAT;
|
||||
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
png_ptr->num_frames_read++;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (ret != Z_OK)
|
||||
|
@ -970,6 +1094,11 @@ png_read_end(png_structp png_ptr, png_infop info_ptr)
|
|||
#if defined(PNG_READ_zTXt_SUPPORTED)
|
||||
PNG_zTXt;
|
||||
#endif
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
PNG_acTl;
|
||||
PNG_fcTl;
|
||||
PNG_fdAt;
|
||||
#endif
|
||||
#endif /* PNG_USE_LOCAL_ARRAYS */
|
||||
|
||||
png_read_data(png_ptr, chunk_length, 4);
|
||||
|
@ -1075,6 +1204,14 @@ png_read_end(png_structp png_ptr, png_infop info_ptr)
|
|||
#if defined(PNG_READ_iTXt_SUPPORTED)
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
|
||||
png_handle_iTXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_acTl, 4))
|
||||
png_handle_acTl(png_ptr, info_ptr, length);
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
|
||||
png_handle_fcTl(png_ptr, info_ptr, length);
|
||||
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
|
||||
png_handle_fdAt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
else
|
||||
png_handle_unknown(png_ptr, info_ptr, length);
|
||||
|
|
|
@ -363,6 +363,12 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
|
|||
filter_type = buf[11];
|
||||
interlace_type = buf[12];
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
png_ptr->IHDR_crc = png_ptr->crc;
|
||||
png_ptr->first_frame_width = width;
|
||||
png_ptr->first_frame_height = height;
|
||||
#endif
|
||||
|
||||
/* set internal variables */
|
||||
png_ptr->width = width;
|
||||
png_ptr->height = height;
|
||||
|
@ -521,6 +527,19 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
|
|||
|
||||
png_set_PLTE(png_ptr, info_ptr, palette, num);
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
if (png_ptr->mode & PNG_HAVE_acTl)
|
||||
{
|
||||
if (png_ptr->crc != png_ptr->PLTE_crc)
|
||||
png_error(png_ptr, "PLTE checksum does not match that in acTl");
|
||||
}
|
||||
else
|
||||
png_ptr->PLTE_crc = png_ptr->crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_tRNS_SUPPORTED)
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
|
@ -2130,6 +2149,184 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
void /* PRIVATE */
|
||||
png_handle_acTl(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte data[16];
|
||||
png_uint_32 num_frames;
|
||||
png_uint_32 num_iterations;
|
||||
png_uint_32 didSet;
|
||||
png_uint_32 IHDR_crc;
|
||||
png_uint_32 PLTE_crc;
|
||||
|
||||
png_debug(1, "in png_handle_acTl\n");
|
||||
|
||||
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 != 16)
|
||||
{
|
||||
png_warning(png_ptr, "acTl with invalid length skipped");
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, data, 16);
|
||||
png_crc_finish(png_ptr, 0);
|
||||
|
||||
num_frames = png_get_uint_31(png_ptr, data);
|
||||
num_iterations = png_get_uint_31(png_ptr, data + 4);
|
||||
IHDR_crc = png_get_uint_32(data + 8);
|
||||
PLTE_crc = png_get_uint_32(data + 12);
|
||||
|
||||
if (IHDR_crc != png_ptr->IHDR_crc)
|
||||
{
|
||||
png_warning(png_ptr, "acTl with invalid IHDR checksum skipped");
|
||||
return;
|
||||
}
|
||||
if (png_ptr->mode & PNG_HAVE_PLTE)
|
||||
{
|
||||
if (PLTE_crc != png_ptr->PLTE_crc)
|
||||
{
|
||||
png_warning(png_ptr, "acTl with invalid PLTE checksum skipped");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
png_ptr->PLTE_crc = PLTE_crc;
|
||||
|
||||
/* the set function will do error checking on num_frames */
|
||||
didSet = png_set_acTl(png_ptr, info_ptr, num_frames, num_iterations);
|
||||
if(didSet)
|
||||
{
|
||||
png_ptr->mode |= PNG_HAVE_acTl;
|
||||
|
||||
/* if there is an fcTl this flag will be unset in png_handle_fcTl() */
|
||||
if (num_frames > 1)
|
||||
png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
png_handle_fcTl(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte data[21];
|
||||
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 render_op;
|
||||
|
||||
png_debug(1, "in png_handle_fcTl\n");
|
||||
|
||||
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);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
else if (length != 25)
|
||||
{
|
||||
png_warning(png_ptr, "fcTl with invalid length skipped");
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
}
|
||||
|
||||
png_ensure_sequence_number(png_ptr, length);
|
||||
|
||||
png_crc_read(png_ptr, data, 21);
|
||||
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);
|
||||
render_op = data[20];
|
||||
|
||||
if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
|
||||
png_error(png_ptr, "fcTl for the first frame must have zero offset");
|
||||
if (png_ptr->num_frames_read == 0 &&
|
||||
(width != info_ptr->width || height != info_ptr->height))
|
||||
png_error(png_ptr, "size in first frame's fcTl must match "
|
||||
"the size in IHDR");
|
||||
|
||||
/* 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,
|
||||
render_op);
|
||||
|
||||
png_read_reinit(png_ptr, info_ptr);
|
||||
|
||||
png_ptr->mode |= PNG_HAVE_fcTl;
|
||||
|
||||
png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/* This function is called when we haven't found a handler for a
|
||||
chunk. If there isn't a problem with the chunk itself (ie bad
|
||||
chunk name, CRC, or a critical chunk), the chunk is silently ignored
|
||||
|
@ -3094,8 +3291,10 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
|
|||
if (row_bytes > (png_uint_32)65536L)
|
||||
png_error(png_ptr, "This image requires a row greater than 64KB");
|
||||
#endif
|
||||
png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
|
||||
png_ptr->row_buf = png_ptr->big_row_buf+32;
|
||||
if (png_ptr->big_row_buf == NULL)
|
||||
png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
|
||||
if (png_ptr->row_buf == NULL)
|
||||
png_ptr->row_buf = png_ptr->big_row_buf+32;
|
||||
#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)
|
||||
png_ptr->row_buf_size = row_bytes;
|
||||
#endif
|
||||
|
@ -3120,4 +3319,82 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
|
|||
|
||||
png_ptr->flags |= PNG_FLAG_ROW_INIT;
|
||||
}
|
||||
|
||||
#if defined(PNG_READ_APNG_SUPPORTED)
|
||||
/* This function is to be called after the main IDAT set has been read and
|
||||
* before a new IDAT is read. It resets some parts of png_ptr
|
||||
* to make them usable by the read functions again */
|
||||
void /* PRIVATE */
|
||||
png_read_reset(png_structp png_ptr)
|
||||
{
|
||||
png_ptr->mode &= ~PNG_HAVE_IDAT;
|
||||
png_ptr->mode &= ~PNG_AFTER_IDAT;
|
||||
png_ptr->row_number = 0;
|
||||
png_ptr->pass = 0;
|
||||
png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
png_read_reinit(png_structp png_ptr, png_infop info_ptr)
|
||||
{
|
||||
png_ptr->width = info_ptr->next_frame_width;
|
||||
png_ptr->height = info_ptr->next_frame_height;
|
||||
png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
|
||||
}
|
||||
|
||||
/* same as png_read_reset() but for the progressive reader */
|
||||
void /* PRIVATE */
|
||||
png_progressive_read_reset(png_structp png_ptr)
|
||||
{
|
||||
#ifdef PNG_USE_LOCAL_ARRAYS
|
||||
/* start of interlace block */
|
||||
const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
|
||||
|
||||
/* offset to next interlace block */
|
||||
const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
|
||||
|
||||
/* start of interlace block in the y direction */
|
||||
const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
|
||||
|
||||
/* offset to next interlace block in the y direction */
|
||||
const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
|
||||
#endif
|
||||
png_uint_32 row_bytes;
|
||||
|
||||
if (png_ptr->interlaced)
|
||||
{
|
||||
if (!(png_ptr->transformations & PNG_INTERLACE))
|
||||
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
|
||||
png_pass_ystart[0]) / png_pass_yinc[0];
|
||||
else
|
||||
png_ptr->num_rows = png_ptr->height;
|
||||
|
||||
png_ptr->iwidth = (png_ptr->width +
|
||||
png_pass_inc[png_ptr->pass] - 1 -
|
||||
png_pass_start[png_ptr->pass]) /
|
||||
png_pass_inc[png_ptr->pass];
|
||||
|
||||
row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1;
|
||||
|
||||
png_ptr->irowbytes = (png_size_t)row_bytes;
|
||||
if((png_uint_32)png_ptr->irowbytes != row_bytes)
|
||||
png_error(png_ptr, "png_progressive_read_reset(): Rowbytes "
|
||||
"overflow");
|
||||
}
|
||||
else
|
||||
{
|
||||
png_ptr->num_rows = png_ptr->height;
|
||||
png_ptr->iwidth = png_ptr->width;
|
||||
png_ptr->irowbytes = png_ptr->rowbytes + 1;
|
||||
}
|
||||
|
||||
png_ptr->flags &= ~PNG_FLAG_ZLIB_FINISHED;
|
||||
if (inflateReset(&(png_ptr->zstream)) != Z_OK)
|
||||
png_error(png_ptr, "inflateReset failed");
|
||||
png_ptr->zstream.avail_in = 0;
|
||||
png_ptr->zstream.next_in = 0;
|
||||
png_ptr->zstream.next_out = png_ptr->row_buf;
|
||||
png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
|
||||
}
|
||||
#endif /* PNG_READ_APNG_SUPPORTED */
|
||||
#endif /* PNG_READ_SUPPORTED */
|
||||
|
|
|
@ -362,6 +362,11 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
|
|||
info_ptr->rowbytes = (png_size_t)0;
|
||||
else
|
||||
info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,width);
|
||||
|
||||
#if defined(PNG_APNG_SUPPORTED)
|
||||
/* for non-animated png. this may be overritten from an acTl chunk later */
|
||||
info_ptr->num_frames = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(PNG_oFFs_SUPPORTED)
|
||||
|
@ -993,6 +998,121 @@ png_set_sPLT(png_structp png_ptr,
|
|||
}
|
||||
#endif /* PNG_sPLT_SUPPORTED */
|
||||
|
||||
#if defined(PNG_APNG_SUPPORTED)
|
||||
png_uint_32 PNGAPI
|
||||
png_set_acTl(png_structp png_ptr, png_infop info_ptr,
|
||||
png_uint_32 num_frames, png_uint_32 num_iterations)
|
||||
{
|
||||
png_debug1(1, "in %s storage function\n", "acTl");
|
||||
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
{
|
||||
png_warning(png_ptr,
|
||||
"Call to png_set_acTl() with NULL png_ptr "
|
||||
"or info_ptr ignored");
|
||||
return (0);
|
||||
}
|
||||
if(num_frames == 0)
|
||||
{
|
||||
png_warning(png_ptr,
|
||||
"Ignoring attempt to set acTl with num_frames zero");
|
||||
return (0);
|
||||
}
|
||||
if(num_frames > PNG_UINT_31_MAX)
|
||||
{
|
||||
png_warning(png_ptr,
|
||||
"Ignoring attempt to set acTl with num_frames > 2^31-1");
|
||||
return (0);
|
||||
}
|
||||
if(num_iterations > PNG_UINT_31_MAX)
|
||||
{
|
||||
png_warning(png_ptr,
|
||||
"Ignoring attempt to set acTl with num_iterations "
|
||||
"> 2^31-1");
|
||||
return (0);
|
||||
}
|
||||
|
||||
info_ptr->num_frames = num_frames;
|
||||
info_ptr->num_iterations = num_iterations;
|
||||
|
||||
info_ptr->valid |= PNG_INFO_acTl;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* delay_num and delay_den can hold any values including zero */
|
||||
png_uint_32 PNGAPI
|
||||
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 render_op)
|
||||
{
|
||||
png_debug1(1, "in %s storage function\n", "fcTl");
|
||||
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
{
|
||||
png_warning(png_ptr,
|
||||
"Call to png_set_fcTl() with NULL png_ptr or info_ptr "
|
||||
"ignored");
|
||||
return (0);
|
||||
}
|
||||
|
||||
png_ensure_fcTl_is_valid(png_ptr, width, height, x_offset, y_offset,
|
||||
delay_num, delay_den, render_op);
|
||||
|
||||
info_ptr->next_frame_width = width;
|
||||
info_ptr->next_frame_height = height;
|
||||
info_ptr->next_frame_x_offset = x_offset;
|
||||
info_ptr->next_frame_y_offset = y_offset;
|
||||
info_ptr->next_frame_delay_num = delay_num;
|
||||
info_ptr->next_frame_delay_den = delay_den;
|
||||
info_ptr->next_frame_render_op = render_op;
|
||||
|
||||
info_ptr->valid |= PNG_INFO_fcTl;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
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 render_op)
|
||||
{
|
||||
if (width > png_ptr->first_frame_width ||
|
||||
height > png_ptr->first_frame_height)
|
||||
png_error(png_ptr, "width and/or height for a frame greater than"
|
||||
"the ones in IHDR");
|
||||
if (width > PNG_UINT_31_MAX)
|
||||
png_error(png_ptr, "invalid width in fcTl (> 2^31-1)");
|
||||
if (height > PNG_UINT_31_MAX)
|
||||
png_error(png_ptr, "invalid height in fcTl (> 2^31-1)");
|
||||
if (x_offset > PNG_UINT_31_MAX)
|
||||
png_error(png_ptr, "invalid x_offset in fcTl (> 2^31-1)");
|
||||
if (y_offset > PNG_UINT_31_MAX)
|
||||
png_error(png_ptr, "invalid y_offset in fcTl (> 2^31-1)");
|
||||
if (render_op & 0xF0)
|
||||
/* Bits 4 through 7 are reserved and must be set to zero (APNG spec) */
|
||||
png_error(png_ptr, "invalid render_op in fcTl");
|
||||
if (render_op & 0x08 && png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
|
||||
png_error(png_ptr, "APNG_RENDER_OP_BLEND_FLAG is not valid for "
|
||||
"color type 'greyscale without alpha'");
|
||||
if ((render_op & 0x08) &&
|
||||
(png_ptr->color_type & PNG_COLOR_MASK_COLOR) &&
|
||||
!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA))
|
||||
png_error(png_ptr, "APNG_RENDER_OP_BLEND_FLAG is not valid for "
|
||||
"color type 'truecolor without alpha'");
|
||||
if (!(render_op & PNG_RENDER_OP_DISPOSE_MASK))
|
||||
png_error(png_ptr, "no DISPOSE_ flag found in fcTl");
|
||||
if ( (render_op & PNG_RENDER_OP_DISPOSE_MASK) != PNG_RENDER_OP_DISPOSE_NONE &&
|
||||
(render_op & PNG_RENDER_OP_DISPOSE_MASK) != PNG_RENDER_OP_DISPOSE_BACKGROUND &&
|
||||
(render_op & PNG_RENDER_OP_DISPOSE_MASK) != PNG_RENDER_OP_DISPOSE_PREVIOUS)
|
||||
png_error(png_ptr, "multiple DISPOSE_ flags set in fcTl");
|
||||
}
|
||||
#endif /* PNG_APNG_SUPPORTED */
|
||||
|
||||
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
|
||||
void PNGAPI
|
||||
png_set_unknown_chunks(png_structp png_ptr,
|
||||
|
|
|
@ -261,6 +261,10 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
if (info_ptr->valid & PNG_INFO_acTl)
|
||||
png_write_acTl(png_ptr, info_ptr->num_frames, info_ptr->num_iterations);
|
||||
#endif
|
||||
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
|
||||
if (info_ptr->unknown_chunks_num)
|
||||
{
|
||||
|
@ -299,6 +303,10 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
|
|||
return;
|
||||
if (!(png_ptr->mode & PNG_HAVE_IDAT))
|
||||
png_error(png_ptr, "No IDATs written into file");
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
|
||||
png_error(png_ptr, "Not enough frames written");
|
||||
#endif
|
||||
|
||||
/* see if user wants us to write information chunks */
|
||||
if (info_ptr != NULL)
|
||||
|
@ -1510,4 +1518,38 @@ png_write_png(png_structp png_ptr, png_infop info_ptr,
|
|||
/* quiet compiler warnings */ return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
void PNGAPI
|
||||
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 render_op,
|
||||
png_byte first_frame_hidden)
|
||||
{
|
||||
png_debug(1, "in png_write_frame_head\n");
|
||||
|
||||
/* there is a chance this has been set after png_write_info was called,
|
||||
* so it would be set but not written. is there a way to be sure? */
|
||||
if (!(info_ptr->valid & PNG_INFO_acTl))
|
||||
png_error(png_ptr, "png_write_frame_head(): acTl not set");
|
||||
|
||||
png_write_reset(png_ptr);
|
||||
|
||||
png_write_reinit(png_ptr, info_ptr, width, height);
|
||||
|
||||
if ( !(png_ptr->num_frames_written == 0 && first_frame_hidden) )
|
||||
png_write_fcTl(png_ptr, width, height, x_offset, y_offset,
|
||||
delay_num, delay_den, render_op);
|
||||
}
|
||||
|
||||
void PNGAPI
|
||||
png_write_frame_tail(png_structp png_ptr, png_infop png_info)
|
||||
{
|
||||
png_debug(1, "in png_write_frame_tail\n");
|
||||
|
||||
png_ptr->num_frames_written++;
|
||||
}
|
||||
#endif /* PNG_WRITE_APNG_SUPPORTED */
|
||||
|
||||
#endif /* PNG_WRITE_SUPPORTED */
|
||||
|
|
|
@ -491,6 +491,12 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
|
|||
/* write the chunk */
|
||||
png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
png_ptr->IHDR_crc = png_ptr->crc;
|
||||
png_ptr->first_frame_width = width;
|
||||
png_ptr->first_frame_height = height;
|
||||
#endif
|
||||
|
||||
/* initialize zlib with PNG info */
|
||||
png_ptr->zstream.zalloc = png_zalloc;
|
||||
png_ptr->zstream.zfree = png_zfree;
|
||||
|
@ -594,6 +600,13 @@ png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
|
|||
#endif
|
||||
png_write_chunk_end(png_ptr);
|
||||
png_ptr->mode |= PNG_HAVE_PLTE;
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
png_ptr->PLTE_crc = png_ptr->crc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* write an IDAT chunk */
|
||||
|
@ -602,6 +615,9 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
|
|||
{
|
||||
#ifdef PNG_USE_LOCAL_ARRAYS
|
||||
PNG_IDAT;
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
PNG_fdAt;
|
||||
#endif
|
||||
#endif
|
||||
png_debug(1, "in png_write_IDAT\n");
|
||||
|
||||
|
@ -644,7 +660,28 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
|
|||
"Invalid zlib compression method or flags in IDAT");
|
||||
}
|
||||
|
||||
png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
if(png_ptr->num_frames_written == 0)
|
||||
#endif
|
||||
png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
else
|
||||
{
|
||||
png_byte buf[4];
|
||||
|
||||
png_write_chunk_start(png_ptr, (png_bytep)png_fdAt, 4 + length);
|
||||
|
||||
png_save_uint_32(buf, png_ptr->next_seq_num);
|
||||
png_write_chunk_data(png_ptr, buf, 4);
|
||||
|
||||
png_write_chunk_data(png_ptr, data, length);
|
||||
|
||||
png_write_chunk_end(png_ptr);
|
||||
|
||||
png_ptr->next_seq_num++;
|
||||
}
|
||||
#endif
|
||||
|
||||
png_ptr->mode |= PNG_HAVE_IDAT;
|
||||
}
|
||||
|
||||
|
@ -1693,6 +1730,76 @@ png_write_tIME(png_structp png_ptr, png_timep mod_time)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
void /* PRIVATE */
|
||||
png_write_acTl(png_structp png_ptr,
|
||||
png_uint_32 num_frames, png_uint_32 num_iterations)
|
||||
{
|
||||
#ifdef PNG_USE_LOCAL_ARRAYS
|
||||
PNG_acTl;
|
||||
#endif
|
||||
png_byte data[16];
|
||||
|
||||
png_debug(1, "in png_write_acTl\n");
|
||||
|
||||
if (num_frames == 0)
|
||||
png_error(png_ptr, "png_write_acTl: invalid number of frames (0)");
|
||||
if (num_frames > PNG_UINT_31_MAX)
|
||||
png_error(png_ptr, "png_write_acTl: invalid number of frames "
|
||||
"(> 2^31-1)");
|
||||
if (num_iterations > PNG_UINT_31_MAX)
|
||||
png_error(png_ptr, "png_write_acTl: invalid number of iterations "
|
||||
"(> 2^31-1)");
|
||||
|
||||
png_ptr->num_frames_to_write = num_frames;
|
||||
|
||||
png_save_uint_32(data, num_frames);
|
||||
png_save_uint_32(data + 4, num_iterations);
|
||||
png_save_uint_32(data + 8, png_ptr->IHDR_crc);
|
||||
png_save_uint_32(data + 12, png_ptr->PLTE_crc);
|
||||
|
||||
png_write_chunk(png_ptr, (png_bytep)png_acTl, data, (png_size_t)16);
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
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 render_op)
|
||||
{
|
||||
#ifdef PNG_USE_LOCAL_ARRAYS
|
||||
PNG_fcTl;
|
||||
#endif
|
||||
png_byte data[25];
|
||||
|
||||
png_debug(1, "in png_write_fcTl\n");
|
||||
|
||||
if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
|
||||
png_error(png_ptr, "x and/or y offset for the first frame aren't 0\n");
|
||||
if (png_ptr->num_frames_written == 0 &&
|
||||
(width != png_ptr->first_frame_width ||
|
||||
height != png_ptr->first_frame_height))
|
||||
png_error(png_ptr, "width and/or height in the first frame's fcTl "
|
||||
"don't match the ones in IHDR\n");
|
||||
|
||||
/* more error checking */
|
||||
png_ensure_fcTl_is_valid(png_ptr, width, height, x_offset, y_offset,
|
||||
delay_num, delay_den, render_op);
|
||||
|
||||
png_save_uint_32(data, png_ptr->next_seq_num);
|
||||
png_save_uint_32(data + 4, width);
|
||||
png_save_uint_32(data + 8, height);
|
||||
png_save_uint_32(data + 12, x_offset);
|
||||
png_save_uint_32(data + 16, y_offset);
|
||||
png_save_uint_16(data + 20, delay_num);
|
||||
png_save_uint_16(data + 22, delay_den);
|
||||
data[24] = render_op;
|
||||
|
||||
png_write_chunk(png_ptr, (png_bytep)png_fcTl, data, (png_size_t)25);
|
||||
|
||||
png_ptr->next_seq_num++;
|
||||
}
|
||||
#endif /* PNG_WRITE_APNG_SUPPORTED */
|
||||
|
||||
/* initializes the row writing capability of libpng */
|
||||
void /* PRIVATE */
|
||||
png_write_start_row(png_structp png_ptr)
|
||||
|
@ -1720,14 +1827,16 @@ png_write_start_row(png_structp png_ptr)
|
|||
png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
|
||||
|
||||
/* set up row buffer */
|
||||
png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
|
||||
if (png_ptr->row_buf == NULL)
|
||||
png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
|
||||
png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
|
||||
|
||||
/* set up filtering buffer, if using this filter */
|
||||
if (png_ptr->do_filter & PNG_FILTER_SUB)
|
||||
{
|
||||
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
if (png_ptr->sub_row == NULL)
|
||||
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
|
||||
}
|
||||
|
||||
|
@ -1735,27 +1844,31 @@ png_write_start_row(png_structp png_ptr)
|
|||
if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
|
||||
{
|
||||
/* set up previous row buffer */
|
||||
png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
|
||||
if (png_ptr->prev_row == NULL)
|
||||
png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
|
||||
png_memset(png_ptr->prev_row, 0, buf_size);
|
||||
|
||||
if (png_ptr->do_filter & PNG_FILTER_UP)
|
||||
{
|
||||
png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
if (png_ptr->up_row == NULL)
|
||||
png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
|
||||
}
|
||||
|
||||
if (png_ptr->do_filter & PNG_FILTER_AVG)
|
||||
{
|
||||
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
if (png_ptr->avg_row == NULL)
|
||||
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
|
||||
}
|
||||
|
||||
if (png_ptr->do_filter & PNG_FILTER_PAETH)
|
||||
{
|
||||
png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
if (png_ptr->paeth_row == NULL)
|
||||
png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
|
||||
(png_ptr->rowbytes + 1));
|
||||
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
|
||||
}
|
||||
}
|
||||
|
@ -2747,4 +2860,39 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(PNG_WRITE_APNG_SUPPORTED)
|
||||
void /* PRIVATE */
|
||||
png_write_reset(png_structp png_ptr)
|
||||
{
|
||||
png_ptr->row_number = 0;
|
||||
png_ptr->pass = 0;
|
||||
png_ptr->mode &= ~PNG_HAVE_IDAT;
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
png_write_reinit(png_structp png_ptr, png_infop info_ptr,
|
||||
png_uint_32 width, png_uint_32 height)
|
||||
{
|
||||
if (png_ptr->num_frames_written == 0 &&
|
||||
(width != png_ptr->first_frame_width ||
|
||||
height != png_ptr->first_frame_height))
|
||||
png_error(png_ptr, "width and/or height in the first frame's fcTl "
|
||||
"don't match the ones in IHDR\n");
|
||||
if (width > png_ptr->first_frame_width ||
|
||||
height > png_ptr->first_frame_height)
|
||||
png_error(png_ptr, "width and/or height for a frame greater than"
|
||||
"the ones in IHDR");
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, width, height,
|
||||
info_ptr->bit_depth, info_ptr->color_type,
|
||||
info_ptr->interlace_type, info_ptr->compression_type,
|
||||
info_ptr->filter_type);
|
||||
|
||||
png_ptr->width = width;
|
||||
png_ptr->height = height;
|
||||
png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
|
||||
png_ptr->usr_width = png_ptr->width;
|
||||
}
|
||||
#endif
|
||||
#endif /* PNG_WRITE_SUPPORTED */
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
|
||||
#ifdef IMG_BUILD_DECODER_gif
|
||||
// gif
|
||||
#include "imgContainerGIF.h"
|
||||
#include "nsGIFDecoder2.h"
|
||||
#endif
|
||||
|
||||
|
@ -106,7 +105,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
|
|||
|
||||
#ifdef IMG_BUILD_DECODER_gif
|
||||
// gif
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(imgContainerGIF)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIFDecoder2)
|
||||
#endif
|
||||
|
||||
|
@ -222,10 +220,6 @@ static const nsModuleComponentInfo components[] =
|
|||
|
||||
#ifdef IMG_BUILD_DECODER_gif
|
||||
// gif
|
||||
{ "GIF image container",
|
||||
NS_GIFCONTAINER_CID,
|
||||
"@mozilla.org/image/container;1?type=image/gif",
|
||||
imgContainerGIFConstructor, },
|
||||
{ "GIF Decoder",
|
||||
NS_GIFDECODER2_CID,
|
||||
"@mozilla.org/image/decoder;2?type=image/gif",
|
||||
|
|
|
@ -634,11 +634,11 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
|||
gs->is_transparent = PR_FALSE;
|
||||
// ignoring gfx control extension
|
||||
}
|
||||
gs->disposal_method = (gdispose)(((*q) >> 2) & 0x7);
|
||||
gs->disposal_method = ((*q) >> 2) & 0x7;
|
||||
// Some specs say 3rd bit (value 4), other specs say value 3
|
||||
// Let's choose 3 (the more popular)
|
||||
if (gs->disposal_method == 4)
|
||||
gs->disposal_method = (gdispose)3;
|
||||
gs->disposal_method = 3;
|
||||
gs->delay_time = GETINT16(q + 1) * 10;
|
||||
GETN(1, gif_consume_block);
|
||||
}
|
||||
|
|
|
@ -72,16 +72,6 @@ typedef enum {
|
|||
gif_consume_comment
|
||||
} gstate;
|
||||
|
||||
/* "Disposal" method indicates how the image should be handled in the
|
||||
framebuffer before the subsequent image is displayed. */
|
||||
typedef enum
|
||||
{
|
||||
DISPOSE_NOT_SPECIFIED = 0,
|
||||
DISPOSE_KEEP = 1, /* Leave it in the framebuffer */
|
||||
DISPOSE_OVERWRITE_BGCOLOR = 2, /* Overwrite with background color */
|
||||
DISPOSE_OVERWRITE_PREVIOUS = 3 /* Save-under */
|
||||
} gdispose;
|
||||
|
||||
/* A GIF decoder's state */
|
||||
typedef struct gif_struct {
|
||||
void* clientptr;
|
||||
|
@ -115,7 +105,7 @@ typedef struct gif_struct {
|
|||
PRUintn x_offset, y_offset; /* With respect to "screen" origin */
|
||||
PRUintn height, width;
|
||||
int tpixel; /* Index of transparent pixel */
|
||||
gdispose disposal_method; /* Restore to background, leave in place, etc.*/
|
||||
PRInt32 disposal_method; /* Restore to background, leave in place, etc.*/
|
||||
PRUint8 *local_colormap; /* Per-image colormap */
|
||||
int local_colormap_size; /* Size of local colormap array. */
|
||||
PRUint32 delay_time; /* Display time, in milliseconds,
|
||||
|
|
|
@ -56,7 +56,10 @@ REQUIRES = xpcom \
|
|||
imglib2 \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = GIF2.cpp nsGIFDecoder2.cpp imgContainerGIF.cpp
|
||||
CPPSRCS = GIF2.cpp nsGIFDecoder2.cpp
|
||||
|
||||
# nsGIFDecoder2.cpp includes imgContainer.h
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/modules/libpr0n/src
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
#include "imgILoad.h"
|
||||
|
||||
#include "imgContainer.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Gif decoder allocator
|
||||
|
@ -102,7 +103,7 @@ NS_IMETHODIMP nsGIFDecoder2::Init(imgILoad *aLoad)
|
|||
{
|
||||
mObserver = do_QueryInterface(aLoad);
|
||||
|
||||
mImageContainer = do_CreateInstance("@mozilla.org/image/container;1?type=image/gif");
|
||||
mImageContainer = do_CreateInstance("@mozilla.org/image/container;1");
|
||||
aLoad->SetImage(mImageContainer);
|
||||
|
||||
if (!gGifAllocator) {
|
||||
|
@ -257,7 +258,7 @@ NS_IMETHODIMP nsGIFDecoder2::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
|
|||
|
||||
|
||||
//******************************************************************************
|
||||
// GIF decoder callback methods. Part of pulic API for GIF2
|
||||
// GIF decoder callback methods. Part of public API for GIF2
|
||||
//******************************************************************************
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -475,7 +476,7 @@ int nsGIFDecoder2::HaveDecodedRow(
|
|||
|
||||
if (!cmap) { // cmap could have null value if the global color table flag is 0
|
||||
for (int i = 0; i < aDuplicateCount; ++i) {
|
||||
imgContainerGIF::BlackenFrame(decoder->mImageFrame, 0, aRowNumber+i, width, 1);
|
||||
imgContainer::BlackenFrame(decoder->mImageFrame, 0, aRowNumber+i, width, 1);
|
||||
}
|
||||
} else {
|
||||
PRUint8* rowBufIndex = aRowBufPtr;
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "imgIDecoder.h"
|
||||
#include "imgContainerGIF.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgIDecoderObserver.h"
|
||||
#include "gfxIImageFrame.h"
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <stuart@mozilla.com>
|
||||
* Andrew Smith
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -55,9 +56,15 @@
|
|||
#include "nspr.h"
|
||||
#include "png.h"
|
||||
|
||||
// for nsPNGDecoder.apngFlags
|
||||
enum {
|
||||
FRAME_HIDDEN = 0x01
|
||||
};
|
||||
|
||||
static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr);
|
||||
static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row,
|
||||
png_uint_32 row_num, int pass);
|
||||
static void PNGAPI frame_info_callback(png_structp png_ptr, png_uint_32 frame_num);
|
||||
static void PNGAPI end_callback(png_structp png_ptr, png_infop info_ptr);
|
||||
static void PNGAPI error_callback(png_structp png_ptr, png_const_charp error_msg);
|
||||
static void PNGAPI warning_callback(png_structp png_ptr, png_const_charp warning_msg);
|
||||
|
@ -70,6 +77,7 @@ NS_IMPL_ISUPPORTS1(nsPNGDecoder, imgIDecoder)
|
|||
|
||||
nsPNGDecoder::nsPNGDecoder() :
|
||||
mPNG(nsnull), mInfo(nsnull),
|
||||
apngFlags(0),
|
||||
interlacebuf(nsnull), ibpr(0),
|
||||
mError(PR_FALSE)
|
||||
{
|
||||
|
@ -81,6 +89,59 @@ nsPNGDecoder::~nsPNGDecoder()
|
|||
nsMemory::Free(interlacebuf);
|
||||
}
|
||||
|
||||
// CreateFrame() is used for both simple and animated images
|
||||
void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
|
||||
PRInt32 width, PRInt32 height, gfx_format format)
|
||||
{
|
||||
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
|
||||
if (!mFrame)
|
||||
longjmp(mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
|
||||
nsresult rv = mFrame->Init(x_offset, y_offset, width, height, format, 24);
|
||||
if (NS_FAILED(rv))
|
||||
longjmp(mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
|
||||
if (png_get_valid(mPNG, mInfo, PNG_INFO_acTl))
|
||||
SetAnimFrameInfo();
|
||||
|
||||
mImage->AppendFrame(mFrame);
|
||||
|
||||
if (mObserver)
|
||||
mObserver->OnStartFrame(nsnull, mFrame);
|
||||
}
|
||||
|
||||
// set timeout and frame disposal method for the current frame
|
||||
void nsPNGDecoder::SetAnimFrameInfo()
|
||||
{
|
||||
png_uint_16 delay_num, delay_den; /* in seconds */
|
||||
png_byte render_op;
|
||||
PRInt32 timeout; /* in milliseconds */
|
||||
|
||||
delay_num = png_get_next_frame_delay_num(mPNG, mInfo);
|
||||
delay_den = png_get_next_frame_delay_den(mPNG, mInfo);
|
||||
render_op = png_get_next_frame_render_op(mPNG, mInfo);
|
||||
|
||||
if (delay_num == 0) {
|
||||
timeout = 0; // gfxImageFrame::SetTimeout() will set to a minimum
|
||||
} else {
|
||||
if (delay_den == 0)
|
||||
delay_den = 100; // so sais the APNG spec
|
||||
|
||||
// Need to cast delay_num to float to have a proper division and
|
||||
// the result to int to avoid compiler warning
|
||||
timeout = NS_STATIC_CAST( PRInt32,
|
||||
NS_STATIC_CAST(PRFloat64, delay_num) * 1000 / delay_den );
|
||||
}
|
||||
mFrame->SetTimeout(timeout);
|
||||
|
||||
if (render_op & PNG_RENDER_OP_DISPOSE_PREVIOUS)
|
||||
mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeRestorePrevious);
|
||||
else if (render_op & PNG_RENDER_OP_DISPOSE_BACKGROUND)
|
||||
mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeClear);
|
||||
else
|
||||
mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeKeep);
|
||||
}
|
||||
|
||||
|
||||
/** imgIDecoder methods **/
|
||||
|
||||
|
@ -213,20 +274,19 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
int channels;
|
||||
double aGamma;
|
||||
|
||||
png_bytep trans=NULL;
|
||||
int num_trans =0;
|
||||
png_bytep trans = NULL;
|
||||
int num_trans = 0;
|
||||
|
||||
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
|
||||
|
||||
/* always decode to 24-bit RGB or 32-bit RGBA */
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
|
||||
&interlace_type, &compression_type, &filter_type);
|
||||
|
||||
|
||||
/* limit image dimensions (bug #251381) */
|
||||
#define MOZ_PNG_MAX_DIMENSION 1000000L
|
||||
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION) {
|
||||
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*,
|
||||
png_get_progressive_ptr(png_ptr));
|
||||
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION)
|
||||
longjmp(decoder->mPNG->jmpbuf, 1);
|
||||
}
|
||||
#undef MOZ_PNG_MAX_DIMENSION
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
|
@ -292,8 +352,6 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
}
|
||||
}
|
||||
|
||||
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
|
||||
|
||||
if (decoder->mObserver)
|
||||
decoder->mObserver->OnStartDecode(nsnull);
|
||||
|
||||
|
@ -303,38 +361,38 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
|
||||
decoder->mImageLoad->SetImage(decoder->mImage);
|
||||
|
||||
// since the png is only 1 frame, initialize the container to the width and height of the frame
|
||||
decoder->mImage->Init(width, height, decoder->mObserver);
|
||||
|
||||
if (decoder->mObserver)
|
||||
decoder->mObserver->OnStartContainer(nsnull, decoder->mImage);
|
||||
|
||||
decoder->mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
|
||||
if (!decoder->mFrame)
|
||||
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
|
||||
gfx_format format;
|
||||
|
||||
if (channels == 3) {
|
||||
format = gfxIFormats::RGB;
|
||||
decoder->format = gfxIFormats::RGB;
|
||||
} else if (channels > 3) {
|
||||
if (alpha_bits == 8) {
|
||||
decoder->mImage->GetPreferredAlphaChannelFormat(&format);
|
||||
decoder->mImage->GetPreferredAlphaChannelFormat(&(decoder->format));
|
||||
} else if (alpha_bits == 1) {
|
||||
format = gfxIFormats::RGB_A1;
|
||||
decoder->format = gfxIFormats::RGB_A1;
|
||||
}
|
||||
}
|
||||
|
||||
// then initialize the frame and append it to the container
|
||||
nsresult rv = decoder->mFrame->Init(0, 0, width, height, format, 24);
|
||||
if (NS_FAILED(rv))
|
||||
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
|
||||
decoder->mImage->AppendFrame(decoder->mFrame);
|
||||
|
||||
if (decoder->mObserver)
|
||||
decoder->mObserver->OnStartFrame(nsnull, decoder->mFrame);
|
||||
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTl))
|
||||
png_set_progressive_frame_fn(png_ptr, frame_info_callback, NULL);
|
||||
|
||||
if (png_first_frame_is_hidden(png_ptr, info_ptr)) {
|
||||
decoder->apngFlags |= FRAME_HIDDEN;
|
||||
|
||||
// create a frame just to get bpr, to allocate interlacebuf
|
||||
decoder->mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
|
||||
if (!decoder->mFrame)
|
||||
longjmp(png_ptr->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
nsresult rv = decoder->mFrame->Init(0, 0, width, height, decoder->format, 24);
|
||||
if (NS_FAILED(rv))
|
||||
longjmp(png_ptr->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
} else {
|
||||
decoder->CreateFrame(0, 0, width, height, decoder->format);
|
||||
}
|
||||
|
||||
PRUint32 bpr;
|
||||
decoder->mFrame->GetImageBytesPerRow(&bpr);
|
||||
|
||||
|
@ -346,9 +404,12 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
decoder->interlacebuf = (PRUint8 *)nsMemory::Alloc(decoder->ibpr*height);
|
||||
if (!decoder->interlacebuf) {
|
||||
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (png_first_frame_is_hidden(png_ptr, info_ptr))
|
||||
decoder->mFrame = nsnull;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -384,6 +445,11 @@ row_callback(png_structp png_ptr, png_bytep new_row,
|
|||
* old row and the new row.
|
||||
*/
|
||||
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
|
||||
|
||||
// do nothing
|
||||
// is it ok that we're not telling the observer there is some data?
|
||||
if (decoder->apngFlags & FRAME_HIDDEN)
|
||||
return;
|
||||
|
||||
png_bytep line;
|
||||
if (decoder->interlacebuf) {
|
||||
|
@ -444,7 +510,32 @@ row_callback(png_structp png_ptr, png_bytep new_row,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// got the header of a new frame that's coming
|
||||
void
|
||||
frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
|
||||
{
|
||||
png_uint_32 x_offset, y_offset;
|
||||
PRInt32 width, height;
|
||||
|
||||
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
|
||||
|
||||
// old frame is done
|
||||
if (!(decoder->apngFlags & FRAME_HIDDEN)) {
|
||||
PRInt32 timeout;
|
||||
decoder->mFrame->GetTimeout(&timeout);
|
||||
decoder->mImage->EndFrameDecode(frame_num, timeout);
|
||||
decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
|
||||
}
|
||||
|
||||
decoder->apngFlags &= ~FRAME_HIDDEN;
|
||||
|
||||
x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
|
||||
y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
|
||||
width = png_get_next_frame_width(png_ptr, decoder->mInfo);
|
||||
height = png_get_next_frame_height(png_ptr, decoder->mInfo);
|
||||
|
||||
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
|
||||
}
|
||||
|
||||
void
|
||||
end_callback(png_structp png_ptr, png_infop info_ptr)
|
||||
|
@ -462,16 +553,29 @@ end_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
*/
|
||||
|
||||
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
|
||||
|
||||
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTl)) {
|
||||
PRInt32 num_iterations = png_get_num_iterations(png_ptr, info_ptr);
|
||||
if (num_iterations <= 0) /* forever */
|
||||
num_iterations = -1;
|
||||
|
||||
decoder->mImage->SetLoopCount(num_iterations);
|
||||
}
|
||||
|
||||
if (!(decoder->apngFlags & FRAME_HIDDEN)) {
|
||||
PRInt32 timeout;
|
||||
decoder->mFrame->GetTimeout(&timeout);
|
||||
decoder->mImage->EndFrameDecode(decoder->mPNG->num_frames_read, timeout);
|
||||
}
|
||||
|
||||
decoder->mImage->DecodingComplete();
|
||||
|
||||
if (decoder->mObserver) {
|
||||
decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
|
||||
if (!(decoder->apngFlags & FRAME_HIDDEN))
|
||||
decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
|
||||
decoder->mObserver->OnStopContainer(nsnull, decoder->mImage);
|
||||
decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
||||
}
|
||||
|
||||
// We are never going to change the data of this frame again. Let the OS
|
||||
// do what it wants with this image.
|
||||
decoder->mFrame->SetMutable(PR_FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -69,6 +69,10 @@ public:
|
|||
nsPNGDecoder();
|
||||
virtual ~nsPNGDecoder();
|
||||
|
||||
void CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
|
||||
PRInt32 width, PRInt32 height, gfx_format format);
|
||||
void SetAnimFrameInfo();
|
||||
|
||||
public:
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
nsCOMPtr<gfxIImageFrame> mFrame;
|
||||
|
@ -77,6 +81,8 @@ public:
|
|||
|
||||
png_structp mPNG;
|
||||
png_infop mInfo;
|
||||
gfx_format format;
|
||||
PRUint8 apngFlags;
|
||||
PRUint8 *interlacebuf;
|
||||
PRUint32 ibpr;
|
||||
PRPackedBool mError;
|
||||
|
|
|
@ -54,6 +54,19 @@ interface imgIContainerObserver;
|
|||
[scriptable, uuid(1a6290e6-8285-4e10-963d-d001f8d327b8)]
|
||||
interface imgIContainer : nsISupports
|
||||
{
|
||||
/**
|
||||
* "Disposal" method indicates how the image should be handled before the
|
||||
* subsequent image is displayed.
|
||||
* Don't change these without looking at the implementations using them,
|
||||
* struct gif_struct::disposal_method and gif_write() in particular.
|
||||
*/
|
||||
const long kDisposeClearAll = -1; // Clear the whole image, revealing
|
||||
// what was there before the gif displayed
|
||||
const long kDisposeNotSpecified = 0; // Leave frame, let new frame draw on top
|
||||
const long kDisposeKeep = 1; // Leave frame, let new frame draw on top
|
||||
const long kDisposeClear = 2; // Clear the frame's area, revealing bg
|
||||
const long kDisposeRestorePrevious = 3; // Restore the previous (composited) frame
|
||||
|
||||
/**
|
||||
* Create a new \a aWidth x \a aHeight sized image container.
|
||||
*
|
||||
|
@ -126,8 +139,6 @@ interface imgIContainer : nsISupports
|
|||
|
||||
void resetAnimation();
|
||||
|
||||
/* animation stuff */
|
||||
|
||||
/**
|
||||
* number of times to loop the image.
|
||||
* @note -1 means forever.
|
||||
|
|
|
@ -47,7 +47,7 @@ interface nsIURI;
|
|||
/**
|
||||
* imgIRequest interface
|
||||
*
|
||||
* @author Stuart Parmenter <pavlov@netscape.com>
|
||||
* @author Stuart Parmenter <stuart@mozilla.com>
|
||||
* @version 0.1
|
||||
* @see imagelib2
|
||||
*/
|
||||
|
|
|
@ -54,6 +54,8 @@ REQUIRES = xpcom \
|
|||
necko \
|
||||
nkcache \
|
||||
gfx \
|
||||
thebes \
|
||||
cairo \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -38,14 +38,26 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/** @file
|
||||
* This file declares the imgContainer class, which
|
||||
* handles static and animated image containers.
|
||||
*
|
||||
* @author Stuart Parmenter <pavlov@netscape.com>
|
||||
* @author Chris Saari <saari@netscape.com>
|
||||
* @author Arron Mogge <paper@animecity.nu>
|
||||
* @author Andrew Smith <asmith15@learn.senecac.on.ca>
|
||||
*/
|
||||
|
||||
#ifndef __imgContainer_h__
|
||||
#define __imgContainer_h__
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "gfxIImageFrame.h"
|
||||
#include "nsIProperties.h"
|
||||
|
||||
#include "nsITimer.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
#define NS_IMGCONTAINER_CID \
|
||||
{ /* 27f0682c-ff64-4dd2-ae7a-668e59f2fd38 */ \
|
||||
|
@ -55,20 +67,231 @@
|
|||
{0xae, 0x7a, 0x66, 0x8e, 0x59, 0xf2, 0xfd, 0x38} \
|
||||
}
|
||||
|
||||
class imgContainer : public imgIContainer, public nsIProperties
|
||||
/**
|
||||
* Handles static and animated image containers.
|
||||
*
|
||||
*
|
||||
* @par A Quick Walk Through
|
||||
* The decoder initializes this class and calls AppendFrame() to add a frame.
|
||||
* Once imgContainer detects more than one frame, it starts the animation
|
||||
* with StartAnimation().
|
||||
*
|
||||
* @par
|
||||
* StartAnimation() checks if animating is allowed, and creates a timer. The
|
||||
* timer calls Notify when the specified frame delay time is up.
|
||||
*
|
||||
* @par
|
||||
* Notify() moves on to the next frame, sets up the new timer delay, destroys
|
||||
* the old frame, and forces a redraw via observer->FrameChanged().
|
||||
*
|
||||
* @par
|
||||
* Each frame can have a different method of removing itself. These are
|
||||
* listed as imgIContainer::cDispose... constants. Notify() calls
|
||||
* DoComposite() to handle any special frame destruction.
|
||||
*
|
||||
* @par
|
||||
* The basic path through DoComposite() is:
|
||||
* 1) Calculate Area that needs updating, which is at least the area of
|
||||
* aNextFrame.
|
||||
* 2) Dispose of previous frame.
|
||||
* 3) Draw new image onto compositingFrame.
|
||||
* See comments in DoComposite() for more information and optimizations.
|
||||
*
|
||||
* @par
|
||||
* The rest of the imgContainer specific functions are used by DoComposite to
|
||||
* destroy the old frame and build the new one.
|
||||
*
|
||||
* @note
|
||||
* <li> "Mask", "Alpha", and "Alpha Level" are interchangable phrases in
|
||||
* respects to imgContainerGIF.
|
||||
*
|
||||
* @par
|
||||
* <li> GIFs never have more than a 1 bit alpha.
|
||||
* <li> APNGs may have a full alpha channel.
|
||||
*
|
||||
* @par
|
||||
* <li> Background color specified in GIF is ignored by web browsers.
|
||||
*
|
||||
* @par
|
||||
* <li> If Frame 3 wants to dispose by restoring previous, what it wants is to
|
||||
* restore the composition up to and including Frame 2, as well as Frame 2s
|
||||
* disposal. So, in the middle of DoComposite when composing Frame 3, right
|
||||
* after destroying Frame 2's area, we copy compositingFrame to
|
||||
* prevCompositingFrame. When DoComposite gets called to do Frame 4, we
|
||||
* copy prevCompositingFrame back, and then draw Frame 4 on top.
|
||||
*
|
||||
* @par
|
||||
* The mAnim structure has members only needed for animated images, so
|
||||
* it's not allocated until the second frame is added.
|
||||
*
|
||||
* @note
|
||||
* mAnimationMode, mLoopCount and mObserver are not in the mAnim structure
|
||||
* because the first two have public setters and the observer we only get
|
||||
* in Init().
|
||||
*/
|
||||
class imgContainer : public imgIContainer,
|
||||
public nsITimerCallback,
|
||||
public nsIProperties
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGICONTAINER
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_FORWARD_SAFE_NSIPROPERTIES(mProperties)
|
||||
|
||||
imgContainer();
|
||||
virtual ~imgContainer();
|
||||
|
||||
private:
|
||||
nsIntSize mSize;
|
||||
nsCOMPtr<gfxIImageFrame> mFrame;
|
||||
nsCOMPtr<nsIProperties> mProperties;
|
||||
friend class nsGIFDecoder2;
|
||||
|
||||
struct Anim
|
||||
{
|
||||
//! Area of the first frame that needs to be redrawn on subsequent loops.
|
||||
nsIntRect firstFrameRefreshArea;
|
||||
// Note this doesn't hold a proper value until frame 2 finished decoding.
|
||||
PRInt32 currentDecodingFrameIndex; // 0 to numFrames-1
|
||||
PRInt32 currentAnimationFrameIndex; // 0 to numFrames-1
|
||||
//! Track the last composited frame for Optimizations (See DoComposite code)
|
||||
PRInt32 lastCompositedFrameIndex;
|
||||
//! Whether we can assume there will be no more frames
|
||||
//! (and thus loop the animation)
|
||||
PRBool doneDecoding;
|
||||
//! Are we currently animating the image?
|
||||
PRBool animating;
|
||||
/** For managing blending of frames
|
||||
*
|
||||
* Some animations will use the compositingFrame to composite images
|
||||
* and just hand this back to the caller when it is time to draw the frame.
|
||||
* NOTE: When clearing compositingFrame, remember to set
|
||||
* lastCompositedFrameIndex to -1. Code assume that if
|
||||
* lastCompositedFrameIndex >= 0 then compositingFrame exists.
|
||||
*/
|
||||
nsCOMPtr<gfxIImageFrame> compositingFrame;
|
||||
/** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
|
||||
*
|
||||
* The Previous Frame (all frames composited up to the current) needs to be
|
||||
* stored in cases where the image specifies it wants the last frame back
|
||||
* when it's done with the current frame.
|
||||
*/
|
||||
nsCOMPtr<gfxIImageFrame> compositingPrevFrame;
|
||||
//! Timer to animate multiframed images
|
||||
nsCOMPtr<nsITimer> timer;
|
||||
|
||||
Anim() :
|
||||
firstFrameRefreshArea(),
|
||||
currentDecodingFrameIndex(0),
|
||||
currentAnimationFrameIndex(0),
|
||||
lastCompositedFrameIndex(-1),
|
||||
doneDecoding(PR_FALSE),
|
||||
animating(PR_FALSE)
|
||||
{
|
||||
;
|
||||
}
|
||||
~Anim()
|
||||
{
|
||||
if (timer)
|
||||
timer->Cancel();
|
||||
}
|
||||
};
|
||||
|
||||
inline gfxIImageFrame* inlinedGetCurrentFrame() {
|
||||
if (!mAnim)
|
||||
return mFrames.SafeObjectAt(0);
|
||||
if (mAnim->lastCompositedFrameIndex == mAnim->currentAnimationFrameIndex)
|
||||
return mAnim->compositingFrame;
|
||||
return mFrames.SafeObjectAt(mAnim->currentAnimationFrameIndex);
|
||||
}
|
||||
|
||||
inline Anim* ensureAnimExists() {
|
||||
if (!mAnim)
|
||||
mAnim = new Anim();
|
||||
return mAnim;
|
||||
}
|
||||
|
||||
/** Function for doing the frame compositing of animations
|
||||
*
|
||||
* @param aFrameToUse Set by DoComposite
|
||||
* (aNextFrame, compositingFrame, or compositingPrevFrame)
|
||||
* @param aDirtyRect Area that the display will need to update
|
||||
* @param aPrevFrame Last Frame seen/processed
|
||||
* @param aNextFrame Frame we need to incorperate/display
|
||||
* @param aNextFrameIndex Position of aNextFrame in mFrames list
|
||||
*/
|
||||
nsresult DoComposite(gfxIImageFrame** aFrameToUse, nsIntRect* aDirtyRect,
|
||||
gfxIImageFrame* aPrevFrame,
|
||||
gfxIImageFrame* aNextFrame,
|
||||
PRInt32 aNextFrameIndex);
|
||||
|
||||
/**
|
||||
* Combine aOverlayFrame's mask into aCompositingFrame's mask.
|
||||
*
|
||||
* This takes the mask information from the passed in aOverlayFrame and
|
||||
* inserts that information into the aCompositingFrame's mask at the proper
|
||||
* offsets. It does *not* rebuild the entire mask.
|
||||
*
|
||||
* @param aCompositingFrame Target frame
|
||||
* @param aOverlayFrame This frame's mask is being copied
|
||||
*/
|
||||
void BuildCompositeMask(gfxIImageFrame* aCompositingFrame,
|
||||
gfxIImageFrame* aOverlayFrame);
|
||||
|
||||
/** Sets an area of the frame's mask.
|
||||
*
|
||||
* @param aFrame Target Frame
|
||||
* @param aVisible Turn on (PR_TRUE) or off (PR_FALSE) visibility
|
||||
*
|
||||
* @note Invisible area of frame's image will need to be set to 0
|
||||
*/
|
||||
void SetMaskVisibility(gfxIImageFrame *aFrame, PRBool aVisible);
|
||||
//! @overload
|
||||
void SetMaskVisibility(gfxIImageFrame *aFrame,
|
||||
PRInt32 aX, PRInt32 aY,
|
||||
PRInt32 aWidth, PRInt32 aHeight,
|
||||
PRBool aVisible);
|
||||
//! @overload
|
||||
void SetMaskVisibility(gfxIImageFrame *aFrame,
|
||||
nsIntRect &aRect, PRBool aVisible) {
|
||||
SetMaskVisibility(aFrame, aRect.x, aRect.y,
|
||||
aRect.width, aRect.height, aVisible);
|
||||
}
|
||||
|
||||
/** Fills an area of <aFrame> with black.
|
||||
*
|
||||
* @param aFrame Target Frame
|
||||
*
|
||||
* @note Does not set the mask
|
||||
*/
|
||||
static void BlackenFrame(gfxIImageFrame* aFrame);
|
||||
//! @overload
|
||||
static void BlackenFrame(gfxIImageFrame* aFrame,
|
||||
PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight);
|
||||
//! @overload
|
||||
static inline void BlackenFrame(gfxIImageFrame* aFrame, nsIntRect &aRect) {
|
||||
BlackenFrame(aFrame, aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
}
|
||||
|
||||
//! Copy one gfxIImageFrame's image and mask into another
|
||||
static PRBool CopyFrameImage(gfxIImageFrame *aSrcFrame,
|
||||
gfxIImageFrame *aDstFrame);
|
||||
|
||||
nsIntSize mSize;
|
||||
|
||||
//! All the <gfxIImageFrame>s of the PNG
|
||||
nsCOMArray<gfxIImageFrame> mFrames;
|
||||
|
||||
nsCOMPtr<nsIProperties> mProperties;
|
||||
|
||||
imgContainer::Anim* mAnim;
|
||||
|
||||
//! See imgIContainer for mode constants
|
||||
PRUint16 mAnimationMode;
|
||||
|
||||
//! # loops remaining before animation stops (-1 no stop)
|
||||
PRInt32 mLoopCount;
|
||||
|
||||
//! imgIContainerObserver
|
||||
nsWeakPtr mObserver;
|
||||
};
|
||||
|
||||
#endif /* __imgContainer_h__ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче