Gitweb links:

...log 
http://git.netsurf-browser.org/libnsgif.git/shortlog/eca5a0cf19e5d9efab647c6a6d537c4827553ea1
...commit 
http://git.netsurf-browser.org/libnsgif.git/commit/eca5a0cf19e5d9efab647c6a6d537c4827553ea1
...tree 
http://git.netsurf-browser.org/libnsgif.git/tree/eca5a0cf19e5d9efab647c6a6d537c4827553ea1

The branch, tlsa/lzw-optimise has been created
        at  eca5a0cf19e5d9efab647c6a6d537c4827553ea1 (commit)

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=eca5a0cf19e5d9efab647c6a6d537c4827553ea1
commit eca5a0cf19e5d9efab647c6a6d537c4827553ea1
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    WIP: lzw: Direct output into frame data, avoiding stack.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index cdd5b6b..fb2577c 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -641,8 +641,8 @@ static gif_result gif__recover_previous_frame(const 
gif_animation *gif)
         return GIF_OK;
 }
 
-static inline gif_result
-gif__decode(gif_animation *gif,
+static gif_result
+gif__decode_complex(gif_animation *gif,
                 unsigned int frame,
                 unsigned int width,
                 unsigned int height,
@@ -716,6 +716,85 @@ gif__decode(gif_animation *gif,
         return ret;
 }
 
+static gif_result
+gif__decode_simple(gif_animation *gif,
+                unsigned int frame,
+                unsigned int height,
+                unsigned int offset_y,
+                uint8_t minimum_code_size,
+                unsigned int *restrict frame_data,
+                unsigned int *restrict colour_table)
+{
+        unsigned int transparency_index;
+        uint32_t pixels = gif->width * height;
+        uint32_t written = 0;
+        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);
+        if (res != LZW_OK) {
+                return gif_error_from_lzw(res);
+        }
+
+        transparency_index = gif->frames[frame].transparency ?
+                        gif->frames[frame].transparency_index :
+                        GIF_NO_TRANSPARENCY;
+
+        frame_data += (offset_y * gif->width);
+
+        while (pixels > 0) {
+                res = lzw_decode_map_continuous(gif->lzw_ctx,
+                                transparency_index, colour_table,
+                                frame_data, pixels, &written);
+                pixels -= written;
+                frame_data += written;
+                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;
+                }
+        }
+
+        if (pixels == 0) {
+                ret = GIF_OK;
+        }
+
+        return ret;
+}
+
+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)
+{
+        gif_result ret;
+
+        if (interlace == false && width == gif->width && offset_x == 0) {
+                ret = gif__decode_simple(gif, frame, height, offset_y,
+                                minimum_code_size, frame_data, colour_table);
+        } else {
+                ret = gif__decode_complex(gif, frame, width, height,
+                                offset_x, offset_y, interlace,
+                                minimum_code_size, frame_data, colour_table);
+        }
+
+        return ret;
+}
+
 /**
  * decode a gif frame
  *
diff --git a/src/lzw.c b/src/lzw.c
index 2f604e4..d555151 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -85,6 +85,9 @@ struct lzw_ctx {
        uint32_t output_code; /**< Code that has been partially output. */
        uint32_t output_left; /**< Number of values left for output_code. */
 
+       uint32_t transparency_index;
+       uint32_t *restrict colour_table;
+
        /** Output value stack. */
        uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
 
@@ -345,6 +348,54 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx 
*ctx,
        return count;
 }
 
+
+/**
+ * Write values for this code to the output stack.
+ *
+ * \param[in]  ctx   LZW reading context, updated.
+ * \param[in]  code  LZW code to output values for.
+ * \return Number of pixel values written.
+ */
+static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
+               void *buffer,
+               uint32_t length,
+               uint32_t used,
+               uint32_t code,
+               uint32_t left)
+{
+       uint32_t *stack_pos = (uint32_t *)buffer + used;
+       struct lzw_table_entry * const table = ctx->table;
+       uint32_t space = length - used;
+       uint32_t count = left;
+
+       if (count > space) {
+               left = count - space;
+               count = space;
+       } else {
+               left = 0;
+       }
+
+       ctx->output_code = code;
+       ctx->output_left = left;
+
+       for (unsigned i = left; i != 0; i--) {
+               struct lzw_table_entry *entry = table + code;
+               code = entry->extends;
+       }
+
+       stack_pos += count;
+       for (unsigned i = count; i != 0; i--) {
+               struct lzw_table_entry *entry = table + code;
+               --stack_pos;
+               if (entry->value != ctx->transparency_index) {
+                       *stack_pos = ctx->colour_table[entry->value];
+               }
+               code = entry->extends;
+       }
+
+       return count;
+}
+
 /**
  * Fill the LZW stack with decompressed data
  *
@@ -452,3 +503,32 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
 
        return LZW_OK;
 }
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+               uint32_t transparency_index,
+               uint32_t *restrict colour_table,
+               uint32_t *restrict data,
+               uint32_t length,
+               uint32_t *restrict used)
+{
+       *used = 0;
+
+       ctx->transparency_index = transparency_index;
+       ctx->colour_table = colour_table;
+
+       if (ctx->output_left != 0) {
+               *used += lzw__write_pixels_map(ctx, data, length, *used,
+                               ctx->output_code, ctx->output_left);
+       }
+
+       while (*used != sizeof(ctx->stack_base)) {
+               lzw_result res = lzw__decode(ctx, data, length,
+                               lzw__write_pixels_map, used);
+               if (res != LZW_OK) {
+                       return res;
+               }
+       }
+
+       return LZW_OK;
+}
diff --git a/src/lzw.h b/src/lzw.h
index ec7709a..9dbcac0 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -106,4 +106,22 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
                const uint8_t ** const data,
                uint32_t *used);
 
+/**
+ * Read LZW codes, mapping output to colours.
+ *
+ * Ensure anything on the stack is used before calling this, as anything
+ * on the stack before this call will be trampled.
+ *
+ * \param[in]  ctx   LZW reading context, updated.
+ * \param[out] data  Returns pointer to array of output values.
+ * \param[out] used  Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+               uint32_t transparency_index,
+               uint32_t *restrict colour_table,
+               uint32_t *restrict data,
+               uint32_t length,
+               uint32_t *restrict used);
+
 #endif


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=b3ebed6297bb797c1af45b33b448514bf05c46e5
commit b3ebed6297bb797c1af45b33b448514bf05c46e5
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    gif: Handle any uncompressed output before exiting due to error.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 60209de..cdd5b6b 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -687,8 +687,6 @@ gif__decode(gif_animation *gif,
                         const uint8_t *uncompressed;
                         unsigned row_available;
                         if (available == 0) {
-                                res = lzw_decode(gif->lzw_ctx,
-                                                &uncompressed, &available);
                                 if (res != LZW_OK) {
                                         /* Unexpected end of frame, try to 
recover */
                                         if (res == LZW_OK_EOD) {
@@ -698,6 +696,8 @@ gif__decode(gif_animation *gif,
                                         }
                                         break;
                                 }
+                                res = lzw_decode(gif->lzw_ctx,
+                                                &uncompressed, &available);
                         }
 
                         row_available = x < available ? x : available;


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=18afa8d0048c86216643ab2e883503ab4c413f38
commit 18afa8d0048c86216643ab2e883503ab4c413f38
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Add function for decoding multiple LZW codes at a time.

diff --git a/src/lzw.c b/src/lzw.c
index 8c8911a..2f604e4 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -426,3 +426,29 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
                        lzw__write_pixels, used);
 }
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+               const uint8_t ** const data,
+               uint32_t *used)
+{
+       *used = 0;
+       *data = ctx->stack_base;
+
+       if (ctx->output_left != 0) {
+               *used += lzw__write_pixels(ctx,
+                               ctx->stack_base, sizeof(ctx->stack_base), *used,
+                               ctx->output_code, ctx->output_left);
+       }
+
+       while (*used != sizeof(ctx->stack_base)) {
+               lzw_result res = lzw__decode(ctx,
+                               ctx->stack_base, sizeof(ctx->stack_base),
+                               lzw__write_pixels, used);
+               if (res != LZW_OK) {
+                       return res;
+               }
+       }
+
+       return LZW_OK;
+}
diff --git a/src/lzw.h b/src/lzw.h
index 4b6bfab..ec7709a 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -91,4 +91,19 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
                const uint8_t ** const data,
                uint32_t *used);
 
