Gitweb links:

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

The branch, tlsa/lzw-optimise has been updated
  discards  ffa65b20ef33d6323cb073dc119bcd3d1ca12c5e (commit)
  discards  18a3f45e896ee30d817b9ddfe4dce3bf2ee6bba0 (commit)
  discards  1e284b45744009ba77e6b44709960fdb1592cdbb (commit)
  discards  98ca2136c67ea6a7a9d0f57b6481288fe9f54f64 (commit)
  discards  5454d9e6be9db8be8f759ec74e37558b93d85bc1 (commit)
  discards  ad9ddb59c4f0607821e52919a5ffdd09a1090a4e (commit)
  discards  19bbdfd0e2cea3d133d3de1d275496060d069376 (commit)
  discards  a37a58757033a143ca6055ddf57111f5bdc6afec (commit)
  discards  7aa7e7cbf5815d833bac688990e9e4d48226a83b (commit)
  discards  92850849f8cefe78c6abad56623f7ee2941fc340 (commit)
  discards  80d152f7e3a67b65302a467ad1c7dd5c03ff3b29 (commit)
  discards  0ecaf6688dfcfb9a36824df9b13fa75ce02e554d (commit)
  discards  680babcd5768289ae72434c5d89c351a505a2136 (commit)
  discards  01faec4a877bba33a7fe1ad8db8d91288548c1a0 (commit)
  discards  d59e5eb2ec7db3009c6a7054c84dcae9273038c5 (commit)
  discards  e708ae66a41c5f5eccc043bcf02bd0dccb132403 (commit)
  discards  e6c790fc877a231653f92b70c75a456812b5be0d (commit)
  discards  0d7049e414806b8af7f835cae9321138d4042a73 (commit)
  discards  970cc6c57b6d245ef20988b777edda51b3325184 (commit)
  discards  aa6d16b88dc74f66e7a4f2041886f57ce750237e (commit)
       via  4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5 (commit)
       via  8f4a3af5e6322c9deb2aa6e1b04952c4031f33b2 (commit)
       via  34d6277cf14fa104de5216fe156beab37d010d94 (commit)
       via  28ee35e73ef56eefbe6992034a2b8046d343393b (commit)
       via  b33ddeb9591c34e12f6d9428bc25b58d2edfbb7f (commit)
       via  d60461e06b690ef4583d767fd7d5c99415622e98 (commit)
       via  ec5b110f5af6618dd250c13e6fed0abd8040e813 (commit)
       via  35079ae6fe202806f616cbbde19a5ff1aa964dc3 (commit)
       via  412a5acea5762690dcf22498530165a7221532e0 (commit)
       via  73f6376fc3ffbed45576a12f69675e09c2b02d1f (commit)
       via  a7183f1ea70b3f3c722b27f97c5d494ada1be231 (commit)
       via  71a32374233598177e06ba9ee6214b9379bd40ba (commit)
       via  9520f18f7290ba4a9080be62ac9d2dbc957866a8 (commit)
       via  cf304dc469bfe688f8ae70c6102803095edfd0df (commit)
       via  62a814e980ea22b289b92b967cc0be7f373029ca (commit)
       via  728be940120d8c63b7c44df45e0203671158116b (commit)
       via  ce2543b41e3394c5cf3161d49f1561ba34f674a2 (commit)
       via  55c00227e1ad7cd7e03cc377fdaf052d57a56a06 (commit)
       via  86786f4cc6800fa6c6282f8a87e2defacebeb94d (commit)
       via  d8e8d3cceef907f798276014ebdfed7c370fb866 (commit)
       via  bba28df0cc0c75338a63645c6a55aebfebe91c74 (commit)
       via  c817c6f1e48ffe98bf65d381f8b11cd4f82c83c6 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (ffa65b20ef33d6323cb073dc119bcd3d1ca12c5e)
            \
             N -- N -- N (4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

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

    lzw: Direct output into frame data, avoiding stack.
    
    If the frame is non-interlaced, and has the same rowstride as the
    full image, then we can decode lzw directly into the output image.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 752f8c2..3c49218 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -626,8 +626,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,
@@ -701,6 +701,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 bd16aa1..a57e125 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_idx;     /**< Index representing transparency. */
+       uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
+
        /** Output value stack. */
        uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
 
@@ -363,6 +366,63 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx 
*ctx,
        return count;
 }
 
