зеркало из https://github.com/mozilla/gecko-dev.git
bug 285872 GIF Decoder: replace gathering buffer with dynamic malloc to fixed
256 bytes hold patch by Alfred Kayser <alfredkayser@nl.ibm.com> r/sr=tor/pavlov
This commit is contained in:
Родитель
7d86ff9edd
Коммит
eaaf0466e4
|
@ -79,57 +79,24 @@ mailing address.
|
||||||
|
|
||||||
#include "nsGIFDecoder2.h"
|
#include "nsGIFDecoder2.h"
|
||||||
|
|
||||||
/* Gather n characters from the input stream and then enter state s. */
|
/*
|
||||||
|
* GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
|
||||||
|
*
|
||||||
|
* Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
|
||||||
|
* as each GIF block (except colormaps) can never be bigger than 256 bytes.
|
||||||
|
* Colormaps are directly copied in the resp. global_colormap or dynamically allocated local_colormap.
|
||||||
|
* So a fixed buffer in gif_struct is good enough.
|
||||||
|
* This buffer is only needed to copy left-over data from one GifWrite call to the next
|
||||||
|
*/
|
||||||
#define GETN(n,s) \
|
#define GETN(n,s) \
|
||||||
PR_BEGIN_MACRO \
|
PR_BEGIN_MACRO \
|
||||||
gs->state = gif_gather; \
|
gs->bytes_to_consume = (n); \
|
||||||
gs->gather_request_size = (n); \
|
gs->state = (s); \
|
||||||
gs->post_gather_state = s; \
|
|
||||||
PR_END_MACRO
|
PR_END_MACRO
|
||||||
|
|
||||||
/* Get a 16-bit value stored in little-endian format */
|
/* Get a 16-bit value stored in little-endian format */
|
||||||
#define GETINT16(p) ((p)[1]<<8|(p)[0])
|
#define GETINT16(p) ((p)[1]<<8|(p)[0])
|
||||||
|
|
||||||
/* Get a 32-bit value stored in little-endian format */
|
|
||||||
#define GETINT32(p) (((p)[3]<<24) | ((p)[2]<<16) | ((p)[1]<<8) | ((p)[0]))
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
/* binary block Allocate and Concatenate
|
|
||||||
*
|
|
||||||
* destination_length is the length of the existing block
|
|
||||||
* source_length is the length of the block being added to the
|
|
||||||
* destination block
|
|
||||||
*/
|
|
||||||
static char *il_BACat (char **destination,
|
|
||||||
size_t destination_length,
|
|
||||||
const char *source,
|
|
||||||
size_t source_length)
|
|
||||||
{
|
|
||||||
if (source) {
|
|
||||||
if (*destination) {
|
|
||||||
*destination = (char *) PR_REALLOC (*destination,
|
|
||||||
destination_length + source_length);
|
|
||||||
if (*destination == nsnull)
|
|
||||||
return (nsnull);
|
|
||||||
|
|
||||||
memmove(*destination + destination_length, source, source_length);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*destination = (char *) PR_MALLOC (source_length);
|
|
||||||
if (*destination == nsnull)
|
|
||||||
return (nsnull);
|
|
||||||
|
|
||||||
memcpy(*destination, source, source_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef BlockAllocCat
|
|
||||||
#define BlockAllocCat(dest, dest_length, src, src_length) \
|
|
||||||
il_BACat(&(dest), dest_length, src, src_length)
|
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
// Send the data to the display front-end.
|
// Send the data to the display front-end.
|
||||||
static void output_row(gif_struct *gs)
|
static void output_row(gif_struct *gs)
|
||||||
|
@ -411,28 +378,13 @@ PRBool GIFInit(gif_struct* gs, void* aClientData)
|
||||||
memset(gs, 0, offsetof(gif_struct, prefix));
|
memset(gs, 0, offsetof(gif_struct, prefix));
|
||||||
gs->clientptr = aClientData;
|
gs->clientptr = aClientData;
|
||||||
|
|
||||||
gs->state = gif_init;
|
// Start with the version (GIF89a|GIF87a)
|
||||||
gs->post_gather_state = gif_error;
|
gs->state = gif_type;
|
||||||
gs->gathered = 0;
|
gs->bytes_to_consume = 6;
|
||||||
|
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Maximum # of bytes to read ahead while waiting for delay_time to expire.
|
|
||||||
We no longer limit this number to remain within WIN16 malloc limitations
|
|
||||||
of 0xffff */
|
|
||||||
|
|
||||||
#define MAX_READ_AHEAD (0xFFFFFFL)
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
PRBool gif_write_ready(const gif_struct* gs)
|
|
||||||
{
|
|
||||||
if (!gs)
|
|
||||||
return PR_FALSE;
|
|
||||||
|
|
||||||
return (gs->gathered < MAX_READ_AHEAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/*
|
/*
|
||||||
* process data arriving from the stream for the gif decoder
|
* process data arriving from the stream for the gif decoder
|
||||||
|
@ -440,20 +392,55 @@ PRBool gif_write_ready(const gif_struct* gs)
|
||||||
|
|
||||||
PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
{
|
{
|
||||||
if (!gs)
|
if (!gs || !len)
|
||||||
return PR_FAILURE;
|
return PR_FAILURE;
|
||||||
|
|
||||||
/* If we fail, some upstream data provider ignored the
|
const PRUint8 *q = buf;
|
||||||
zero return value from il_gif_write_ready() which says not to
|
|
||||||
send any more data to this stream until the delay timeout fires. */
|
|
||||||
if ((len != 0) && (gs->gathered >= MAX_READ_AHEAD))
|
|
||||||
return PR_FAILURE;
|
|
||||||
|
|
||||||
const PRUint8 *q, *p = buf, *ep = buf + len;
|
// Add what we have sofar to the block
|
||||||
|
// If previous call to me left something in the hold first complete current block
|
||||||
|
// Or if we are filling the colormaps, first complete the colormap
|
||||||
|
PRUint8* p;
|
||||||
|
if (gs->state == gif_global_colormap)
|
||||||
|
p = gs->global_colormap;
|
||||||
|
else if (gs->state == gif_image_colormap)
|
||||||
|
p = gs->local_colormap;
|
||||||
|
else if (gs->bytes_in_hold)
|
||||||
|
p = gs->hold;
|
||||||
|
else
|
||||||
|
p = nsnull;
|
||||||
|
|
||||||
q = nsnull; /* Initialize to shut up gcc warnings */
|
if (p) {
|
||||||
|
// Add what we have sofar to the block
|
||||||
|
PRUint32 l = PR_MIN(len, gs->bytes_to_consume);
|
||||||
|
memcpy(p+gs->bytes_in_hold, buf, l);
|
||||||
|
|
||||||
|
if (l < gs->bytes_to_consume) {
|
||||||
|
// Not enough in 'buf' to complete current block, get more
|
||||||
|
gs->bytes_in_hold += l;
|
||||||
|
gs->bytes_to_consume -= l;
|
||||||
|
return PR_SUCCESS;
|
||||||
|
}
|
||||||
|
// Reset hold buffer count
|
||||||
|
gs->bytes_in_hold = 0;
|
||||||
|
// Point 'q' to complete block in hold (or in colormap)
|
||||||
|
q = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invariant:
|
||||||
|
// 'q' is start of current to be processed block (hold, colormap or buf)
|
||||||
|
// 'bytes_to_consume' is number of bytes to consume from 'buf'
|
||||||
|
// 'buf' points to the bytes to be consumed from the input buffer
|
||||||
|
// 'len' is number of bytes left in input buffer from position 'buf'.
|
||||||
|
// At entrance of the for loop will 'buf' will be moved 'bytes_to_consume'
|
||||||
|
// to point to next buffer, 'len' is adjusted accordingly.
|
||||||
|
// So that next round in for loop, q gets pointed to the next buffer.
|
||||||
|
|
||||||
|
for (;len >= gs->bytes_to_consume; q=buf) {
|
||||||
|
// Eat the current block from the buffer, q keeps pointed at current block
|
||||||
|
buf += gs->bytes_to_consume;
|
||||||
|
len -= gs->bytes_to_consume;
|
||||||
|
|
||||||
while (p <= ep) {
|
|
||||||
switch (gs->state)
|
switch (gs->state)
|
||||||
{
|
{
|
||||||
case gif_lzw:
|
case gif_lzw:
|
||||||
|
@ -496,29 +483,12 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* We're positioned at the very start of the file. */
|
|
||||||
case gif_init:
|
|
||||||
{
|
|
||||||
GETN(3, gif_type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All GIF files begin with "GIF87a" or "GIF89a" */
|
/* All GIF files begin with "GIF87a" or "GIF89a" */
|
||||||
case gif_type:
|
case gif_type:
|
||||||
{
|
{
|
||||||
if (strncmp((char*)q, "GIF", 3)) {
|
if (!strncmp((char*)q, "GIF89a", 6)) {
|
||||||
gs->state = gif_error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
GETN(3, gif_version);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case gif_version:
|
|
||||||
{
|
|
||||||
if (!strncmp((char*)q, "89a", 3)) {
|
|
||||||
gs->version = 89;
|
gs->version = 89;
|
||||||
} else if (!strncmp((char*)q, "87a", 3)) {
|
} else if (!strncmp((char*)q, "GIF87a", 6)) {
|
||||||
gs->version = 87;
|
gs->version = 87;
|
||||||
} else {
|
} else {
|
||||||
gs->state = gif_error;
|
gs->state = gif_error;
|
||||||
|
@ -551,11 +521,21 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
gs->screen_height,
|
gs->screen_height,
|
||||||
gs->screen_bgcolor);
|
gs->screen_bgcolor);
|
||||||
|
|
||||||
if (q[4] & 0x80) /* global map */
|
if (q[4] & 0x80) { /* global map */
|
||||||
/* 3 bytes for each entry in the global colormap */
|
// Get the global colormap
|
||||||
GETN(gs->global_colormap_size*3, gif_global_colormap);
|
const PRUint32 size = 3*gs->global_colormap_size;
|
||||||
else
|
if (len < size) {
|
||||||
GETN(1, gif_image_start);
|
// Use 'hold' pattern to get the global colormap
|
||||||
|
GETN(size, gif_global_colormap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Copy everything and directly go to gif_lzw_start
|
||||||
|
memcpy(gs->global_colormap, buf, size);
|
||||||
|
buf += size;
|
||||||
|
len -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
GETN(1, gif_image_start);
|
||||||
|
|
||||||
// q[6] = Pixel Aspect Ratio
|
// q[6] = Pixel Aspect Ratio
|
||||||
// Not used
|
// Not used
|
||||||
|
@ -564,11 +544,8 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case gif_global_colormap:
|
case gif_global_colormap:
|
||||||
{
|
// Everything is already copied into global_colormap
|
||||||
memcpy(gs->global_colormap, q, 3 * gs->global_colormap_size);
|
|
||||||
|
|
||||||
GETN(1, gif_image_start);
|
GETN(1, gif_image_start);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case gif_image_start:
|
case gif_image_start:
|
||||||
|
@ -669,9 +646,8 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
|
|
||||||
case gif_comment_extension:
|
case gif_comment_extension:
|
||||||
{
|
{
|
||||||
gs->count = *q;
|
if (*q)
|
||||||
if (gs->count)
|
GETN(*q, gif_consume_comment);
|
||||||
GETN(gs->count, gif_consume_comment);
|
|
||||||
else
|
else
|
||||||
GETN(1, gif_image_start);
|
GETN(1, gif_image_start);
|
||||||
}
|
}
|
||||||
|
@ -833,43 +809,46 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
gs->rowend = gs->rowbuf + gs->width;
|
gs->rowend = gs->rowbuf + gs->width;
|
||||||
gs->rowp = gs->rowbuf;
|
gs->rowp = gs->rowbuf;
|
||||||
|
|
||||||
/* bits per pixel is 1<<((q[8]&0x07) + 1); */
|
/* bits per pixel is q[8]&0x07 */
|
||||||
|
|
||||||
if (q[8] & 0x80) /* has a local colormap? */
|
if (q[8] & 0x80) /* has a local colormap? */
|
||||||
{
|
{
|
||||||
int num_colors = 2 << (q[8] & 0x7);
|
int num_colors = 2 << (q[8] & 0x7);
|
||||||
|
const PRUint32 size = 3*num_colors;
|
||||||
// If current local_colormap is not big enough, force reallocation
|
PRUint8 *map = gs->local_colormap;
|
||||||
if (num_colors > gs->local_colormap_size)
|
if (!map || (num_colors > gs->local_colormap_size)) {
|
||||||
PR_FREEIF(gs->local_colormap);
|
map = (PRUint8*)PR_REALLOC(map, size);
|
||||||
gs->local_colormap_size = num_colors;
|
if (!map) {
|
||||||
|
gs->state = gif_oom;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Switch to the new local palette after it loads */
|
/* Switch to the new local palette after it loads */
|
||||||
|
gs->local_colormap = map;
|
||||||
|
gs->local_colormap_size = num_colors;
|
||||||
gs->is_local_colormap_defined = PR_TRUE;
|
gs->is_local_colormap_defined = PR_TRUE;
|
||||||
GETN(gs->local_colormap_size * 3, gif_image_colormap);
|
|
||||||
|
if (len < size) {
|
||||||
|
// Use 'hold' pattern to get the image colormap
|
||||||
|
GETN(size, gif_image_colormap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Copy everything and directly go to gif_lzw_start
|
||||||
|
memcpy(gs->local_colormap, buf, size);
|
||||||
|
buf += size;
|
||||||
|
len -= size;
|
||||||
} else {
|
} else {
|
||||||
/* Switch back to the global palette */
|
/* Switch back to the global palette */
|
||||||
gs->is_local_colormap_defined = PR_FALSE;
|
gs->is_local_colormap_defined = PR_FALSE;
|
||||||
GETN(1, gif_lzw_start);
|
|
||||||
}
|
}
|
||||||
|
GETN(1, gif_lzw_start);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case gif_image_colormap:
|
case gif_image_colormap:
|
||||||
{
|
// Everything is already copied into local_colormap
|
||||||
PRUint8 *map = gs->local_colormap;
|
|
||||||
if (!map) {
|
|
||||||
map = gs->local_colormap = (PRUint8*)PR_MALLOC(3 * gs->local_colormap_size);
|
|
||||||
if (!map) {
|
|
||||||
gs->state = gif_oom;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(map, q, 3 * gs->local_colormap_size);
|
|
||||||
|
|
||||||
GETN(1, gif_lzw_start);
|
GETN(1, gif_lzw_start);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case gif_sub_block:
|
case gif_sub_block:
|
||||||
|
@ -900,6 +879,7 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
gs->delay_time);
|
gs->delay_time);
|
||||||
|
|
||||||
/* Clear state from this image */
|
/* Clear state from this image */
|
||||||
|
gs->is_local_colormap_defined = PR_FALSE;
|
||||||
gs->is_transparent = PR_FALSE;
|
gs->is_transparent = PR_FALSE;
|
||||||
|
|
||||||
/* An image can specify a delay time before which to display
|
/* An image can specify a delay time before which to display
|
||||||
|
@ -917,59 +897,6 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
return PR_SUCCESS;
|
return PR_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case gif_delay:
|
|
||||||
case gif_gather:
|
|
||||||
{
|
|
||||||
PRInt32 gather_remaining;
|
|
||||||
PRInt32 request_size = gs->gather_request_size;
|
|
||||||
|
|
||||||
{
|
|
||||||
gather_remaining = request_size - gs->gathered;
|
|
||||||
|
|
||||||
/* Do we already have enough data in the accumulation
|
|
||||||
buffer to satisfy the request ? (This can happen
|
|
||||||
after we transition from the gif_delay state.) */
|
|
||||||
if (gather_remaining <= 0) {
|
|
||||||
gs->gathered -= request_size;
|
|
||||||
q = gs->gather_head;
|
|
||||||
gs->gather_head += request_size;
|
|
||||||
gs->state = gs->post_gather_state;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift remaining data to the head of the buffer */
|
|
||||||
if (gs->gathered && (gs->gather_head != gs->hold)) {
|
|
||||||
memmove(gs->hold, gs->gather_head, gs->gathered);
|
|
||||||
gs->gather_head = gs->hold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we add the data just handed to us by the netlib
|
|
||||||
to what we've already gathered, is there enough to satisfy
|
|
||||||
the current request ? */
|
|
||||||
if ((ep - p) >= gather_remaining) {
|
|
||||||
if (gs->gathered) { /* finish a prior gather */
|
|
||||||
char *hold = (char*)gs->hold;
|
|
||||||
BlockAllocCat(hold, gs->gathered, (char*)p, gather_remaining);
|
|
||||||
gs->hold = (PRUint8*)hold;
|
|
||||||
q = gs->gather_head = gs->hold;
|
|
||||||
gs->gathered = 0;
|
|
||||||
} else
|
|
||||||
q = p;
|
|
||||||
|
|
||||||
p += gather_remaining;
|
|
||||||
gs->state = gs->post_gather_state;
|
|
||||||
} else {
|
|
||||||
char *hold = (char*)gs->hold;
|
|
||||||
BlockAllocCat(hold, gs->gathered, (char*)p, ep - p);
|
|
||||||
gs->hold = (PRUint8*)hold;
|
|
||||||
gs->gather_head = gs->hold;
|
|
||||||
gs->gathered += ep-p;
|
|
||||||
return PR_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Handle out of memory errors
|
// Handle out of memory errors
|
||||||
case gif_oom:
|
case gif_oom:
|
||||||
return PR_FAILURE;
|
return PR_FAILURE;
|
||||||
|
@ -979,15 +906,27 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
|
||||||
nsGIFDecoder2::EndGIF(gs->clientptr, gs->loop_count);
|
nsGIFDecoder2::EndGIF(gs->clientptr, gs->loop_count);
|
||||||
return PR_SUCCESS;
|
return PR_SUCCESS;
|
||||||
|
|
||||||
case gif_stop_animating:
|
|
||||||
return PR_SUCCESS;
|
|
||||||
|
|
||||||
// We shouldn't ever get here.
|
// We shouldn't ever get here.
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the leftover into gs->hold
|
||||||
|
gs->bytes_in_hold = len;
|
||||||
|
if (len) {
|
||||||
|
// Add what we have sofar to the block
|
||||||
|
PRUint8* p;
|
||||||
|
if (gs->state == gif_global_colormap)
|
||||||
|
p = gs->global_colormap;
|
||||||
|
else if (gs->state == gif_image_colormap)
|
||||||
|
p = gs->local_colormap;
|
||||||
|
else
|
||||||
|
p = gs->hold;
|
||||||
|
memcpy(p, buf, len);
|
||||||
|
gs->bytes_to_consume -= len;
|
||||||
|
}
|
||||||
|
|
||||||
return PR_SUCCESS;
|
return PR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,8 +942,6 @@ void gif_destroy(gif_struct *gs)
|
||||||
gs->delay_time = 0;
|
gs->delay_time = 0;
|
||||||
|
|
||||||
PR_FREEIF(gs->rowbuf);
|
PR_FREEIF(gs->rowbuf);
|
||||||
PR_FREEIF(gs->hold);
|
|
||||||
|
|
||||||
PR_FREEIF(gs->local_colormap);
|
PR_FREEIF(gs->local_colormap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,39 +41,35 @@
|
||||||
#define MAX_BITS 4097 /* 2^MAX_LZW_BITS+1 */
|
#define MAX_BITS 4097 /* 2^MAX_LZW_BITS+1 */
|
||||||
#define MINIMUM_DELAY_TIME 100
|
#define MINIMUM_DELAY_TIME 100
|
||||||
#define MAX_COLORS 256
|
#define MAX_COLORS 256
|
||||||
|
#define MAX_HOLD_SIZE 256
|
||||||
|
|
||||||
/* gif2.h
|
/* gif2.h
|
||||||
The interface for the GIF87/89a decoder.
|
The interface for the GIF87/89a decoder.
|
||||||
*/
|
*/
|
||||||
// List of possible parsing states
|
// List of possible parsing states
|
||||||
typedef enum {
|
typedef enum {
|
||||||
gif_gather,
|
|
||||||
gif_init, //1
|
|
||||||
gif_type,
|
gif_type,
|
||||||
gif_version,
|
|
||||||
gif_global_header,
|
gif_global_header,
|
||||||
gif_global_colormap,
|
gif_global_colormap,
|
||||||
gif_image_start, //6
|
gif_image_start,
|
||||||
gif_image_header,
|
gif_image_header,
|
||||||
gif_image_colormap,
|
gif_image_colormap,
|
||||||
gif_image_body,
|
gif_image_body,
|
||||||
gif_lzw_start,
|
gif_lzw_start,
|
||||||
gif_lzw, //11
|
gif_lzw,
|
||||||
gif_sub_block,
|
gif_sub_block,
|
||||||
gif_extension,
|
gif_extension,
|
||||||
gif_control_extension,
|
gif_control_extension,
|
||||||
gif_consume_block,
|
gif_consume_block,
|
||||||
gif_skip_block,
|
gif_skip_block,
|
||||||
gif_done, //17
|
gif_done,
|
||||||
gif_oom,
|
gif_oom,
|
||||||
gif_error,
|
gif_error,
|
||||||
gif_comment_extension,
|
gif_comment_extension,
|
||||||
gif_application_extension,
|
gif_application_extension,
|
||||||
gif_netscape_extension_block,
|
gif_netscape_extension_block,
|
||||||
gif_consume_netscape_extension,
|
gif_consume_netscape_extension,
|
||||||
gif_consume_comment,
|
gif_consume_comment
|
||||||
gif_delay,
|
|
||||||
gif_stop_animating //added for animation stop
|
|
||||||
} gstate;
|
} gstate;
|
||||||
|
|
||||||
/* "Disposal" method indicates how the image should be handled in the
|
/* "Disposal" method indicates how the image should be handled in the
|
||||||
|
@ -90,12 +86,9 @@ typedef enum
|
||||||
typedef struct gif_struct {
|
typedef struct gif_struct {
|
||||||
void* clientptr;
|
void* clientptr;
|
||||||
/* Parsing state machine */
|
/* Parsing state machine */
|
||||||
gstate state; /* Curent decoder master state */
|
gstate state; /* Curent decoder master state */
|
||||||
PRUint8 *hold; /* Accumulation buffer */
|
PRUint32 bytes_to_consume; /* Number of bytes to accumulate */
|
||||||
PRUint8 *gather_head; /* Next byte to read in accumulation buffer */
|
PRUint32 bytes_in_hold; /* bytes accumulated so far*/
|
||||||
int32 gather_request_size; /* Number of bytes to accumulate */
|
|
||||||
int32 gathered; /* bytes accumulated so far*/
|
|
||||||
gstate post_gather_state; /* State after requested bytes accumulated */
|
|
||||||
|
|
||||||
/* LZW decoder state machine */
|
/* LZW decoder state machine */
|
||||||
PRUint8 *stackp; /* Current stack pointer */
|
PRUint8 *stackp; /* Current stack pointer */
|
||||||
|
@ -144,6 +137,7 @@ typedef struct gif_struct {
|
||||||
PRPackedBool is_local_colormap_defined;
|
PRPackedBool is_local_colormap_defined;
|
||||||
|
|
||||||
PRUint16 prefix[MAX_BITS]; /* LZW decoding tables */
|
PRUint16 prefix[MAX_BITS]; /* LZW decoding tables */
|
||||||
|
PRUint8 hold[MAX_HOLD_SIZE]; /* Accumulation buffer */
|
||||||
PRUint8 global_colormap[3*MAX_COLORS]; /* Default colormap if local not supplied, 3 bytes for each color */
|
PRUint8 global_colormap[3*MAX_COLORS]; /* Default colormap if local not supplied, 3 bytes for each color */
|
||||||
PRUint8 suffix[MAX_BITS]; /* LZW decoding tables */
|
PRUint8 suffix[MAX_BITS]; /* LZW decoding tables */
|
||||||
PRUint8 stack[MAX_BITS]; /* Base of LZW decoder stack */
|
PRUint8 stack[MAX_BITS]; /* Base of LZW decoder stack */
|
||||||
|
|
|
@ -223,14 +223,9 @@ nsresult nsGIFDecoder2::ProcessData(unsigned char *data, PRUint32 count, PRUint3
|
||||||
{
|
{
|
||||||
// Push the data to the GIF decoder
|
// Push the data to the GIF decoder
|
||||||
|
|
||||||
// First we ask if the gif decoder is ready for more data, and if so, push it.
|
PRStatus result = gif_write(mGIFStruct, data, count);
|
||||||
// In the new decoder, we should always be able to process more data since
|
if (result != PR_SUCCESS)
|
||||||
// we don't wait to decode each frame in an animation now.
|
return NS_ERROR_FAILURE;
|
||||||
if (gif_write_ready(mGIFStruct)) {
|
|
||||||
PRStatus result = gif_write(mGIFStruct, data, count);
|
|
||||||
if (result != PR_SUCCESS)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mImageFrame && mObserver) {
|
if (mImageFrame && mObserver) {
|
||||||
FlushImageData();
|
FlushImageData();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче