summaryrefslogtreecommitdiff
path: root/src/libnsgif.c
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2021-04-02 12:34:35 +0100
committerMichael Drake <tlsa@netsurf-browser.org>2021-04-06 09:03:19 +0100
commit270155287a0f2e7788253a38178efefb608ffdd5 (patch)
treeaf8e07fe1b2de3e902c782247fed0ca128fb53d8 /src/libnsgif.c
parentdef4cda3550f2f3e661fecf897447e0409e3ca15 (diff)
downloadlibnsgif-270155287a0f2e7788253a38178efefb608ffdd5.tar.gz
libnsgif-270155287a0f2e7788253a38178efefb608ffdd5.tar.bz2
gif: Split out gif frame data decode.
Diffstat (limited to 'src/libnsgif.c')
-rw-r--r--src/libnsgif.c141
1 files changed, 82 insertions, 59 deletions
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 512ebfe..ed394a2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -623,6 +623,83 @@ static gif_result gif__recover_previous_frame(const gif_animation *gif)
return GIF_OK;
}
+static inline gif_result
+gif__decode(gif_animation *gif,
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
+{
+ const uint8_t *stack_base;
+ const uint8_t *stack_pos;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size, &stack_base, &stack_pos);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ for (unsigned int y = 0; y < height; y++) {
+ unsigned int x;
+ unsigned int decode_y;
+ unsigned int *frame_scanline;
+
+ if (interlace) {
+ decode_y = gif_interlaced_line(height, y) + offset_y;
+ } else {
+ decode_y = y + offset_y;
+ }
+ frame_scanline = frame_data + offset_x + (decode_y * gif->width);
+
+ /* Rather than decoding pixel by pixel, we try to burst
+ * out streams of data to remove the need for end-of
+ * data checks every pixel.
+ */
+ x = width;
+ while (x > 0) {
+ unsigned int burst_bytes = (stack_pos - stack_base);
+ if (burst_bytes > 0) {
+ if (burst_bytes > x) {
+ burst_bytes = x;
+ }
+ x -= burst_bytes;
+ while (burst_bytes-- > 0) {
+ register unsigned char colour;
+ colour = *--stack_pos;
+ if (((gif->frames[frame].transparency) &&
+ (colour != gif->frames[frame].transparency_index)) ||
+ (!gif->frames[frame].transparency)) {
+ *frame_scanline = colour_table[colour];
+ }
+ frame_scanline++;
+ }
+ } else {
+ res = lzw_decode(gif->lzw_ctx, &stack_pos);
+ if (res != LZW_OK) {
+ /* Unexpected end of frame, try to recover */
+ if (res == LZW_OK_EOD) {
+ ret = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
/**
* decode a gif frame
*
@@ -643,11 +720,8 @@ gif_internal_decode_frame(gif_animation *gif,
unsigned int flags, colour_table_size, interlace;
unsigned int *colour_table;
unsigned int *frame_data = 0; // Set to 0 for no warnings
- unsigned int *frame_scanline;
unsigned int save_buffer_position;
unsigned int return_value = 0;
- unsigned int x, y, decode_y, burst_bytes;
- register unsigned char colour;
/* Ensure this frame is supposed to be decoded */
if (gif->frames[frame].display == false) {
@@ -801,10 +875,6 @@ gif_internal_decode_frame(gif_animation *gif,
/* If we are clearing the image we just clear, if not decode */
if (!clear_image) {
- lzw_result res;
- const uint8_t *stack_base;
- const uint8_t *stack_pos;
-
/* Ensure we have enough data for a 1-byte LZW code size +
* 1-byte gif trailer
*/
@@ -868,62 +938,15 @@ gif_internal_decode_frame(gif_animation *gif,
gif->decoded_frame = frame;
gif->buffer_position = (gif_data - gif->gif_data) + 1;
- /* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- gif_data[0], &stack_base, &stack_pos);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
-
- /* Decompress the data */
- for (y = 0; y < height; y++) {
- if (interlace) {
- decode_y = gif_interlaced_line(height, y) + offset_y;
- } else {
- decode_y = y + offset_y;
- }
- frame_scanline = frame_data + offset_x + (decode_y * gif->width);
-
- /* Rather than decoding pixel by pixel, we try to burst
- * out streams of data to remove the need for end-of
- * data checks every pixel.
- */
- x = width;
- while (x > 0) {
- burst_bytes = (stack_pos - stack_base);
- if (burst_bytes > 0) {
- if (burst_bytes > x) {
- burst_bytes = x;
- }
- x -= burst_bytes;
- while (burst_bytes-- > 0) {
- colour = *--stack_pos;
- if (((gif->frames[frame].transparency) &&
- (colour != gif->frames[frame].transparency_index)) ||
- (!gif->frames[frame].transparency)) {
- *frame_scanline = colour_table[colour];
- }
- frame_scanline++;
- }
- } else {
- res = lzw_decode(gif->lzw_ctx, &stack_pos);
- if (res != LZW_OK) {
- /* Unexpected end of frame, try to recover */
- if (res == LZW_OK_EOD) {
- return_value = GIF_OK;
- } else {
- return_value = gif_error_from_lzw(res);
- }
- goto gif_decode_frame_exit;
- }
- }
- }
- }
+ return_value = gif__decode(gif, frame, width, height,
+ offset_x, offset_y, interlace, gif_data[0],
+ frame_data, colour_table);
} else {
/* Clear our frame */
if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) {
+ unsigned int y;
for (y = 0; y < height; y++) {
+ unsigned int *frame_scanline;
frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width);
if (gif->frames[frame].transparency) {
memset(frame_scanline,