mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-23 23:09:39 +03:00
[project @ 2004-05-10 22:14:33 by rjw]
Added support for NETSCAPE2.0 application extension for limited looping. GIF decoding attempts all images, irrespective of whether they adhere to the GIF87/GIF89a spec. Disabled logging. svn path=/import/netsurf/; revision=849
This commit is contained in:
parent
7fa938d09c
commit
47ab606edf
23
riscos/gif.c
23
riscos/gif.c
@ -161,15 +161,30 @@ void nsgif_animate(void *p)
|
||||
{
|
||||
struct content *c = p;
|
||||
union content_msg_data data;
|
||||
|
||||
/* at the moment just advance by one frame */
|
||||
|
||||
/* Advance by a frame, updating the loop count accordingly
|
||||
*/
|
||||
c->data.gif.current_frame++;
|
||||
if (c->data.gif.current_frame == c->data.gif.gif->frame_count) {
|
||||
c->data.gif.current_frame = 0;
|
||||
|
||||
/* A loop count of 0 has a special meaning of infinite
|
||||
*/
|
||||
if (c->data.gif.gif->loop_count != 0) {
|
||||
c->data.gif.gif->loop_count--;
|
||||
if (c->data.gif.gif->loop_count == 0) {
|
||||
c->data.gif.gif->loop_count = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schedule(c->data.gif.gif->frames[c->data.gif.current_frame].frame_delay,
|
||||
nsgif_animate, c);
|
||||
|
||||
/* Continue animating if we should
|
||||
*/
|
||||
if (c->data.gif.gif->loop_count >= 0) {
|
||||
schedule(c->data.gif.gif->frames[c->data.gif.current_frame].frame_delay,
|
||||
nsgif_animate, c);
|
||||
}
|
||||
|
||||
/* area within gif to redraw */
|
||||
data.redraw.x = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_x;
|
||||
|
140
riscos/gifread.c
140
riscos/gifread.c
@ -17,21 +17,21 @@
|
||||
|
||||
/* READING GIF FILES
|
||||
=================
|
||||
|
||||
|
||||
The functions provided by this file allow for efficient progressive GIF
|
||||
decoding. Whilst the initialisation does not ensure that there is
|
||||
sufficient image data to complete the entire frame, it does ensure that
|
||||
the information provided is valid. Any subsequent attempts to decode an
|
||||
initialised GIF are guaranteed to succeed, and any bytes of the image
|
||||
not present are assumed to be totally transparent.
|
||||
|
||||
|
||||
To begin decoding a GIF, the 'gif' structure must be initialised with
|
||||
the 'gif_data' and 'buffer_size' set to their initial values. The
|
||||
'buffer_position' should initially be 0, and will be internally updated
|
||||
as the decoding commences. The caller should then repeatedly call
|
||||
gif_initialise() with the structure until the function returns 1, or
|
||||
no more data is avaliable.
|
||||
|
||||
|
||||
Once the initialisation has begun, the decoder completes the variables
|
||||
'frame_count' and 'frame_count_partial'. The former being the total
|
||||
number of frames that have been successfully initialised, and the
|
||||
@ -92,7 +92,7 @@ static int clear_image = FALSE;
|
||||
/* Initialises any workspace held by the animation and attempts to decode
|
||||
any information that hasn't already been decoded.
|
||||
If an error occurs, all previously decoded frames are retained.
|
||||
|
||||
|
||||
@return -5 for GIF frame data error
|
||||
-4 for insufficient data to process any more frames
|
||||
-3 for memory error
|
||||
@ -118,10 +118,6 @@ int gif_initialise(struct gif_animation *gif) {
|
||||
*/
|
||||
if (gif->buffer_position == 0) {
|
||||
|
||||
/* The 12th byte must be a 0 for the block terminator
|
||||
*/
|
||||
// if (gif_data[11] != 0x00) return GIF_DATA_ERROR;
|
||||
|
||||
/* We want everything to be NULL before we start so we've no chance
|
||||
of freeing bad pointers (paranoia)
|
||||
*/
|
||||
@ -129,26 +125,26 @@ int gif_initialise(struct gif_animation *gif) {
|
||||
gif->frames = NULL;
|
||||
gif->local_colour_table = NULL;
|
||||
gif->global_colour_table = NULL;
|
||||
|
||||
|
||||
/* The caller may have been lazy and not reset any values
|
||||
*/
|
||||
gif->frame_count = 0;
|
||||
gif->frame_count_partial = 0;
|
||||
gif->decoded_frame = 0xffffffff;
|
||||
|
||||
|
||||
/* Check we are a GIF
|
||||
*/
|
||||
if (strncmp(gif_data, "GIF", 3) != 0) {
|
||||
LOG(("Invalid GIF header - should be 'GIF'"));
|
||||
// LOG(("Invalid GIF header - should be 'GIF'"));
|
||||
return GIF_DATA_ERROR;
|
||||
}
|
||||
gif_data += 3;
|
||||
|
||||
|
||||
/* Check we are a GIF type 87a or 89a
|
||||
*/
|
||||
if ((strncmp(gif_data, "87a", 3) != 0) &&
|
||||
(strncmp(gif_data, "89a", 3) != 0)) {
|
||||
LOG(("Unknown GIF format - proceeding anyway"));
|
||||
// LOG(("Unknown GIF format - proceeding anyway"));
|
||||
}
|
||||
gif_data += 3;
|
||||
|
||||
@ -161,8 +157,9 @@ int gif_initialise(struct gif_animation *gif) {
|
||||
gif->background_colour = gif_data[5];
|
||||
gif->aspect_ratio = gif_data[6];
|
||||
gif->dirty_frame = -1;
|
||||
gif->loop_count = 0;
|
||||
gif_data += 7;
|
||||
|
||||
|
||||
/* Allocate some data irrespective of whether we've got any colour tables. We
|
||||
always get the maximum size in case a GIF is lying to us. It's far better
|
||||
to give the wrong colours than to trample over some memory somewhere.
|
||||
@ -173,7 +170,7 @@ int gif_initialise(struct gif_animation *gif) {
|
||||
gif_finalise(gif);
|
||||
return GIF_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
/* Set the first colour to a value that will never occur in reality so we
|
||||
know if we've processed it
|
||||
*/
|
||||
@ -233,25 +230,25 @@ int gif_initialise(struct gif_animation *gif) {
|
||||
gif->global_colour_table[1] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Repeatedly try to decode frames
|
||||
*/
|
||||
while ((return_value = gif_initialise_frame(gif)) == 0);
|
||||
|
||||
|
||||
/* If there was a memory error tell the caller
|
||||
*/
|
||||
if ((return_value == GIF_INSUFFICIENT_MEMORY) ||
|
||||
if ((return_value == GIF_INSUFFICIENT_MEMORY) ||
|
||||
(return_value == GIF_DATA_ERROR)) {
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
||||
/* If we didn't have some frames then a GIF_INSUFFICIENT_DATA becomes a
|
||||
GIF_INSUFFICIENT_FRAME_DATA
|
||||
*/
|
||||
if ((return_value == GIF_INSUFFICIENT_DATA) && (gif->frame_count_partial > 0)) {
|
||||
return_value = GIF_INSUFFICIENT_FRAME_DATA;
|
||||
}
|
||||
|
||||
|
||||
/* Return how many we got
|
||||
*/
|
||||
return return_value;
|
||||
@ -260,7 +257,7 @@ int gif_initialise(struct gif_animation *gif) {
|
||||
|
||||
|
||||
/** Updates the sprite memory size
|
||||
|
||||
|
||||
@return -3 for a memory error
|
||||
0 for success
|
||||
*/
|
||||
@ -275,11 +272,11 @@ static int gif_initialise_sprite(struct gif_animation *gif, unsigned int width,
|
||||
if ((width <= gif->width) && (height <= gif->height)) return 0;
|
||||
|
||||
/* Get our maximum values
|
||||
*/
|
||||
*/
|
||||
max_width = (width > gif->width) ? width : gif->width;
|
||||
max_height = (height > gif->height) ? height : gif->height;
|
||||
frame_bytes = max_width * max_height * 4 + sizeof(osspriteop_header);
|
||||
|
||||
|
||||
/* Allocate some more memory
|
||||
*/
|
||||
if ((buffer = (osspriteop_header *)realloc(gif->frame_image, frame_bytes)) == NULL) {
|
||||
@ -291,7 +288,7 @@ static int gif_initialise_sprite(struct gif_animation *gif, unsigned int width,
|
||||
*/
|
||||
gif->width = max_width;
|
||||
gif->height = max_height;
|
||||
|
||||
|
||||
/* Update our sprite image
|
||||
*/
|
||||
buffer->size = frame_bytes;
|
||||
@ -306,7 +303,7 @@ static int gif_initialise_sprite(struct gif_animation *gif, unsigned int width,
|
||||
|
||||
|
||||
/* Attempts to initialise the next frame
|
||||
|
||||
|
||||
@return -4 for insufficient data to process the entire frame
|
||||
-3 for a memory error
|
||||
-2 for a data error
|
||||
@ -363,19 +360,18 @@ int gif_initialise_frame(struct gif_animation *gif) {
|
||||
*/
|
||||
gif->frame_holders = frame + 1;
|
||||
}
|
||||
|
||||
|
||||
/* Store our frame pointer. We would do it when allocating except we
|
||||
start off with one frame allocated so we can always use realloc.
|
||||
*/
|
||||
// LOG(("Set frame number %i to offset %i", frame, gif->buffer_position));
|
||||
gif->frames[frame].frame_pointer = gif->buffer_position;
|
||||
gif->frames[frame].frame_delay = 100; // Paranoia
|
||||
gif->frames[frame].redraw_required = 0; // Paranoia
|
||||
|
||||
|
||||
/* Invalidate any previous decoding we have of this frame
|
||||
*/
|
||||
if (gif->decoded_frame == frame) gif->decoded_frame = 0xffffffff;
|
||||
|
||||
|
||||
/* We pretend to initialise the frames, but really we just skip over all
|
||||
the data contained within. This is all basically a cut down version of
|
||||
gif_decode_frame that doesn't have any of the LZW bits in it.
|
||||
@ -383,11 +379,11 @@ int gif_initialise_frame(struct gif_animation *gif) {
|
||||
more_images = 1;
|
||||
first_image = 1;
|
||||
while (more_images != 0) {
|
||||
|
||||
|
||||
/* Ensure we have some data
|
||||
*/
|
||||
if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
|
||||
|
||||
/* Decode the extensions
|
||||
*/
|
||||
background_action = 0;
|
||||
@ -395,41 +391,52 @@ int gif_initialise_frame(struct gif_animation *gif) {
|
||||
/* Get the extension size
|
||||
*/
|
||||
extension_size = gif_data[2];
|
||||
|
||||
|
||||
/* Check we've enough data for the extension then header
|
||||
*/
|
||||
if ((gif_end - gif_data) < (int)(extension_size + 13)) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
|
||||
/* Graphic control extension - store the frame delay.
|
||||
*/
|
||||
if (gif_data[1] == 0xf9) {
|
||||
gif->frames[frame].frame_delay = gif_data[4] | (gif_data[5] << 8);
|
||||
background_action = ((gif_data[3] & 0x1c) >> 2);
|
||||
more_images = ((gif->frames[frame].frame_delay) == 0);
|
||||
|
||||
/* Application extension - handle NETSCAPE2.0 looping
|
||||
*/
|
||||
} else if ((gif_data[1] == 0xff) &&
|
||||
(gif_data[2] == 0x0b) &&
|
||||
(strncmp(gif_data + 3, "NETSCAPE2.0", 11) == 0) &&
|
||||
(gif_data[14] == 0x03) &&
|
||||
(gif_data[15] == 0x01)) {
|
||||
gif->loop_count = gif_data[16] | (gif_data[17] << 8);
|
||||
}
|
||||
|
||||
/* Move to the first sub-block
|
||||
*/
|
||||
gif_data += 2;
|
||||
|
||||
|
||||
/* Skip all the sub-blocks
|
||||
*/
|
||||
while (gif_data[0] != 0x00) {
|
||||
gif_data += gif_data[0] + 1;
|
||||
if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
}
|
||||
gif_data++;
|
||||
}
|
||||
|
||||
|
||||
/* We must have at least one image descriptor
|
||||
*/
|
||||
if (gif_data[0] != 0x2c) return GIF_FRAME_DATA_ERROR;
|
||||
|
||||
|
||||
/* Do some simple boundary checking
|
||||
*/
|
||||
offset_x = gif_data[1] | (gif_data[2] << 8);
|
||||
offset_y = gif_data[3] | (gif_data[4] << 8);
|
||||
width = gif_data[5] | (gif_data[6] << 8);
|
||||
height = gif_data[7] | (gif_data[8] << 8);
|
||||
|
||||
|
||||
/* Set up the redraw characteristics. We have to check for extending the area
|
||||
due to multi-image frames.
|
||||
*/
|
||||
@ -462,34 +469,34 @@ int gif_initialise_frame(struct gif_animation *gif) {
|
||||
if (gif_initialise_sprite(gif, (offset_x + width), (offset_y + height))) {
|
||||
return GIF_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
/* Decode the flags
|
||||
*/
|
||||
flags = gif_data[9];
|
||||
colour_table_size = 2 << (flags & 0x07);
|
||||
|
||||
|
||||
/* Move our data onwards and remember we've got a bit of this frame
|
||||
*/
|
||||
gif_data += 10;
|
||||
gif_bytes = (gif_end - gif_data);
|
||||
gif->frame_count_partial = frame + 1;
|
||||
|
||||
|
||||
/* Skip the local colour table
|
||||
*/
|
||||
if (flags & 0x80) {
|
||||
gif_data += 3 * colour_table_size;
|
||||
if ((gif_bytes = (gif_end - gif_data)) < 0) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure we have a correct code size
|
||||
*/
|
||||
if (gif_data[0] > GIF_MAX_LZW) return GIF_DATA_ERROR;
|
||||
|
||||
|
||||
/* Move our data onwards
|
||||
*/
|
||||
gif_data++;
|
||||
if (--gif_bytes < 0) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
|
||||
|
||||
/* Repeatedly skip blocks until we get a zero block or run out of data
|
||||
*/
|
||||
block_size = 0;
|
||||
@ -512,7 +519,7 @@ int gif_initialise_frame(struct gif_animation *gif) {
|
||||
return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
} else {
|
||||
gif->buffer_position = gif_data - gif->gif_data;
|
||||
gif->frame_count = frame + 1;
|
||||
gif->frame_count = frame + 1;
|
||||
if (gif_data[0] == 0x3b) return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -551,7 +558,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
*/
|
||||
if (frame > gif->frame_count_partial) return GIF_INSUFFICIENT_DATA;
|
||||
if ((!clear_image) && (frame == gif->decoded_frame)) return 0;
|
||||
|
||||
|
||||
/* If the previous frame was dirty, remove it
|
||||
*/
|
||||
if (!clear_image) {
|
||||
@ -562,7 +569,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
}
|
||||
gif->dirty_frame = -1;
|
||||
}
|
||||
|
||||
|
||||
/* Get the start of our frame data and the end of the GIF data
|
||||
*/
|
||||
gif_data = gif->gif_data + gif->frames[frame].frame_pointer;
|
||||
@ -589,18 +596,18 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
*/
|
||||
save_buffer_position = gif->buffer_position;
|
||||
gif->buffer_position = gif_data - gif->gif_data;
|
||||
|
||||
|
||||
/* We've got to do this more than one time if we've got multiple images
|
||||
*/
|
||||
more_images = 1;
|
||||
while (more_images != 0) {
|
||||
background_action = 0;
|
||||
|
||||
|
||||
/* Ensure we have some data
|
||||
*/
|
||||
gif_data = gif->gif_data + gif->buffer_position;
|
||||
if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
|
||||
|
||||
/* Decode the extensions
|
||||
*/
|
||||
while (gif_data[0] == 0x21) {
|
||||
@ -608,7 +615,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
/* Get the extension size
|
||||
*/
|
||||
extension_size = gif_data[2];
|
||||
|
||||
|
||||
/* Check we've enough data for the extension then header
|
||||
*/
|
||||
if ((gif_end - gif_data) < (int)(extension_size + 13)) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
@ -624,12 +631,12 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
/* Move to the first sub-block
|
||||
*/
|
||||
gif_data += 2;
|
||||
|
||||
|
||||
/* Skip all the sub-blocks
|
||||
*/
|
||||
while (gif_data[0] != 0x00) {
|
||||
gif_data += gif_data[0] + 1;
|
||||
if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
}
|
||||
gif_data++;
|
||||
}
|
||||
@ -648,7 +655,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
if ((offset_x + width > gif->width) || (offset_y + height > gif->height)) {
|
||||
return GIF_DATA_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Decode the flags
|
||||
*/
|
||||
flags = gif_data[9];
|
||||
@ -659,7 +666,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
*/
|
||||
gif_data += 10;
|
||||
gif_bytes = (int)(gif_end - gif_data);
|
||||
|
||||
|
||||
/* Set up the colour table
|
||||
*/
|
||||
if (flags & 0x80) {
|
||||
@ -687,7 +694,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
if ((background_action == 2) || (background_action == 3)) {
|
||||
gif->dirty_frame = frame;
|
||||
}
|
||||
|
||||
|
||||
/* Initialise the LZW decoding
|
||||
*/
|
||||
set_code_size = gif_data[0];
|
||||
@ -725,7 +732,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
} else {
|
||||
return_value = GIF_INSUFFICIENT_FRAME_DATA;
|
||||
goto gif_decode_frame_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -737,7 +744,7 @@ int gif_decode_frame(struct gif_animation *gif, unsigned int frame) {
|
||||
memset(frame_scanline, 0x00, width * 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Repeatedly skip blocks until we get a zero block or run out of data
|
||||
*/
|
||||
gif_bytes = gif->buffer_size - gif->buffer_position;
|
||||
@ -786,14 +793,13 @@ static unsigned int gif_interlaced_line(unsigned int height, unsigned int y) {
|
||||
/* Releases any workspace held by the animation
|
||||
*/
|
||||
void gif_finalise(struct gif_animation *gif) {
|
||||
LOG(("Finalising image"));
|
||||
/* Release all our memory blocks
|
||||
*/
|
||||
free(gif->frame_image);
|
||||
gif->frame_image = NULL;
|
||||
free(gif->frames);
|
||||
gif->frames = NULL;
|
||||
free(gif->local_colour_table);
|
||||
free(gif->local_colour_table);
|
||||
gif->local_colour_table = NULL;
|
||||
free(gif->global_colour_table);
|
||||
gif->global_colour_table = NULL;
|
||||
@ -811,7 +817,7 @@ static int gif_next_LZW(struct gif_animation *gif) {
|
||||
/* Check we have a valid clear code
|
||||
*/
|
||||
if (clear_code >= (1 << GIF_MAX_LZW)) return -2;
|
||||
|
||||
|
||||
/* Initialise our table
|
||||
*/
|
||||
for (i = 0; i < (unsigned int)clear_code; ++i) {
|
||||
@ -821,7 +827,7 @@ static int gif_next_LZW(struct gif_animation *gif) {
|
||||
for (; i < (1 << GIF_MAX_LZW); ++i) {
|
||||
table[0][i] = table[1][i] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Update our LZW parameters
|
||||
*/
|
||||
code_size = set_code_size + 1;
|
||||
@ -860,7 +866,7 @@ static int gif_next_LZW(struct gif_animation *gif) {
|
||||
if (code == table[0][code]) return(code);
|
||||
if (((char *)stack_pointer - (char *)stack) >= (int)sizeof(stack)) return(code);
|
||||
code = table[0][code];
|
||||
}
|
||||
}
|
||||
|
||||
*stack_pointer++ = firstcode = table[1][code];
|
||||
|
||||
@ -872,7 +878,7 @@ static int gif_next_LZW(struct gif_animation *gif) {
|
||||
max_code_size *= 2;
|
||||
++code_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oldcode = incode;
|
||||
|
||||
@ -906,7 +912,7 @@ static int gif_next_code(struct gif_animation *gif, int code_size) {
|
||||
lastbit = (2 + count) * 8;
|
||||
end = curbit + code_size;
|
||||
}
|
||||
|
||||
|
||||
j = end / 8;
|
||||
i = curbit / 8;
|
||||
if (i == j) {
|
||||
@ -916,7 +922,7 @@ static int gif_next_code(struct gif_animation *gif, int code_size) {
|
||||
} else {
|
||||
ret = (long)buf[i] | ((long)buf[i+1] << 8) | ((long)buf[i+2] << 16);
|
||||
}
|
||||
|
||||
|
||||
ret = (ret >> (curbit % 8)) & maskTbl[code_size];
|
||||
curbit += code_size;
|
||||
return (int)ret;
|
||||
@ -925,12 +931,12 @@ static int gif_next_code(struct gif_animation *gif, int code_size) {
|
||||
static int gif_next_block(struct gif_animation *gif, unsigned char *buf) {
|
||||
unsigned int block_size;
|
||||
unsigned char *gif_data;
|
||||
|
||||
|
||||
gif_data = gif->gif_data + gif->buffer_position;
|
||||
zero_data_block = ((block_size = gif_data[0]) == 0);
|
||||
|
||||
if ((gif->buffer_position + block_size) >= gif->buffer_size) {
|
||||
LOG(("Insufficient data to read %i bytes", block_size));
|
||||
// LOG(("Insufficient data to read %i bytes", block_size));
|
||||
return -1;
|
||||
}
|
||||
if (block_size > 0) memcpy(buf, gif_data + 1, block_size);
|
||||
|
Loading…
Reference in New Issue
Block a user