Gitweb links:

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

The branch, tlsa/lzw-optimise has been updated
  discards  bf7155c5495a6e9c118e4c97da15d0c295f16b3d (commit)
  discards  4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5 (commit)
  discards  8f4a3af5e6322c9deb2aa6e1b04952c4031f33b2 (commit)
  discards  34d6277cf14fa104de5216fe156beab37d010d94 (commit)
  discards  28ee35e73ef56eefbe6992034a2b8046d343393b (commit)
  discards  b33ddeb9591c34e12f6d9428bc25b58d2edfbb7f (commit)
  discards  d60461e06b690ef4583d767fd7d5c99415622e98 (commit)
  discards  ec5b110f5af6618dd250c13e6fed0abd8040e813 (commit)
  discards  35079ae6fe202806f616cbbde19a5ff1aa964dc3 (commit)
  discards  412a5acea5762690dcf22498530165a7221532e0 (commit)
  discards  73f6376fc3ffbed45576a12f69675e09c2b02d1f (commit)
  discards  a7183f1ea70b3f3c722b27f97c5d494ada1be231 (commit)
  discards  71a32374233598177e06ba9ee6214b9379bd40ba (commit)
  discards  9520f18f7290ba4a9080be62ac9d2dbc957866a8 (commit)
  discards  cf304dc469bfe688f8ae70c6102803095edfd0df (commit)
  discards  62a814e980ea22b289b92b967cc0be7f373029ca (commit)
  discards  728be940120d8c63b7c44df45e0203671158116b (commit)
  discards  ce2543b41e3394c5cf3161d49f1561ba34f674a2 (commit)
  discards  55c00227e1ad7cd7e03cc377fdaf052d57a56a06 (commit)
  discards  86786f4cc6800fa6c6282f8a87e2defacebeb94d (commit)
       via  f14022e4f5ac2f4aa5bf898d59774d76442816c8 (commit)
       via  9184fc8f94fd1e755733952f42cda2e448d61b31 (commit)
       via  b94e8ecc48c336c41f52d1605bd4b1a80d836fce (commit)
       via  8bfe1285b83e942b65e871975792b9168bb70c6e (commit)
       via  393b9677b022c0cf61cc1959040fe8351332aeed (commit)
       via  39519291052243d5ab678be3da5ae12787941016 (commit)
       via  45c0d2812d13d110b151e4b60787275572c65e69 (commit)
       via  c2074de22a8d77ff8e688a3f22132f6d0ee44c20 (commit)
       via  602dcec85a1fc6f932bd32b49008354016c29bec (commit)
       via  f434088537e3c8a4bde836fcea3c159b44fe8983 (commit)
       via  3ab1f9e45455ea4406168da9a5837bd0ce176542 (commit)
       via  79d5d80a4dbe33d9e446aa637d7b905fac072f88 (commit)
       via  270155287a0f2e7788253a38178efefb608ffdd5 (commit)
       via  def4cda3550f2f3e661fecf897447e0409e3ca15 (commit)
       via  b5b9d0524b2159278be8ebb18812b82872704c5d (commit)
       via  bf63b51e89777cccbc3e94e3c4ca082f5f82def2 (commit)
       via  c06164add4d44baad937ee9abcd110a46b7944ba (commit)
       via  f1e0c5c5bbb01ab9747b9bd0113e6598bcc5025a (commit)
       via  87f9e081593d4ca373997f4a19578f13066e1941 (commit)
       via  29f3d0fb22f9cdbd603e9561c9c8e000a2d6d5ef (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 (bf7155c5495a6e9c118e4c97da15d0c295f16b3d)
            \
             N -- N -- N (f14022e4f5ac2f4aa5bf898d59774d76442816c8)

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=f14022e4f5ac2f4aa5bf898d59774d76442816c8
commit f14022e4f5ac2f4aa5bf898d59774d76442816c8
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    gif: Switch complex decoder over to continuous lzw API.

diff --git a/src/libnsgif.c b/src/libnsgif.c
index 3c49218..6d78dc2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -681,7 +681,7 @@ gif__decode_complex(gif_animation *gif,
                                         }
                                         break;
                                 }
-                                res = lzw_decode(gif->lzw_ctx,
+                                res = lzw_decode_continuous(gif->lzw_ctx,
                                                 &uncompressed, &available);
                         }
 


commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=9184fc8f94fd1e755733952f42cda2e448d61b31
commit 9184fc8f94fd1e755733952f42cda2e448d61b31
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 1440b78..0d39882 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_TABLE_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=b94e8ecc48c336c41f52d1605bd4b1a80d836fce
commit b94e8ecc48c336c41f52d1605bd4b1a80d836fce
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=8bfe1285b83e942b65e871975792b9168bb70c6e
commit 8bfe1285b83e942b65e871975792b9168bb70c6e
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 882c35a..1440b78 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=393b9677b022c0cf61cc1959040fe8351332aeed
commit 393b9677b022c0cf61cc1959040fe8351332aeed
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 035882d..882c35a 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_TABLE_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=39519291052243d5ab678be3da5ae12787941016
commit 39519291052243d5ab678be3da5ae12787941016
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 a589221..035882d 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=45c0d2812d13d110b151e4b60787275572c65e69
commit 45c0d2812d13d110b151e4b60787275572c65e69
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=c2074de22a8d77ff8e688a3f22132f6d0ee44c20
commit c2074de22a8d77ff8e688a3f22132f6d0ee44c20
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=602dcec85a1fc6f932bd32b49008354016c29bec
commit 602dcec85a1fc6f932bd32b49008354016c29bec
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 ac710a7..a589221 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_TABLE_ENTRY_MAX];
 
        /** LZW code 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=f434088537e3c8a4bde836fcea3c159b44fe8983
commit f434088537e3c8a4bde836fcea3c159b44fe8983
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 518756c..ac710a7 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_TABLE_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_TABLE_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=3ab1f9e45455ea4406168da9a5837bd0ce176542
commit 3ab1f9e45455ea4406168da9a5837bd0ce176542
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 7032501..518756c 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_TABLE_ENTRY_MAX];
 
        /** LZW code 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=79d5d80a4dbe33d9e446aa637d7b905fac072f88
commit 79d5d80a4dbe33d9e446aa637d7b905fac072f88
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 916bcec..7032501 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=270155287a0f2e7788253a38178efefb608ffdd5
commit 270155287a0f2e7788253a38178efefb608ffdd5
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=def4cda3550f2f3e661fecf897447e0409e3ca15
commit def4cda3550f2f3e661fecf897447e0409e3ca15
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 5b7227f..916bcec 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 lzw table entries. */
 #define LZW_TABLE_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_TABLE_ENTRY_MAX];
 
-       /** LZW decode dictionary. Generated during decode. */
-       struct lzw_dictionary_entry table[LZW_TABLE_ENTRY_MAX];
+       /** LZW code table. Generated during decode. */
+       struct lzw_table_entry table[LZW_TABLE_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_TABLE_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_TABLE_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=b5b9d0524b2159278be8ebb18812b82872704c5d
commit b5b9d0524b2159278be8ebb18812b82872704c5d
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 a5f6e98..5b7227f 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_TABLE_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=bf63b51e89777cccbc3e94e3c4ca082f5f82def2
commit bf63b51e89777cccbc3e94e3c4ca082f5f82def2
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 a5fe811..a5f6e98 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=c06164add4d44baad937ee9abcd110a46b7944ba
commit c06164add4d44baad937ee9abcd110a46b7944ba
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 ed92e36..a5fe811 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=f1e0c5c5bbb01ab9747b9bd0113e6598bcc5025a
commit f1e0c5c5bbb01ab9747b9bd0113e6598bcc5025a
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 3504982..ed92e36 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=87f9e081593d4ca373997f4a19578f13066e1941
commit 87f9e081593d4ca373997f4a19578f13066e1941
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 e7b06f1..3504982 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_TABLE_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=29f3d0fb22f9cdbd603e9561c9c8e000a2d6d5ef
commit 29f3d0fb22f9cdbd603e9561c9c8e000a2d6d5ef
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..e7b06f1 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_TABLE_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_TABLE_ENTRY_MAX];
 
        /** LZW decode dictionary. Generated during decode. */
-       struct lzw_dictionary_entry table[1 << LZW_CODE_MAX];
+       struct lzw_dictionary_entry table[LZW_TABLE_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_TABLE_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/lzw.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/lzw.c b/src/lzw.c
index a57e125..0d39882 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -21,8 +21,8 @@
  * Decoder for GIF LZW data.
  */
 
-/** Maximum number of table entries. */
-#define LZW_DICTIONARY_ENTRY_MAX (1u << LZW_CODE_MAX)
+/** Maximum number of lzw table entries. */
+#define LZW_TABLE_ENTRY_MAX (1u << LZW_CODE_MAX)
 
 /**
  * Context for reading LZW data.
@@ -89,10 +89,10 @@ struct lzw_ctx {
        uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
 
        /** Output value stack. */
-       uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
+       uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
 
-       /** LZW decode table. Generated during decode. */
-       struct lzw_table_entry table[LZW_DICTIONARY_ENTRY_MAX];
+       /** LZW code table. Generated during decode. */
+       struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX];
 };
 
 
@@ -461,7 +461,7 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
                lzw__clear_table(ctx);
        } else {
                if (ctx->prev_code != ctx->clear_code &&
-                   ctx->table_size < LZW_DICTIONARY_ENTRY_MAX) {
+                   ctx->table_size < LZW_TABLE_ENTRY_MAX) {
                        uint32_t size = ctx->table_size;
                        lzw__table_add_entry(ctx, (code < size) ?
                                        ctx->table[code].first :


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

Reply via email to