+
+/**
+ * Write colour mapped values for this code to the output stack.
+ *
+ * If there isn't enough space in the output stack, this function will write
+ * the as many as it can into the output.  If `ctx->output_left > 0` after
+ * this call, then there is more data for this code left to output.  The code
+ * is stored to the context as `ctx->output_code`.
+ *
+ * \param[in]  ctx     LZW reading context, updated.
+ * \param[in]  output  Array to write output values into.
+ * \param[in]  length  Size of output array.
+ * \param[in]  used    Current position in output array.
+ * \param[in]  code    LZW code to output values for.
+ * \param[in]  left    Number of values remaining to output for this value.
+ * \return Number of pixel values written.
+ */
+static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
+               void *restrict buffer,
+               uint32_t length,
+               uint32_t used,
+               uint32_t code,
+               uint32_t left)
+{
+       uint32_t *restrict 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_idx) {
+                       *stack_pos = ctx->colour_map[entry->value];
+               }
+               code = entry->extends;
+       }
+
+       return count;
+}
+
 /**
  * Get the next LZW code and write its value(s) to output buffer.
  *
@@ -374,7 +434,7 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx 
*ctx,
  * \return LZW_OK on success, or appropriate error code otherwise.
  */
 static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
-               uint8_t *restrict output,
+               void *restrict output,
                uint32_t length,
                lzw_writer_fn write_pixels,
                uint32_t *restrict used)
@@ -463,3 +523,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_idx,
+               uint32_t *restrict colour_map,
+               uint32_t *restrict data,
+               uint32_t length,
+               uint32_t *restrict used)
+{
+       *used = 0;
+
+       ctx->transparency_idx = transparency_idx;
+       ctx->colour_map = colour_map;
+
+       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 c130c24..3be97d0 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -106,4 +106,29 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
                const uint8_t ** const data,
                uint32_t *used);
 
+/**
+ * Read LZW codes into client buffer, mapping output to colours.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
+ *
+ * For transparency to work correctly, the given client buffer must have
+ * the values from the previous frame.  The transparency_idx should be a value
+ * of 256 or above, if the frame does not have transparency.
+ *
+ * \param[in]  ctx              LZW reading context, updated.
+ * \param[in]  transparency_idx Index representing transparency.
+ * \param[in]  colour_map       Index to pixel colour mapping
+ * \param[in]  data             Client buffer to fill with colour mapped 
values.
+ * \param[in]  length           Size of output array.
+ * \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_idx,
+               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=8f4a3af5e6322c9deb2aa6e1b04952c4031f33b2
commit 8f4a3af5e6322c9deb2aa6e1b04952c4031f33b2
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 e0d97c0..752f8c2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -672,8 +672,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) {
@@ -683,6 +681,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=34d6277cf14fa104de5216fe156beab37d010d94
commit 34d6277cf14fa104de5216fe156beab37d010d94
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 6ac4d49..bd16aa1 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -437,3 +437,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 dd0191e..c130c24 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -91,4 +91,19 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
                const uint8_t *restrict *const restrict data,
                uint32_t *restrict used);
 
+/**
+ * Read input codes until end of lzw context owned output buffer.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there 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=28ee35e73ef56eefbe6992034a2b8046d343393b
commit 28ee35e73ef56eefbe6992034a2b8046d343393b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    lzw: Add support for resumable output of a single code.
    
    This allows handling of insufficient output buffer space.

diff --git a/src/lzw.c b/src/lzw.c
index 24f4651..6ac4d49 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];
 
@@ -263,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;
@@ -296,21 +301,57 @@ static inline void lzw__table_add_entry(
        ctx->table_size++;
 }
 
+typedef uint32_t (*lzw_writer_fn)(
+               struct lzw_ctx *ctx,
+               void *restrict output,
+               uint32_t length,
+               uint32_t used,
+               uint32_t code,
+               uint32_t left);
+
 /**
  * Write values for this code to the output stack.
  *
+ * If there isn't enough space in the output stack, this function will write
+ * the as many as it can into the output.  If `ctx->output_left > 0` after
+ * this call, then there is more data for this code left to output.  The code
+ * is stored to the context as `ctx->output_code`.
+ *
  * \param[in]  ctx     LZW reading context, updated.
  * \param[in]  output  Array to write output values into.
+ * \param[in]  length  Size of output array.
+ * \param[in]  used    Current position in output array.
  * \param[in]  code    LZW code to output values for.
+ * \param[in]  left    Number of values remaining to output for this value.
  * \return Number of pixel values written.
  */
 static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
                void *restrict output,