+/**
+ * Read input codes until end of input or output buffer is full.
+ *
+ * Ensure anything on the stack is used before calling this, as anything
+ * on the stack before this call will be trampled.
+ *
+ * \param[in]  ctx   LZW reading context, updated.
+ * \param[out] data  Returns pointer to array of output values.
+ * \param[out] used  Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+               const uint8_t ** const data,
+               uint32_t *used);
+
 #endif


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=c8f094505a7d53997ef8f8b2d05fc114eee9315b
commit c8f094505a7d53997ef8f8b2d05fc114eee9315b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    f

diff --git a/src/lzw.h b/src/lzw.h
index 2e82869..4b6bfab 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -77,15 +77,14 @@ lzw_result lzw_decode_init(
                uint8_t minimum_code_size);
 
 /**
- * Fill the LZW stack with decompressed data
+ * Read a single LZW code into the output buffer.
  *
  * Ensure anything on the stack is used before calling this, as anything
  * on the stack before this call will be trampled.
  *
- * \param[in]  ctx      LZW reading context, updated.
- * \param[out] written  Returns the number of values written.
- *                      Use with `stack_base_out` value from previous
- *                      lzw_decode_init() call.
+ * \param[in]  ctx   LZW reading context, updated.
+ * \param[out] data  Returns pointer to array of output values.
+ * \param[out] used  Returns the number of values written to data.
  * \return LZW_OK on success, or appropriate error code otherwise.
  */
 lzw_result lzw_decode(struct lzw_ctx *ctx,


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=3f760807f71ffef44a6ac36d0eb0c09c65ad90ba
commit 3f760807f71ffef44a6ac36d0eb0c09c65ad90ba
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Return output pointer from decode rather than init.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 050a961..60209de 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -654,8 +654,6 @@ gif__decode(gif_animation *gif,
                 unsigned int *restrict colour_table)
 {
         unsigned int transparency_index;
-        const uint8_t *stack_base;
-        const uint8_t *stack_pos;
         uint32_t available = 0;
         gif_result ret = GIF_OK;
         lzw_result res;
@@ -663,7 +661,7 @@ gif__decode(gif_animation *gif,
         /* 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);
+                        minimum_code_size);
         if (res != LZW_OK) {
                 return gif_error_from_lzw(res);
         }
@@ -672,7 +670,6 @@ gif__decode(gif_animation *gif,
                         gif->frames[frame].transparency_index :
                         GIF_NO_TRANSPARENCY;
 
-        stack_pos = stack_base;
         for (unsigned int y = 0; y < height; y++) {
                 unsigned int x;
                 unsigned int decode_y;
@@ -687,9 +684,11 @@ gif__decode(gif_animation *gif,
 
                 x = width;
                 while (x > 0) {
+                        const uint8_t *uncompressed;
                         unsigned row_available;
                         if (available == 0) {
-                                res = lzw_decode(gif->lzw_ctx, &available);
+                                res = lzw_decode(gif->lzw_ctx,
+                                                &uncompressed, &available);
                                 if (res != LZW_OK) {
                                         /* Unexpected end of frame, try to 
recover */
                                         if (res == LZW_OK_EOD) {
@@ -699,7 +698,6 @@ gif__decode(gif_animation *gif,
                                         }
                                         break;
                                 }
-                                stack_pos = stack_base;
                         }
 
                         row_available = x < available ? x : available;
@@ -707,7 +705,7 @@ gif__decode(gif_animation *gif,
                         available -= row_available;
                         while (row_available-- > 0) {
                                 register unsigned int colour;
-                                colour = *stack_pos++;
+                                colour = *uncompressed++;
                                 if (colour != transparency_index) {
                                         *frame_scanline = colour_table[colour];
                                 }
diff --git a/src/lzw.c b/src/lzw.c
index d3e0dcf..8c8911a 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -82,6 +82,9 @@ struct lzw_ctx {
 
        uint32_t table_size; /**< Next position in table to fill. */
 
+       uint32_t output_code; /**< Code that has been partially output. */
+       uint32_t output_left; /**< Number of values left for output_code. */
+
        /** Output value stack. */
        uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
 
@@ -241,8 +244,7 @@ lzw_result lzw_decode_init(
                const uint8_t *compressed_data,
                uint32_t compressed_data_len,
                uint32_t compressed_data_pos,
-               uint8_t minimum_code_size,
-               const uint8_t ** const stack_base_out)
+               uint8_t minimum_code_size)
 {
        struct lzw_table_entry *table = ctx->table;
 
@@ -264,6 +266,8 @@ lzw_result lzw_decode_init(
        ctx->clear_code = (1 << minimum_code_size) + 0;
        ctx->eoi_code   = (1 << minimum_code_size) + 1;
 
+       ctx->output_left = 0;
+
        /* Initialise the standard table entries */
        for (uint32_t i = 0; i < ctx->clear_code; ++i) {
                table[i].first = i;
@@ -274,7 +278,6 @@ lzw_result lzw_decode_init(
        lzw__clear_table(ctx);
        ctx->prev_code = ctx->clear_code;
 
-       *stack_base_out = ctx->stack_base;
        return LZW_OK;
 }
 
@@ -306,11 +309,31 @@ static inline void lzw__table_add_entry(
  * \return Number of pixel values written.
  */
 static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
-               uint32_t code)
+               void *buffer,
+               uint32_t length,
+               uint32_t used,
+               uint32_t code,
+               uint32_t left)
 {
-       uint8_t *stack_pos = ctx->stack_base;
+       uint8_t *stack_pos = (uint8_t *)buffer + used;
        struct lzw_table_entry * const table = ctx->table;
-       uint32_t count = table[code].count;
+       uint32_t space = length - used;
+       uint32_t count = left;
+
+       if (count > space) {
+               left = count - space;
+               count = space;
+       } else {
+               left = 0;
+       }
+
+       ctx->output_code = code;
+       ctx->output_left = left;
+
+       for (unsigned i = left; i != 0; i--) {
+               struct lzw_table_entry *entry = table + code;
+               code = entry->extends;
+       }
 
        stack_pos += count;
        for (unsigned i = count; i != 0; i--) {
@@ -322,9 +345,28 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx 
*ctx,
        return count;
 }
 
-/* Exported function, documented in lzw.h */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
-               uint32_t *written)
+/**
+ * Fill the LZW stack with decompressed data
+ *
+ * Ensure anything on the stack is used before calling this, as anything
+ * on the stack before this call will be trampled.
+ *
+ * \param[in]  ctx      LZW reading context, updated.
+ * \param[out] written  Returns the number of values written.
+ *                      Use with `stack_base_out` value from previous
+ *                      lzw_decode_init() call.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
+               void *buffer,
+               uint32_t length,
+               uint32_t (*write_pixels)(struct lzw_ctx *ctx,
+                               void *buffer,
+                               uint32_t length,
+                               uint32_t used,
+                               uint32_t code,
+                               uint32_t left),
+               uint32_t *used)
 {
        lzw_result res;
        uint32_t code;
@@ -362,7 +404,8 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
                        }
                }
 
-               *written += lzw__write_pixels(ctx, code);
+               *used += write_pixels(ctx, buffer, length, *used, code,
+                               ctx->table[code].count);
        }
 
        /* Store details of this code as "previous code" to the context. */
@@ -372,3 +415,14 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
 
        return LZW_OK;
 }
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+               const uint8_t ** const data,
+               uint32_t *used)
+{
+       *used = 0;
+       *data = ctx->stack_base;
+       return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
+                       lzw__write_pixels, used);
+}
diff --git a/src/lzw.h b/src/lzw.h
index a4a58fc..2e82869 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -74,8 +74,7 @@ lzw_result lzw_decode_init(
                const uint8_t *compressed_data,
                uint32_t compressed_data_len,
                uint32_t compressed_data_pos,
-               uint8_t minimum_code_size,
-               const uint8_t ** const stack_base_out);
+               uint8_t minimum_code_size);
 
 /**
  * Fill the LZW stack with decompressed data
@@ -89,8 +88,8 @@ lzw_result lzw_decode_init(
  *                      lzw_decode_init() call.
  * \return LZW_OK on success, or appropriate error code otherwise.
  */
-lzw_result lzw_decode(
-               struct lzw_ctx *ctx,
-               uint32_t *written);
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+               const uint8_t ** const data,
+               uint32_t *used);
 
 #endif


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=ad9ddb59c4f0607821e52919a5ffdd09a1090a4e
commit ad9ddb59c4f0607821e52919a5ffdd09a1090a4e
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    gif: Frame decoding: Rearrange for readability.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 2db34df..050a961 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -656,7 +656,7 @@ gif__decode(gif_animation *gif,
         unsigned int transparency_index;
         const uint8_t *stack_base;
         const uint8_t *stack_pos;
-        uint32_t written = 0;
+        uint32_t available = 0;
         gif_result ret = GIF_OK;
         lzw_result res;
 
@@ -687,23 +687,9 @@ gif__decode(gif_animation *gif,
 
                 x = width;
                 while (x > 0) {
-                        if (written > 0) {
-                                unsigned burst_bytes = written;
-                                if (burst_bytes > x) {
-                                        burst_bytes = x;
-                                }
-                                x -= burst_bytes;
-                                written -= burst_bytes;
-                                while (burst_bytes-- > 0) {
-                                        register unsigned int colour;
-                                        colour = *stack_pos++;
-                                        if (colour != transparency_index) {
-                                                *frame_scanline = 
colour_table[colour];
-                                        }
-                                        frame_scanline++;
-                                }
-                        } else {
-                                res = lzw_decode(gif->lzw_ctx, &written);
+                        unsigned row_available;
+                        if (available == 0) {
+                                res = lzw_decode(gif->lzw_ctx, &available);
                                 if (res != LZW_OK) {
                                         /* Unexpected end of frame, try to 
recover */
                                         if (res == LZW_OK_EOD) {
@@ -715,6 +701,18 @@ gif__decode(gif_animation *gif,
                                 }
                                 stack_pos = stack_base;
                         }
+
+                        row_available = x < available ? x : available;
+                        x -= row_available;
+                        available -= row_available;
+                        while (row_available-- > 0) {
+                                register unsigned int colour;
+                                colour = *stack_pos++;
+                                if (colour != transparency_index) {
+                                        *frame_scanline = colour_table[colour];
+                                }
+                                frame_scanline++;
+                        }
                 }
         }
         return ret;


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=19bbdfd0e2cea3d133d3de1d275496060d069376
commit 19bbdfd0e2cea3d133d3de1d275496060d069376
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    gif: Frame decoding: Simplify transparency check.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 91dbb42..2db34df 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -42,6 +42,9 @@
 /** Transparent colour */
 #define GIF_TRANSPARENT_COLOUR 0x00
 
+/** No transparency */
+#define GIF_NO_TRANSPARENCY (0xFFFFFFFFu)
+
 /* GIF Flags */
 #define GIF_FRAME_COMBINE 1
 #define GIF_FRAME_CLEAR 2
@@ -650,6 +653,7 @@ gif__decode(gif_animation *gif,
                 unsigned int *restrict frame_data,
                 unsigned int *restrict colour_table)
 {
+        unsigned int transparency_index;
         const uint8_t *stack_base;
         const uint8_t *stack_pos;
         uint32_t written = 0;
@@ -664,6 +668,10 @@ gif__decode(gif_animation *gif,
                 return gif_error_from_lzw(res);
         }
 
+        transparency_index = gif->frames[frame].transparency ?
+                        gif->frames[frame].transparency_index :
+                        GIF_NO_TRANSPARENCY;
+
         stack_pos = stack_base;
         for (unsigned int y = 0; y < height; y++) {
                 unsigned int x;
@@ -687,11 +695,9 @@ gif__decode(gif_animation *gif,
                                 x -= burst_bytes;
                                 written -= burst_bytes;
                                 while (burst_bytes-- > 0) {
-                                        register unsigned char colour;
+                                        register unsigned int colour;
                                         colour = *stack_pos++;
-                                        if (((gif->frames[frame].transparency) 
&&
-                                             (colour != 
gif->frames[frame].transparency_index)) ||
-                                            
(!gif->frames[frame].transparency)) {
+                                        if (colour != transparency_index) {
                                                 *frame_scanline = 
colour_table[colour];
                                         }
                                         frame_scanline++;


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=a37a58757033a143ca6055ddf57111f5bdc6afec
commit a37a58757033a143ca6055ddf57111f5bdc6afec
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Remove written member from context.
    
    Not needed now that clear codes are handled normally.

diff --git a/src/lzw.c b/src/lzw.c
index d7e7a04..d3e0dcf 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -83,7 +83,6 @@ struct lzw_ctx {
        uint32_t table_size; /**< Next position in table to fill. */
 
        /** Output value stack. */
-       uint32_t written;
        uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
 
        /** LZW decode table. Generated during decode. */
@@ -302,13 +301,14 @@ static inline void lzw__table_add_entry(
 /**
  * Write values for this code to the output stack.
  *
- * \param[in]  ctx            LZW reading context, updated.
- * \param[in]  code           LZW code to output values for.
+ * \param[in]  ctx   LZW reading context, updated.
+ * \param[in]  code  LZW code to output values for.
+ * \return Number of pixel values written.
  */
-static inline void lzw__write_pixels(struct lzw_ctx *ctx,
+static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
                uint32_t code)
 {
-       uint8_t *stack_pos = ctx->stack_base + ctx->written;
+       uint8_t *stack_pos = ctx->stack_base;
        struct lzw_table_entry * const table = ctx->table;
        uint32_t count = table[code].count;
 
@@ -319,8 +319,7 @@ static inline void lzw__write_pixels(struct lzw_ctx *ctx,
                code = entry->extends;
        }
 
-       ctx->written += count;
-       return;
+       return count;
 }
 
 /* Exported function, documented in lzw.h */
@@ -330,8 +329,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        lzw_result res;
        uint32_t code;
 
-       ctx->written = 0;
-
        /* Get a new code from the input */
        res = lzw__read_code(&ctx->input, ctx->code_size, &code);
        if (res != LZW_OK) {
@@ -365,7 +362,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
                        }
                }
 
-               lzw__write_pixels(ctx, code);
+               *written += lzw__write_pixels(ctx, code);
        }
 
        /* Store details of this code as "previous code" to the context. */
@@ -373,7 +370,5 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        ctx->prev_code_count = ctx->table[code].count;
        ctx->prev_code = code;
 
-       *written = ctx->written;
-
        return LZW_OK;
 }


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=7aa7e7cbf5815d833bac688990e9e4d48226a83b
commit 7aa7e7cbf5815d833bac688990e9e4d48226a83b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Adapt main code handling to handle clear codes too.

diff --git a/src/lzw.c b/src/lzw.c
index 3db65c3..d7e7a04 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -223,42 +223,16 @@ static inline lzw_result lzw__read_code(
 /**
  * Clear LZW code table.
  *
- * \param[in]  ctx            LZW reading context, updated.
+ * \param[in]  ctx  LZW reading context, updated.
  * \return LZW_OK or error code.
  */
-static lzw_result lzw__clear_codes(
+static inline void lzw__clear_table(
                struct lzw_ctx *ctx)
 {
-       uint32_t code;
-
        /* Reset table building context */
        ctx->code_size = ctx->initial_code_size;
        ctx->code_max = (1 << ctx->initial_code_size) - 1;
        ctx->table_size = ctx->eoi_code + 1;
-
-       /* There might be a sequence of clear codes, so process them all */
-       do {
-               lzw_result res = lzw__read_code(&ctx->input,
-                               ctx->code_size, &code);
-               if (res != LZW_OK) {
-                       return res;
-               }
-       } while (code == ctx->clear_code);
-
-       /* The initial code must be from the initial table. */
-       if (code > ctx->clear_code) {
-               return LZW_BAD_ICODE;
-       }
-
-       /* Record this initial code as "previous" code, needed during decode. */
-       ctx->prev_code = code;
-       ctx->prev_code_first = code;
-       ctx->prev_code_count = 1;
-
-       /* Reset the stack, and add first non-clear code added as first item. */
-       ctx->stack_base[ctx->written++] = code;
-
-       return LZW_OK;
 }
 
 
@@ -298,10 +272,11 @@ lzw_result lzw_decode_init(
                table[i].count = 1;
        }
 
-       ctx->written = 0;
+       lzw__clear_table(ctx);
+       ctx->prev_code = ctx->clear_code;
 
        *stack_base_out = ctx->stack_base;
-       return lzw__clear_codes(ctx);
+       return LZW_OK;
 }
 
 /**
@@ -355,6 +330,8 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        lzw_result res;
        uint32_t code;
 
+       ctx->written = 0;
+
        /* Get a new code from the input */
        res = lzw__read_code(&ctx->input, ctx->code_size, &code);
        if (res != LZW_OK) {
@@ -362,35 +339,33 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        }
 
        /* Handle the new code */
-       if (code == ctx->clear_code) {
-               /* Got Clear code */
-               res = lzw__clear_codes(ctx);
-               if (res == LZW_OK) {
-                       *written = ctx->written;
-                       ctx->written = 0;
-               }
-               return res;
-
-       } else if (code == ctx->eoi_code) {
+       if (code == ctx->eoi_code) {
                /* Got End of Information code */
                return LZW_EOI_CODE;
 
        } else if (code > ctx->table_size) {
                /* Code is invalid */
                return LZW_BAD_CODE;
-       }
 
-       if (ctx->table_size < LZW_DICTIONARY_ENTRY_MAX) {
-               uint32_t size = ctx->table_size;
-               lzw__table_add_entry(ctx, (code < size) ?
-                               ctx->table[code].first :
-                               ctx->prev_code_first);
-
-               /* Ensure code size is increased, if needed. */
-               if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
-                       ctx->code_size++;
-                       ctx->code_max = (1 << ctx->code_size) - 1;
+       } else if (code == ctx->clear_code) {
+               lzw__clear_table(ctx);
+       } else {
+               if (ctx->prev_code != ctx->clear_code &&
+                   ctx->table_size < LZW_DICTIONARY_ENTRY_MAX) {
+                       uint32_t size = ctx->table_size;
+                       lzw__table_add_entry(ctx, (code < size) ?
+                                       ctx->table[code].first :
+                                       ctx->prev_code_first);
+
+                       /* Ensure code size is increased, if needed. */
+                       if (size == ctx->code_max &&
+                           ctx->code_size < LZW_CODE_MAX) {
+                               ctx->code_size++;
+                               ctx->code_max = (1 << ctx->code_size) - 1;
+                       }
                }
+
+               lzw__write_pixels(ctx, code);
        }
 
        /* Store details of this code as "previous code" to the context. */
@@ -398,10 +373,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        ctx->prev_code_count = ctx->table[code].count;
        ctx->prev_code = code;
 
-       lzw__write_pixels(ctx, code);
-
        *written = ctx->written;
-       ctx->written = 0;
 
        return LZW_OK;
 }


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=92850849f8cefe78c6abad56623f7ee2941fc340
commit 92850849f8cefe78c6abad56623f7ee2941fc340
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Output values in picture order.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 6b73e2f..91dbb42 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -652,17 +652,19 @@ gif__decode(gif_animation *gif,
 {
         const uint8_t *stack_base;
         const uint8_t *stack_pos;
+        uint32_t written = 0;
         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);
+                        minimum_code_size, &stack_base);
         if (res != LZW_OK) {
                 return gif_error_from_lzw(res);
         }
 
+        stack_pos = stack_base;
         for (unsigned int y = 0; y < height; y++) {
                 unsigned int x;
                 unsigned int decode_y;
@@ -675,21 +677,18 @@ gif__decode(gif_animation *gif,
                 }
                 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 (written > 0) {
+                                unsigned burst_bytes = written;
                                 if (burst_bytes > x) {
                                         burst_bytes = x;
                                 }
                                 x -= burst_bytes;
+                                written -= burst_bytes;
                                 while (burst_bytes-- > 0) {
                                         register unsigned char colour;
-                                        colour = *--stack_pos;
+                                        colour = *stack_pos++;
                                         if (((gif->frames[frame].transparency) 
&&
                                              (colour != 
gif->frames[frame].transparency_index)) ||
                                             
(!gif->frames[frame].transparency)) {
@@ -698,7 +697,7 @@ gif__decode(gif_animation *gif,
                                         frame_scanline++;
                                 }
                         } else {
-                                res = lzw_decode(gif->lzw_ctx, &stack_pos);
+                                res = lzw_decode(gif->lzw_ctx, &written);
                                 if (res != LZW_OK) {
                                         /* Unexpected end of frame, try to 
recover */
                                         if (res == LZW_OK_EOD) {
@@ -708,10 +707,10 @@ gif__decode(gif_animation *gif,
                                         }
                                         break;
                                 }
+                                stack_pos = stack_base;
                         }
                 }
         }
-
         return ret;
 }
 
diff --git a/src/lzw.c b/src/lzw.c
index d9b4571..3db65c3 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -83,6 +83,7 @@ struct lzw_ctx {
        uint32_t table_size; /**< Next position in table to fill. */
 
        /** Output value stack. */
+       uint32_t written;
        uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
 
        /** LZW decode table. Generated during decode. */
@@ -223,15 +224,12 @@ static inline lzw_result lzw__read_code(
  * Clear LZW code table.
  *
  * \param[in]  ctx            LZW reading context, updated.
- * \param[out] stack_pos_out  Returns current stack position.
  * \return LZW_OK or error code.
  */
 static lzw_result lzw__clear_codes(
-               struct lzw_ctx *ctx,
-               const uint8_t ** const stack_pos_out)
+               struct lzw_ctx *ctx)
 {
        uint32_t code;
-       uint8_t *stack_pos;
 
        /* Reset table building context */
        ctx->code_size = ctx->initial_code_size;
@@ -258,10 +256,8 @@ static lzw_result lzw__clear_codes(
        ctx->prev_code_count = 1;
 
        /* Reset the stack, and add first non-clear code added as first item. */
-       stack_pos = ctx->stack_base;
-       *stack_pos++ = code;
+       ctx->stack_base[ctx->written++] = code;
 
-       *stack_pos_out = stack_pos;
        return LZW_OK;
 }
 
@@ -273,8 +269,7 @@ lzw_result lzw_decode_init(
                uint32_t compressed_data_len,
                uint32_t compressed_data_pos,
                uint8_t minimum_code_size,
-               const uint8_t ** const stack_base_out,
-               const uint8_t ** const stack_pos_out)
+               const uint8_t ** const stack_base_out)
 {
        struct lzw_table_entry *table = ctx->table;
 
@@ -303,8 +298,10 @@ lzw_result lzw_decode_init(
                table[i].count = 1;
        }
 
+       ctx->written = 0;
+
        *stack_base_out = ctx->stack_base;
-       return lzw__clear_codes(ctx, stack_pos_out);
+       return lzw__clear_codes(ctx);
 }
 
 /**
@@ -332,32 +329,28 @@ static inline void lzw__table_add_entry(
  *
  * \param[in]  ctx            LZW reading context, updated.
  * \param[in]  code           LZW code to output values for.
- * \param[out] stack_pos_out  Returns current stack position.
- *                            There are `stack_pos_out - ctx->stack_base`
- *                            current stack entries.
  */
 static inline void lzw__write_pixels(struct lzw_ctx *ctx,
-               uint32_t code,
-               const uint8_t ** const stack_pos_out)
+               uint32_t code)
 {
-       uint8_t *stack_pos = ctx->stack_base;
-       uint32_t clear_code = ctx->clear_code;
+       uint8_t *stack_pos = ctx->stack_base + ctx->written;
        struct lzw_table_entry * const table = ctx->table;
+       uint32_t count = table[code].count;
 
-       while (code > clear_code) {
+       stack_pos += count;
+       for (unsigned i = count; i != 0; i--) {
                struct lzw_table_entry *entry = table + code;
-               *stack_pos++ = entry->value;
+               *--stack_pos = entry->value;
                code = entry->extends;
        }
-       *stack_pos++ = table[code].value;
 
-       *stack_pos_out = stack_pos;
+       ctx->written += count;
        return;
 }
 
 /* Exported function, documented in lzw.h */
 lzw_result lzw_decode(struct lzw_ctx *ctx,
-               const uint8_t ** const stack_pos_out)
+               uint32_t *written)
 {
        lzw_result res;
        uint32_t code;
@@ -371,7 +364,12 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        /* Handle the new code */
        if (code == ctx->clear_code) {
                /* Got Clear code */
-               return lzw__clear_codes(ctx, stack_pos_out);
+               res = lzw__clear_codes(ctx);
+               if (res == LZW_OK) {
+                       *written = ctx->written;
+                       ctx->written = 0;
+               }
+               return res;
 
        } else if (code == ctx->eoi_code) {
                /* Got End of Information code */
@@ -400,6 +398,10 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        ctx->prev_code_count = ctx->table[code].count;
        ctx->prev_code = code;
 
-       lzw__write_pixels(ctx, code, stack_pos_out);
+       lzw__write_pixels(ctx, code);
+
+       *written = ctx->written;
+       ctx->written = 0;
+
        return LZW_OK;
 }
diff --git a/src/lzw.h b/src/lzw.h
index 888526e..a4a58fc 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -67,9 +67,6 @@ void lzw_context_destroy(
  *                                  of a size byte at sub-block start.
  * \param[in]  minimum_code_size    The LZW Minimum Code Size.
  * \param[out] stack_base_out       Returns base of decompressed data stack.
- * \param[out] stack_pos_out        Returns current stack position.
- *                                  There are `stack_pos_out - stack_base_out`
- *                                  current stack entries.
  * \return LZW_OK on success, or appropriate error code otherwise.
  */
 lzw_result lzw_decode_init(
@@ -78,8 +75,7 @@ lzw_result lzw_decode_init(
                uint32_t compressed_data_len,
                uint32_t compressed_data_pos,
                uint8_t minimum_code_size,
-               const uint8_t ** const stack_base_out,
-               const uint8_t ** const stack_pos_out);
+               const uint8_t ** const stack_base_out);
 
 /**
  * Fill the LZW stack with decompressed data
@@ -87,19 +83,14 @@ lzw_result lzw_decode_init(
  * Ensure anything on the stack is used before calling this, as anything
  * on the stack before this call will be trampled.
  *
- * Caller does not own `stack_pos_out`.
- *
- * \param[in]  ctx            LZW reading context, updated.
- * \param[out] stack_pos_out  Returns current stack position.
- *                            Use with `stack_base_out` value from previous
- *                            lzw_decode_init() call.
- *                            There are `stack_pos_out - stack_base_out`
- *                            current stack entries.
+ * \param[in]  ctx      LZW reading context, updated.
+ * \param[out] written  Returns the number of values written.
+ *                      Use with `stack_base_out` value from previous
+ *                      lzw_decode_init() call.
  * \return LZW_OK on success, or appropriate error code otherwise.
  */
 lzw_result lzw_decode(
                struct lzw_ctx *ctx,
-               const uint8_t ** const stack_pos_out);
-
+               uint32_t *written);
 
 #endif


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=80d152f7e3a67b65302a467ad1c7dd5c03ff3b29
commit 80d152f7e3a67b65302a467ad1c7dd5c03ff3b29
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Store code's value count in table.

diff --git a/src/lzw.c b/src/lzw.c
index 6371513..d9b4571 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -58,6 +58,7 @@ struct lzw_read_ctx {
 struct lzw_table_entry {
        uint8_t  value;   /**< Last value for record ending at entry. */
        uint8_t  first;   /**< First value in entry's entire record. */
+       uint16_t count;   /**< Count of values in this entry's record. */
        uint16_t extends; /**< Offset in table to previous entry. */
 };
 
@@ -69,6 +70,7 @@ struct lzw_ctx {
 
        uint32_t prev_code;       /**< Code read from input previously. */
        uint32_t prev_code_first; /**< First value of previous code. */
+       uint32_t prev_code_count; /**< Total values for previous code. */
 
        uint32_t initial_code_size; /**< Starting LZW code size. */
 
@@ -253,6 +255,7 @@ static lzw_result lzw__clear_codes(
        /* Record this initial code as "previous" code, needed during decode. */
        ctx->prev_code = code;
        ctx->prev_code_first = code;
+       ctx->prev_code_count = 1;
 
        /* Reset the stack, and add first non-clear code added as first item. */
        stack_pos = ctx->stack_base;
@@ -297,6 +300,7 @@ lzw_result lzw_decode_init(
        for (uint32_t i = 0; i < ctx->clear_code; ++i) {
                table[i].first = i;
                table[i].value = i;
+               table[i].count = 1;
        }
 
        *stack_base_out = ctx->stack_base;
@@ -317,6 +321,7 @@ static inline void lzw__table_add_entry(
 
        entry->value = code;
        entry->first = ctx->prev_code_first;
+       entry->count = ctx->prev_code_count + 1;
        entry->extends = ctx->prev_code;
 
        ctx->table_size++;
@@ -392,6 +397,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
 
        /* Store details of this code as "previous code" to the context. */
        ctx->prev_code_first = ctx->table[code].first;
+       ctx->prev_code_count = ctx->table[code].count;
        ctx->prev_code = code;
 
        lzw__write_pixels(ctx, code, stack_pos_out);


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=0ecaf6688dfcfb9a36824df9b13fa75ce02e554d
commit 0ecaf6688dfcfb9a36824df9b13fa75ce02e554d
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    gif: Split out gif frame data decode.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 7c40eeb..6b73e2f 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -638,6 +638,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
  *
@@ -658,11 +735,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) {
@@ -810,10 +884,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
                  */
@@ -877,62 +947,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,


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=680babcd5768289ae72434c5d89c351a505a2136
commit 680babcd5768289ae72434c5d89c351a505a2136
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Rename a bunch of structures, functions and variables.
    
        new_code              -> code
        last_value            -> value
        first_value           -> first
        previous_entry        -> extends
        current_entry         -> table_size
        previous_code         -> prev_code
        previous_code_first   -> prev_code_first
        current_code_size     -> code_size
        current_code_size_max -> code_max
        lzw__next_code        -> lzw_read_code

diff --git a/src/lzw.c b/src/lzw.c
index 61093bb..6371513 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -21,7 +21,7 @@
  * Decoder for GIF LZW data.
  */
 
-/** Maximum number of dictionary entries. */
+/** Maximum number of table entries. */
 #define LZW_DICTIONARY_ENTRY_MAX (1u << LZW_CODE_MAX)
 
 /**
@@ -46,45 +46,45 @@ struct lzw_read_ctx {
 };
 
 /**
- * LZW dictionary entry.
+ * LZW table entry.
  *
- * Records in the dictionary are composed of 1 or more entries.
- * Entries point to previous entries which can be followed to compose
+ * Records in the table are composed of 1 or more entries.
+ * Entries refer to the entry they extend which can be followed to compose
  * the complete record.  To compose the record in reverse order, take
- * the `last_value` from each entry, and move to the previous entry.
- * If the previous_entry's index is < the current clear_code, then it
+ * the `value` from each entry, and move to the entry it extends.
+ * If the extended entries index is < the current clear_code, then it
  * is the last entry in the record.
  */
-struct lzw_dictionary_entry {
-       uint8_t last_value;      /**< Last value for record ending at entry. */
-       uint8_t first_value;     /**< First value for entry's record. */
-       uint16_t previous_entry; /**< Offset in dictionary to previous entry. */
+struct lzw_table_entry {
+       uint8_t  value;   /**< Last value for record ending at entry. */
+       uint8_t  first;   /**< First value in entry's entire record. */
+       uint16_t extends; /**< Offset in table to previous entry. */
 };
 
 /**
  * LZW decompression context.
  */
 struct lzw_ctx {
-       /** Input reading context */
-       struct lzw_read_ctx input;
+       struct lzw_read_ctx input; /**< Input reading context */
 
-       uint32_t previous_code;       /**< Code read from input previously. */
-       uint32_t previous_code_first; /**< First value of previous code. */
+       uint32_t prev_code;       /**< Code read from input previously. */
+       uint32_t prev_code_first; /**< First value of previous code. */
 
-       uint32_t initial_code_size;     /**< Starting LZW code size. */
-       uint32_t current_code_size;     /**< Current LZW code size. */
-       uint32_t current_code_size_max; /**< Max code value for current size. */
+       uint32_t initial_code_size; /**< Starting LZW code size. */
+
+       uint32_t code_size; /**< Current LZW code size. */
+       uint32_t code_max;  /**< Max code value for current code size. */
 
        uint32_t clear_code; /**< Special Clear code value */
        uint32_t eoi_code;   /**< Special End of Information code value */
 
-       uint32_t current_entry; /**< Next position in table to fill. */
+       uint32_t table_size; /**< Next position in table to fill. */
 
        /** Output value stack. */
        uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
 
-       /** LZW decode dictionary. Generated during decode. */
-       struct lzw_dictionary_entry table[LZW_DICTIONARY_ENTRY_MAX];
+       /** LZW decode table. Generated during decode. */
+       struct lzw_table_entry table[LZW_DICTIONARY_ENTRY_MAX];
 };
 
 
@@ -155,7 +155,7 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx 
*ctx)
  * \param[out] code_out   Returns an LZW code on success.
  * \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
  */
-static inline lzw_result lzw__next_code(
+static inline lzw_result lzw__read_code(
                struct lzw_read_ctx *ctx,
                uint8_t code_size,
                uint32_t *code_out)
@@ -218,7 +218,7 @@ static inline lzw_result lzw__next_code(
 
 
 /**
- * Clear LZW code dictionary.
+ * Clear LZW code table.
  *
  * \param[in]  ctx            LZW reading context, updated.
  * \param[out] stack_pos_out  Returns current stack position.
@@ -231,28 +231,28 @@ static lzw_result lzw__clear_codes(
        uint32_t code;
        uint8_t *stack_pos;
 
-       /* Reset dictionary building context */
-       ctx->current_code_size = ctx->initial_code_size;
-       ctx->current_code_size_max = (1 << ctx->initial_code_size) - 1;
-       ctx->current_entry = ctx->eoi_code + 1;
+       /* Reset table building context */
+       ctx->code_size = ctx->initial_code_size;
+       ctx->code_max = (1 << ctx->initial_code_size) - 1;
+       ctx->table_size = ctx->eoi_code + 1;
 
        /* There might be a sequence of clear codes, so process them all */
        do {
-               lzw_result res = lzw__next_code(&ctx->input,
-                               ctx->current_code_size, &code);
+               lzw_result res = lzw__read_code(&ctx->input,
+                               ctx->code_size, &code);
                if (res != LZW_OK) {
                        return res;
                }
        } while (code == ctx->clear_code);
 
-       /* The initial code must be from the initial dictionary. */
+       /* The initial code must be from the initial table. */
        if (code > ctx->clear_code) {
                return LZW_BAD_ICODE;
        }
 
        /* Record this initial code as "previous" code, needed during decode. */
-       ctx->previous_code = code;
-       ctx->previous_code_first = code;
+       ctx->prev_code = code;
+       ctx->prev_code_first = code;
 
        /* Reset the stack, and add first non-clear code added as first item. */
        stack_pos = ctx->stack_base;
@@ -273,7 +273,7 @@ lzw_result lzw_decode_init(
                const uint8_t ** const stack_base_out,
                const uint8_t ** const stack_pos_out)
 {
-       struct lzw_dictionary_entry *table = ctx->table;
+       struct lzw_table_entry *table = ctx->table;
 
        if (minimum_code_size >= LZW_CODE_MAX) {
                return LZW_BAD_ICODE;
@@ -287,16 +287,16 @@ lzw_result lzw_decode_init(
        ctx->input.sb_bit = 0;
        ctx->input.sb_bit_count = 0;
 
-       /* Initialise the dictionary building context */
+       /* Initialise the table building context */
        ctx->initial_code_size = minimum_code_size + 1;
 
        ctx->clear_code = (1 << minimum_code_size) + 0;
        ctx->eoi_code   = (1 << minimum_code_size) + 1;
 
-       /* Initialise the standard dictionary entries */
+       /* Initialise the standard table entries */
        for (uint32_t i = 0; i < ctx->clear_code; ++i) {
-               table[i].first_value = i;
-               table[i].last_value  = i;
+               table[i].first = i;
+               table[i].value = i;
        }
 
        *stack_base_out = ctx->stack_base;
@@ -304,22 +304,22 @@ lzw_result lzw_decode_init(
 }
 
 /**
- * Create new dictionary entry.
+ * Create new table entry.
  *
  * \param[in]  ctx   LZW reading context, updated.
- * \param[in]  code  Last value code for new dictionary entry.
+ * \param[in]  code  Last value code for new table entry.
  */
-static inline void lzw__dictionary_add_entry(
+static inline void lzw__table_add_entry(
                struct lzw_ctx *ctx,
                uint32_t code)
 {
-       struct lzw_dictionary_entry *entry = &ctx->table[ctx->current_entry];
+       struct lzw_table_entry *entry = &ctx->table[ctx->table_size];
 
-       entry->last_value     = code;
-       entry->first_value    = ctx->previous_code_first;
-       entry->previous_entry = ctx->previous_code;
+       entry->value = code;
+       entry->first = ctx->prev_code_first;
+       entry->extends = ctx->prev_code;
 
-       ctx->current_entry++;
+       ctx->table_size++;
 }
 
 /**
@@ -337,14 +337,14 @@ static inline void lzw__write_pixels(struct lzw_ctx *ctx,
 {
        uint8_t *stack_pos = ctx->stack_base;
        uint32_t clear_code = ctx->clear_code;
-       struct lzw_dictionary_entry * const table = ctx->table;
+       struct lzw_table_entry * const table = ctx->table;
 
        while (code > clear_code) {
-               struct lzw_dictionary_entry *entry = table + code;
-               *stack_pos++ = entry->last_value;
-               code = entry->previous_entry;
+               struct lzw_table_entry *entry = table + code;
+               *stack_pos++ = entry->value;
+               code = entry->extends;
        }
-       *stack_pos++ = table[code].last_value;
+       *stack_pos++ = table[code].value;
 
        *stack_pos_out = stack_pos;
        return;
@@ -355,47 +355,45 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
                const uint8_t ** const stack_pos_out)
 {
        lzw_result res;
-       uint32_t code_new;
-       uint32_t current_entry = ctx->current_entry;
+       uint32_t code;
 
        /* Get a new code from the input */
-       res = lzw__next_code(&ctx->input, ctx->current_code_size, &code_new);
+       res = lzw__read_code(&ctx->input, ctx->code_size, &code);
        if (res != LZW_OK) {
                return res;
        }
 
        /* Handle the new code */
-       if (code_new == ctx->clear_code) {
+       if (code == ctx->clear_code) {
                /* Got Clear code */
                return lzw__clear_codes(ctx, stack_pos_out);
 
-       } else if (code_new == ctx->eoi_code) {
+       } else if (code == ctx->eoi_code) {
                /* Got End of Information code */
                return LZW_EOI_CODE;
 
-       } else if (code_new > current_entry) {
+       } else if (code > ctx->table_size) {
                /* Code is invalid */
                return LZW_BAD_CODE;
        }
 
-       if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
-               lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
-                               ctx->table[code_new].first_value :
-                               ctx->previous_code_first);
+       if (ctx->table_size < LZW_DICTIONARY_ENTRY_MAX) {
+               uint32_t size = ctx->table_size;
+               lzw__table_add_entry(ctx, (code < size) ?
+                               ctx->table[code].first :
+                               ctx->prev_code_first);
 
                /* Ensure code size is increased, if needed. */
-               if (current_entry == ctx->current_code_size_max &&
-                               ctx->current_code_size < LZW_CODE_MAX) {
-                       ctx->current_code_size++;
-                       ctx->current_code_size_max =
-                                       (1 << ctx->current_code_size) - 1;
+               if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
+                       ctx->code_size++;
+                       ctx->code_max = (1 << ctx->code_size) - 1;
                }
        }
 
        /* Store details of this code as "previous code" to the context. */
-       ctx->previous_code_first = ctx->table[code_new].first_value;
-       ctx->previous_code = code_new;
+       ctx->prev_code_first = ctx->table[code].first;
+       ctx->prev_code = code;
 
-       lzw__write_pixels(ctx, code_new, stack_pos_out);
+       lzw__write_pixels(ctx, code, stack_pos_out);
        return LZW_OK;
 }


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=01faec4a877bba33a7fe1ad8db8d91288548c1a0
commit 01faec4a877bba33a7fe1ad8db8d91288548c1a0
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Split out output writing.

diff --git a/src/lzw.c b/src/lzw.c
index 8f2d5f2..61093bb 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -322,16 +322,41 @@ static inline void lzw__dictionary_add_entry(
        ctx->current_entry++;
 }
 
+/**
+ * Write values for this code to the output stack.
+ *
+ * \param[in]  ctx            LZW reading context, updated.
+ * \param[in]  code           LZW code to output values for.
+ * \param[out] stack_pos_out  Returns current stack position.
+ *                            There are `stack_pos_out - ctx->stack_base`
+ *                            current stack entries.
+ */
+static inline void lzw__write_pixels(struct lzw_ctx *ctx,
+               uint32_t code,
+               const uint8_t ** const stack_pos_out)
+{
+       uint8_t *stack_pos = ctx->stack_base;
+       uint32_t clear_code = ctx->clear_code;
+       struct lzw_dictionary_entry * const table = ctx->table;
+
+       while (code > clear_code) {
+               struct lzw_dictionary_entry *entry = table + code;
+               *stack_pos++ = entry->last_value;
+               code = entry->previous_entry;
+       }
+       *stack_pos++ = table[code].last_value;
+
+       *stack_pos_out = stack_pos;
+       return;
+}
+
 /* Exported function, documented in lzw.h */
 lzw_result lzw_decode(struct lzw_ctx *ctx,
                const uint8_t ** const stack_pos_out)
 {
        lzw_result res;
        uint32_t code_new;
-       uint8_t *stack_pos = ctx->stack_base;
-       uint32_t clear_code = ctx->clear_code;
        uint32_t current_entry = ctx->current_entry;
-       struct lzw_dictionary_entry * const table = ctx->table;
 
        /* Get a new code from the input */
        res = lzw__next_code(&ctx->input, ctx->current_code_size, &code_new);
@@ -340,7 +365,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        }
 
        /* Handle the new code */
-       if (code_new == clear_code) {
+       if (code_new == ctx->clear_code) {
                /* Got Clear code */
                return lzw__clear_codes(ctx, stack_pos_out);
 
@@ -355,7 +380,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
 
        if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
                lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
-                               table[code_new].first_value :
+                               ctx->table[code_new].first_value :
                                ctx->previous_code_first);
 
                /* Ensure code size is increased, if needed. */
@@ -368,17 +393,9 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        }
 
        /* Store details of this code as "previous code" to the context. */
-       ctx->previous_code_first = table[code_new].first_value;
+       ctx->previous_code_first = ctx->table[code_new].first_value;
        ctx->previous_code = code_new;
 
-       /* Put data for this code on output stack. */
-       while (code_new > clear_code) {
-               struct lzw_dictionary_entry *entry = table + code_new;
-               *stack_pos++ = entry->last_value;
-               code_new = entry->previous_entry;
-       }
-       *stack_pos++ = table[code_new].last_value;
-
-       *stack_pos_out = stack_pos;
+       lzw__write_pixels(ctx, code_new, stack_pos_out);
        return LZW_OK;
 }


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=d59e5eb2ec7db3009c6a7054c84dcae9273038c5
commit d59e5eb2ec7db3009c6a7054c84dcae9273038c5
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Rename minimum_code_size to match what it's called in spec.

diff --git a/src/lzw.c b/src/lzw.c
index 8b3e472..8f2d5f2 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -269,13 +269,13 @@ lzw_result lzw_decode_init(
                const uint8_t *compressed_data,
                uint32_t compressed_data_len,
                uint32_t compressed_data_pos,
-               uint8_t code_size,
+               uint8_t minimum_code_size,
                const uint8_t ** const stack_base_out,
                const uint8_t ** const stack_pos_out)
 {
        struct lzw_dictionary_entry *table = ctx->table;
 
-       if (code_size >= LZW_CODE_MAX) {
+       if (minimum_code_size >= LZW_CODE_MAX) {
                return LZW_BAD_ICODE;
        }
 
@@ -288,10 +288,10 @@ lzw_result lzw_decode_init(
        ctx->input.sb_bit_count = 0;
 
        /* Initialise the dictionary building context */
-       ctx->initial_code_size = code_size + 1;
+       ctx->initial_code_size = minimum_code_size + 1;
 
-       ctx->clear_code = (1 << code_size) + 0;
-       ctx->eoi_code   = (1 << code_size) + 1;
+       ctx->clear_code = (1 << minimum_code_size) + 0;
+       ctx->eoi_code   = (1 << minimum_code_size) + 1;
 
        /* Initialise the standard dictionary entries */
        for (uint32_t i = 0; i < ctx->clear_code; ++i) {
diff --git a/src/lzw.h b/src/lzw.h
index 385b425..888526e 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -65,7 +65,7 @@ void lzw_context_destroy(
  * \param[in]  compressed_data_len  Byte length of compressed data.
  * \param[in]  compressed_data_pos  Start position in data.  Must be position
  *                                  of a size byte at sub-block start.
- * \param[in]  code_size            The initial LZW code size to use.
+ * \param[in]  minimum_code_size    The LZW Minimum Code Size.
  * \param[out] stack_base_out       Returns base of decompressed data stack.
  * \param[out] stack_pos_out        Returns current stack position.
  *                                  There are `stack_pos_out - stack_base_out`
@@ -77,7 +77,7 @@ lzw_result lzw_decode_init(
                const uint8_t *compressed_data,
                uint32_t compressed_data_len,
                uint32_t compressed_data_pos,
-               uint8_t code_size,
+               uint8_t minimum_code_size,
                const uint8_t ** const stack_base_out,
                const uint8_t ** const stack_pos_out);
 


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=e708ae66a41c5f5eccc043bcf02bd0dccb132403
commit e708ae66a41c5f5eccc043bcf02bd0dccb132403
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Slight simplification of clear code handling.

diff --git a/src/lzw.c b/src/lzw.c
index 55bb4f8..8b3e472 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -232,9 +232,9 @@ static lzw_result lzw__clear_codes(
        uint8_t *stack_pos;
 
        /* Reset dictionary building context */
-       ctx->current_code_size = ctx->initial_code_size + 1;
-       ctx->current_code_size_max = (1 << ctx->current_code_size) - 1;
-       ctx->current_entry = (1 << ctx->initial_code_size) + 2;
+       ctx->current_code_size = ctx->initial_code_size;
+       ctx->current_code_size_max = (1 << ctx->initial_code_size) - 1;
+       ctx->current_entry = ctx->eoi_code + 1;
 
        /* There might be a sequence of clear codes, so process them all */
        do {
@@ -288,7 +288,7 @@ lzw_result lzw_decode_init(
        ctx->input.sb_bit_count = 0;
 
        /* Initialise the dictionary building context */
-       ctx->initial_code_size = code_size;
+       ctx->initial_code_size = code_size + 1;
 
        ctx->clear_code = (1 << code_size) + 0;
        ctx->eoi_code   = (1 << code_size) + 1;


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=e6c790fc877a231653f92b70c75a456812b5be0d
commit e6c790fc877a231653f92b70c75a456812b5be0d
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Avoid code size increment check when dictionary is full.

diff --git a/src/lzw.c b/src/lzw.c
index 1d145b4..55bb4f8 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -357,11 +357,10 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
                lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
                                table[code_new].first_value :
                                ctx->previous_code_first);
-       }
 
-       /* Ensure code size is increased, if needed. */
-       if (current_entry == ctx->current_code_size_max) {
-               if (ctx->current_code_size < LZW_CODE_MAX) {
+               /* Ensure code size is increased, if needed. */
+               if (current_entry == ctx->current_code_size_max &&
+                               ctx->current_code_size < LZW_CODE_MAX) {
                        ctx->current_code_size++;
                        ctx->current_code_size_max =
                                        (1 << ctx->current_code_size) - 1;


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=0d7049e414806b8af7f835cae9321138d4042a73
commit 0d7049e414806b8af7f835cae9321138d4042a73
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Split out dictionary augmentation.

diff --git a/src/lzw.c b/src/lzw.c
index a5097ab..1d145b4 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -303,6 +303,24 @@ lzw_result lzw_decode_init(
        return lzw__clear_codes(ctx, stack_pos_out);
 }
 
+/**
+ * Create new dictionary entry.
+ *
+ * \param[in]  ctx   LZW reading context, updated.
+ * \param[in]  code  Last value code for new dictionary entry.
+ */
+static inline void lzw__dictionary_add_entry(
+               struct lzw_ctx *ctx,
+               uint32_t code)
+{
+       struct lzw_dictionary_entry *entry = &ctx->table[ctx->current_entry];
+
+       entry->last_value     = code;
+       entry->first_value    = ctx->previous_code_first;
+       entry->previous_entry = ctx->previous_code;
+
+       ctx->current_entry++;
+}
 
 /* Exported function, documented in lzw.h */
 lzw_result lzw_decode(struct lzw_ctx *ctx,
@@ -310,7 +328,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
 {
        lzw_result res;
        uint32_t code_new;
-       uint8_t last_value;
        uint8_t *stack_pos = ctx->stack_base;
        uint32_t clear_code = ctx->clear_code;
        uint32_t current_entry = ctx->current_entry;
@@ -334,22 +351,12 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        } else if (code_new > current_entry) {
                /* Code is invalid */
                return LZW_BAD_CODE;
-
-       } else if (code_new < current_entry) {
-               /* Code is in table */
-               last_value = table[code_new].first_value;
-       } else {
-               /* Code not in table */
-               last_value = ctx->previous_code_first;
        }
 
-       /* Add to the dictionary, only if there's space */
        if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
-               struct lzw_dictionary_entry *entry = table + current_entry;
-               entry->last_value     = last_value;
-               entry->first_value    = ctx->previous_code_first;
-               entry->previous_entry = ctx->previous_code;
-               ctx->current_entry++;
+               lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
+                               table[code_new].first_value :
+                               ctx->previous_code_first);
        }
 
        /* Ensure code size is increased, if needed. */


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=970cc6c57b6d245ef20988b777edda51b3325184
commit 970cc6c57b6d245ef20988b777edda51b3325184
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Create #define for number of dictionary entry slots.

diff --git a/src/lzw.c b/src/lzw.c
index 16e1a72..a5097ab 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -21,6 +21,8 @@
  * Decoder for GIF LZW data.
  */
 
+/** Maximum number of dictionary entries. */
+#define LZW_DICTIONARY_ENTRY_MAX (1u << LZW_CODE_MAX)
 
 /**
  * Context for reading LZW data.
@@ -79,10 +81,10 @@ struct lzw_ctx {
        uint32_t current_entry; /**< Next position in table to fill. */
 
        /** Output value stack. */
-       uint8_t stack_base[1 << LZW_CODE_MAX];
+       uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
 
        /** LZW decode dictionary. Generated during decode. */
-       struct lzw_dictionary_entry table[1 << LZW_CODE_MAX];
+       struct lzw_dictionary_entry table[LZW_DICTIONARY_ENTRY_MAX];
 };
 
 
@@ -342,7 +344,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        }
 
        /* Add to the dictionary, only if there's space */
-       if (current_entry < (1 << LZW_CODE_MAX)) {
+       if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
                struct lzw_dictionary_entry *entry = table + current_entry;
                entry->last_value     = last_value;
                entry->first_value    = ctx->previous_code_first;


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=aa6d16b88dc74f66e7a4f2041886f57ce750237e
commit aa6d16b88dc74f66e7a4f2041886f57ce750237e
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Simplify new code handling.
    
    The tiny overhead of an extra time through the output loop
    is worth the simpler code.

diff --git a/src/lzw.c b/src/lzw.c
index 1f85496..16e1a72 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -4,6 +4,7 @@
  *                http://www.opensource.org/licenses/mit-license.php
  *
  * Copyright 2017 Michael Drake <[email protected]>
+ * Copyright 2021 Michael Drake <[email protected]>
  */
 
 #include <assert.h>
@@ -307,7 +308,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
 {
        lzw_result res;
        uint32_t code_new;
-       uint32_t code_out;
        uint8_t last_value;
        uint8_t *stack_pos = ctx->stack_base;
        uint32_t clear_code = ctx->clear_code;
@@ -335,12 +335,9 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
 
        } else if (code_new < current_entry) {
                /* Code is in table */
-               code_out = code_new;
                last_value = table[code_new].first_value;
        } else {
                /* Code not in table */
-               *stack_pos++ = ctx->previous_code_first;
-               code_out = ctx->previous_code;
                last_value = ctx->previous_code_first;
        }
 
@@ -366,15 +363,13 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
        ctx->previous_code_first = table[code_new].first_value;
        ctx->previous_code = code_new;
 
-       /* Put rest of data for this code on output stack.
-        * Note, in the case of "code not in table", the last entry of the
-        * current code has already been placed on the stack above. */
-       while (code_out > clear_code) {
-               struct lzw_dictionary_entry *entry = table + code_out;
+       /* Put data for this code on output stack. */
+       while (code_new > clear_code) {
+               struct lzw_dictionary_entry *entry = table + code_new;
                *stack_pos++ = entry->last_value;
-               code_out = entry->previous_entry;
+               code_new = entry->previous_entry;
        }
-       *stack_pos++ = table[code_out].last_value;
+       *stack_pos++ = table[code_new].last_value;
 
        *stack_pos_out = stack_pos;
        return LZW_OK;


-----------------------------------------------------------------------


-- 
NetSurf GIF Decoder
_______________________________________________
netsurf-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to