-               uint32_t code)
+               uint32_t length,
+               uint32_t used,
+               uint32_t code,
+               uint32_t left)
 {
-       uint8_t *restrict output_pos = (uint8_t *)output;
+       uint8_t *restrict output_pos = (uint8_t *)output + 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;
+
+       /* Skip over any values we don't have space for. */
+       for (unsigned i = left; i != 0; i--) {
+               struct lzw_table_entry *entry = table + code;
+               code = entry->extends;
+       }
 
        output_pos += count;
        for (unsigned i = count; i != 0; i--) {
@@ -323,20 +364,19 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx 
*ctx,
 }
 
 /**
- * Fill the LZW stack with decompressed data
- *
- * Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
+ * Get the next LZW code and write its value(s) to output buffer.
  *
- * \param[in]  ctx     LZW reading context, updated.
- * \param[in]  output  Array to write output values into.
- * \param[out] used    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[in]     output        Array to write output values into.
+ * \param[in]     length        Size of output array.
+ * \param[in]     write_pixels  Function for writing pixels to output.
+ * \param[in,out] used          Number of values written. Updated on exit.
  * \return LZW_OK on success, or appropriate error code otherwise.
  */
 static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
                uint8_t *restrict output,
+               uint32_t length,
+               lzw_writer_fn write_pixels,
                uint32_t *restrict used)
 {
        lzw_result res;
@@ -375,7 +415,8 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
                        }
                }
 
-               *used += lzw__write_pixels(ctx, output, code);
+               *used += write_pixels(ctx, output, length, *used, code,
+                               ctx->table[code].count);
        }
 
        /* Store details of this code as "previous code" to the context. */
@@ -393,5 +434,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
 {
        *used = 0;
        *data = ctx->stack_base;
-       return lzw__decode(ctx, ctx->stack_base, used);
+       return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
+                       lzw__write_pixels, used);
 }


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

    lzw: Return output array from decode function instead of init.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 1540e1d..e0d97c0 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -639,8 +639,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;
@@ -648,7 +646,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);
         }
@@ -657,7 +655,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;
@@ -672,9 +669,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) {
@@ -684,7 +683,6 @@ gif__decode(gif_animation *gif,
                                         }
                                         break;
                                 }
-                                stack_pos = stack_base;
                         }
 
                         row_available = x < available ? x : available;
@@ -692,7 +690,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..24f4651 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -241,8 +241,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;
 
@@ -274,7 +273,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;
 }
 
@@ -301,30 +299,45 @@ 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]  output  Array to write output values into.
+ * \param[in]  code    LZW code to output values for.
  * \return Number of pixel values written.
  */
 static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
+               void *restrict output,
                uint32_t code)
 {
-       uint8_t *stack_pos = ctx->stack_base;
+       uint8_t *restrict output_pos = (uint8_t *)output;
        struct lzw_table_entry * const table = ctx->table;
        uint32_t count = table[code].count;
 
-       stack_pos += count;
+       output_pos += count;
        for (unsigned i = count; i != 0; i--) {
                struct lzw_table_entry *entry = table + code;
-               *--stack_pos = entry->value;
+               *--output_pos = entry->value;
                code = entry->extends;
        }
 
        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 in output is used before calling this, as anything
+ * on the there before this call will be trampled.
+ *
+ * \param[in]  ctx     LZW reading context, updated.
+ * \param[in]  output  Array to write output values into.
+ * \param[out] used    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,
+               uint8_t *restrict output,
+               uint32_t *restrict used)
 {
        lzw_result res;
        uint32_t code;
@@ -362,7 +375,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
                        }
                }
 
-               *written += lzw__write_pixels(ctx, code);
+               *used += lzw__write_pixels(ctx, output, code);
        }
 
        /* Store details of this code as "previous code" to the context. */
@@ -372,3 +385,13 @@ 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 *restrict* const restrict data,
+               uint32_t *restrict used)
+{
+       *used = 0;
+       *data = ctx->stack_base;
+       return lzw__decode(ctx, ctx->stack_base, used);
+}
diff --git a/src/lzw.h b/src/lzw.h
index a4a58fc..dd0191e 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -74,23 +74,21 @@ 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
+ * Read a single LZW code and write into lzw context owned output buffer.
  *
- * Ensure anything on the stack is used before calling this, as anything
- * on the stack before this call will be trampled.
+ * Ensure anything in output is used before calling this, as anything
+ * on the there 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,
-               uint32_t *written);
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+               const uint8_t *restrict *const restrict data,
+               uint32_t *restrict used);
 
 #endif


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=d60461e06b690ef4583d767fd7d5c99415622e98
commit d60461e06b690ef4583d767fd7d5c99415622e98
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 0874ec9..1540e1d 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -641,7 +641,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;
 
@@ -672,23 +672,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) {
@@ -700,6 +686,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=ec5b110f5af6618dd250c13e6fed0abd8040e813
commit ec5b110f5af6618dd250c13e6fed0abd8040e813
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 3b070b3..0874ec9 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
@@ -635,6 +638,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;
@@ -649,6 +653,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;
@@ -672,11 +680,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=35079ae6fe202806f616cbbde19a5ff1aa964dc3
commit 35079ae6fe202806f616cbbde19a5ff1aa964dc3
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=412a5acea5762690dcf22498530165a7221532e0
commit 412a5acea5762690dcf22498530165a7221532e0
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=73f6376fc3ffbed45576a12f69675e09c2b02d1f
commit 73f6376fc3ffbed45576a12f69675e09c2b02d1f
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 ed394a2..3b070b3 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -637,17 +637,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;
@@ -660,21 +662,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)) {
@@ -683,7 +682,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) {
@@ -693,10 +692,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=a7183f1ea70b3f3c722b27f97c5d494ada1be231
commit a7183f1ea70b3f3c722b27f97c5d494ada1be231
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=71a32374233598177e06ba9ee6214b9379bd40ba
commit 71a32374233598177e06ba9ee6214b9379bd40ba
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 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,


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=9520f18f7290ba4a9080be62ac9d2dbc957866a8
commit 9520f18f7290ba4a9080be62ac9d2dbc957866a8
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=cf304dc469bfe688f8ae70c6102803095edfd0df
commit cf304dc469bfe688f8ae70c6102803095edfd0df
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=62a814e980ea22b289b92b967cc0be7f373029ca
commit 62a814e980ea22b289b92b967cc0be7f373029ca
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=728be940120d8c63b7c44df45e0203671158116b
commit 728be940120d8c63b7c44df45e0203671158116b
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=ce2543b41e3394c5cf3161d49f1561ba34f674a2
commit ce2543b41e3394c5cf3161d49f1561ba34f674a2
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=55c00227e1ad7cd7e03cc377fdaf052d57a56a06
commit 55c00227e1ad7cd7e03cc377fdaf052d57a56a06
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=86786f4cc6800fa6c6282f8a87e2defacebeb94d
commit 86786f4cc6800fa6c6282f8a87e2defacebeb94d
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=d8e8d3cceef907f798276014ebdfed7c370fb866
commit d8e8d3cceef907f798276014ebdfed7c370fb866
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;


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

Summary of changes:
 src/libnsgif.c    |   49 ++++++++++++++++---------------------------------
 test/decode_gif.c |    4 ++++
 2 files changed, 20 insertions(+), 33 deletions(-)

diff --git a/src/libnsgif.c b/src/libnsgif.c
index fb2577c..3c49218 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -82,34 +82,17 @@ gif_initialise_sprite(gif_animation *gif,
                       unsigned int width,
                       unsigned int height)
 {
-        unsigned int max_width;
-        unsigned int max_height;
-        struct bitmap *buffer;
-
-        /* Check if we've changed */
-        if ((width <= gif->width) && (height <= gif->height)) {
+        /* Already allocated? */
+        if (gif->frame_image) {
                 return GIF_OK;
         }
 
-        /* Get our maximum values */
-        max_width = (width > gif->width) ? width : gif->width;
-        max_height = (height > gif->height) ? height : gif->height;
-
-        /* Allocate some more memory */
         assert(gif->bitmap_callbacks.bitmap_create);
-        buffer = gif->bitmap_callbacks.bitmap_create(max_width, max_height);
-        if (buffer == NULL) {
+        gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
+        if (gif->frame_image == NULL) {
                 return GIF_INSUFFICIENT_MEMORY;
         }
 
-        assert(gif->bitmap_callbacks.bitmap_destroy);
-        gif->bitmap_callbacks.bitmap_destroy(gif->frame_image);
-        gif->frame_image = buffer;
-        gif->width = max_width;
-        gif->height = max_height;
-
-        /* Invalidate our currently decoded image */
-        gif->decoded_frame = GIF_INVALID_FRAME;
         return GIF_OK;
 }
 
@@ -395,10 +378,12 @@ static gif_result gif_initialise_frame(gif_animation *gif)
         gif->frames[frame].redraw_required = 
((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
                                                 
(gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
 
-        /* Boundary checking - shouldn't ever happen except with junk data */
-        if (gif_initialise_sprite(gif, (offset_x + width), (offset_y + 
height))) {
-                return GIF_INSUFFICIENT_MEMORY;
-        }
+        /* Frame size may have grown.
+         */
+        gif->width = (offset_x + width > gif->width) ?
+                        offset_x + width : gif->width;
+        gif->height = (offset_y + height > gif->height) ?
+                        offset_y + height : gif->height;
 
         /* Decode the flags */
         flags = gif_data[9];
@@ -898,6 +883,12 @@ gif_internal_decode_frame(gif_animation *gif,
                 goto gif_decode_frame_exit;
         }
 
+        /* Make sure we have a buffer to decode to.
+         */
+        if (gif_initialise_sprite(gif, gif->width, gif->height)) {
+                return GIF_INSUFFICIENT_MEMORY;
+        }
+
         /* Decode the flags */
         flags = gif_data[9];
         colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
@@ -1223,14 +1214,6 @@ gif_result gif_initialise(gif_animation *gif, size_t 
size, unsigned char *data)
                 }
                 gif->frame_holders = 1;
 
-                /* Initialise the bitmap header */
-                assert(gif->bitmap_callbacks.bitmap_create);
-                gif->frame_image = 
gif->bitmap_callbacks.bitmap_create(gif->width, gif->height);
-                if (gif->frame_image == NULL) {
-                        gif_finalise(gif);
-                        return GIF_INSUFFICIENT_MEMORY;
-                }
-
                 /* Remember we've done this now */
                 gif->buffer_position = gif_data - gif->gif_data;
         }
diff --git a/test/decode_gif.c b/test/decode_gif.c
index 619be29..64387ef 100644
--- a/test/decode_gif.c
+++ b/test/decode_gif.c
@@ -161,6 +161,10 @@ static void write_ppm(FILE* fh, const char *name, 
gif_animation *gif,
                 if (code != GIF_OK)
                         warning("gif_decode_frame", code);
 
+                if (!gif->frames[i].display) {
+                        continue;
+                }
+
                 if (!no_write) {
                         fprintf(fh, "# frame %u:\n", i);
                         image = (unsigned char *) gif->frame_image;


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

Reply via email to