netsurf: branch master updated. release/3.10-158-gd92b269
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/d92b2696295e18146ff5c...
...commit http://git.netsurf-browser.org/netsurf.git/commit/d92b2696295e18146ff5c8f...
...tree http://git.netsurf-browser.org/netsurf.git/tree/d92b2696295e18146ff5c8fd1...
The branch, master has been updated
via d92b2696295e18146ff5c8fd15bc6ea198749f28 (commit)
from 729e56dccca8d480dccaf4ea286eed5adc2e0a8f (commit)
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/netsurf.git/commit/?id=d92b2696295e18146ff...
commit d92b2696295e18146ff5c8fd15bc6ea198749f28
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Amiga: Don't open/close dos.library ourselves on OS3
Suspect this is the cause of crash on exit
diff --git a/frontends/amiga/libs.c b/frontends/amiga/libs.c
index 3c09bcb..eb1f216 100644
--- a/frontends/amiga/libs.c
+++ b/frontends/amiga/libs.c
@@ -223,6 +223,7 @@ bool ami_libs_open(void)
#ifdef __amigaos4__
/* Libraries only needed on OS4 */
AMINS_LIB_OPEN("application.library", 53, Application, "application", 2, false)
+ AMINS_LIB_OPEN("dos.library", 37, DOS, "main", 1, true)
#else
/* Libraries we get automatically on OS4 but not OS3 */
AMINS_LIB_OPEN("utility.library", 37, Utility, "main", 1, true)
@@ -231,7 +232,6 @@ bool ami_libs_open(void)
AMINS_LIB_OPEN("asl.library", 37, Asl, "main", 1, true)
AMINS_LIB_OPEN("datatypes.library", 39, DataTypes, "main", 1, true)
AMINS_LIB_OPEN("diskfont.library", 40, Diskfont, "main", 1, true)
- AMINS_LIB_OPEN("dos.library", 37, DOS, "main", 1, true)
AMINS_LIB_OPEN("gadtools.library", 37, GadTools, "main", 1, true)
AMINS_LIB_OPEN("graphics.library", 40, Graphics, "main", 1, true)
AMINS_LIB_OPEN("icon.library", 44, Icon, "main", 1, true)
@@ -332,7 +332,6 @@ void ami_libs_close(void)
AMINS_LIB_CLOSE(Asl)
AMINS_LIB_CLOSE(DataTypes)
AMINS_LIB_CLOSE(Diskfont)
- AMINS_LIB_CLOSE(DOS)
AMINS_LIB_CLOSE(GadTools)
AMINS_LIB_CLOSE(Graphics)
AMINS_LIB_CLOSE(Icon)
@@ -345,6 +344,7 @@ void ami_libs_close(void)
AMINS_LIB_CLOSE(Workbench)
#ifdef __amigaos4__
AMINS_LIB_CLOSE(Application)
+ AMINS_LIB_CLOSE(DOS)
#else
AMINS_LIB_CLOSE(Utility)
#endif
-----------------------------------------------------------------------
Summary of changes:
frontends/amiga/libs.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frontends/amiga/libs.c b/frontends/amiga/libs.c
index 3c09bcb..eb1f216 100644
--- a/frontends/amiga/libs.c
+++ b/frontends/amiga/libs.c
@@ -223,6 +223,7 @@ bool ami_libs_open(void)
#ifdef __amigaos4__
/* Libraries only needed on OS4 */
AMINS_LIB_OPEN("application.library", 53, Application, "application", 2, false)
+ AMINS_LIB_OPEN("dos.library", 37, DOS, "main", 1, true)
#else
/* Libraries we get automatically on OS4 but not OS3 */
AMINS_LIB_OPEN("utility.library", 37, Utility, "main", 1, true)
@@ -231,7 +232,6 @@ bool ami_libs_open(void)
AMINS_LIB_OPEN("asl.library", 37, Asl, "main", 1, true)
AMINS_LIB_OPEN("datatypes.library", 39, DataTypes, "main", 1, true)
AMINS_LIB_OPEN("diskfont.library", 40, Diskfont, "main", 1, true)
- AMINS_LIB_OPEN("dos.library", 37, DOS, "main", 1, true)
AMINS_LIB_OPEN("gadtools.library", 37, GadTools, "main", 1, true)
AMINS_LIB_OPEN("graphics.library", 40, Graphics, "main", 1, true)
AMINS_LIB_OPEN("icon.library", 44, Icon, "main", 1, true)
@@ -332,7 +332,6 @@ void ami_libs_close(void)
AMINS_LIB_CLOSE(Asl)
AMINS_LIB_CLOSE(DataTypes)
AMINS_LIB_CLOSE(Diskfont)
- AMINS_LIB_CLOSE(DOS)
AMINS_LIB_CLOSE(GadTools)
AMINS_LIB_CLOSE(Graphics)
AMINS_LIB_CLOSE(Icon)
@@ -345,6 +344,7 @@ void ami_libs_close(void)
AMINS_LIB_CLOSE(Workbench)
#ifdef __amigaos4__
AMINS_LIB_CLOSE(Application)
+ AMINS_LIB_CLOSE(DOS)
#else
AMINS_LIB_CLOSE(Utility)
#endif
--
NetSurf Browser
1 year, 7 months
netsurf: branch tlsa/gif-api created. release/3.10-158-g0f547ed
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/0f547ed94026145f48602...
...commit http://git.netsurf-browser.org/netsurf.git/commit/0f547ed94026145f48602e7...
...tree http://git.netsurf-browser.org/netsurf.git/tree/0f547ed94026145f48602e72d...
The branch, tlsa/gif-api has been created
at 0f547ed94026145f48602e72d5c9bbafbbb72b10 (commit)
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=0f547ed94026145f486...
commit 0f547ed94026145f48602e72d5c9bbafbbb72b10
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
WIP: GIF: Update to new libnsgif API.
diff --git a/content/handlers/image/gif.c b/content/handlers/image/gif.c
index e2a0ca5..d7dedef 100644
--- a/content/handlers/image/gif.c
+++ b/content/handlers/image/gif.c
@@ -34,7 +34,8 @@
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <libnsgif.h>
+
+#include <nsgif.h>
#include "utils/utils.h"
#include "utils/messages.h"
@@ -51,13 +52,12 @@
#include "image/image.h"
#include "image/gif.h"
-typedef struct nsgif_content {
+typedef struct gif_content {
struct content base;
- struct gif_animation *gif; /**< GIF animation data */
- int current_frame; /**< current frame to display [0...(max-1)] */
-} nsgif_content;
-
+ nsgif *gif; /**< GIF animation data */
+ uint32_t current_frame; /**< current frame to display [0...(max-1)] */
+} gif_content;
/**
* Callback for libnsgif; forwards the call to bitmap_create()
@@ -66,44 +66,41 @@ typedef struct nsgif_content {
* \param height width of image in pixels
* \return an opaque struct bitmap, or NULL on memory exhaustion
*/
-static void *nsgif_bitmap_create(int width, int height)
+static void *gif_bitmap_create(int width, int height)
{
return guit->bitmap->create(width, height, BITMAP_NEW);
}
-
-static nserror nsgif_create_gif_data(nsgif_content *c)
+static nserror gif_create_gif_data(gif_content *c)
{
- gif_bitmap_callback_vt gif_bitmap_callbacks = {
- .bitmap_create = nsgif_bitmap_create,
- .bitmap_destroy = guit->bitmap->destroy,
- .bitmap_get_buffer = guit->bitmap->get_buffer,
- .bitmap_set_opaque = guit->bitmap->set_opaque,
- .bitmap_test_opaque = guit->bitmap->test_opaque,
- .bitmap_modified = guit->bitmap->modified
+ nsgif_bitmap_cb_vt gif_bitmap_callbacks = {
+ .create = gif_bitmap_create,
+ .destroy = guit->bitmap->destroy,
+ .get_buffer = guit->bitmap->get_buffer,
+ .set_opaque = guit->bitmap->set_opaque,
+ .test_opaque = guit->bitmap->test_opaque,
+ .modified = guit->bitmap->modified
};
/* Initialise our data structure */
- c->gif = calloc(sizeof(gif_animation), 1);
+ c->gif = calloc(sizeof(nsgif), 1);
if (c->gif == NULL) {
content_broadcast_error(&c->base, NSERROR_NOMEM, NULL);
return NSERROR_NOMEM;
}
- gif_create(c->gif, &gif_bitmap_callbacks);
+ nsgif_create(c->gif, &gif_bitmap_callbacks);
return NSERROR_OK;
}
-
-
-static nserror nsgif_create(const content_handler *handler,
- lwc_string *imime_type, const struct http_parameter *params,
+static nserror gif_create(const content_handler *handler,
+ lwc_string *imime_type, const struct http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
- nsgif_content *result;
+ gif_content *result;
nserror error;
- result = calloc(1, sizeof(nsgif_content));
+ result = calloc(1, sizeof(gif_content));
if (result == NULL)
return NSERROR_NOMEM;
@@ -114,7 +111,7 @@ static nserror nsgif_create(const content_handler *handler,
return error;
}
- error = nsgif_create_gif_data(result);
+ error = gif_create_gif_data(result);
if (error != NSERROR_OK) {
free(result);
return error;
@@ -126,99 +123,83 @@ static nserror nsgif_create(const content_handler *handler,
}
/**
+ * Scheduler callback. Performs any necessary animation.
+ *
+ * \param p The content to animate
+*/
+static void gif_animate_cb(void *p);
+
+static inline nserror gif__nsgif_error_to_ns(nsgif_result gif_res)
+{
+ nserror err;
+
+ switch (gif_res) {
+ case NSGIF_OK:
+ err = NSERROR_OK;
+ break;
+ case NSGIF_INSUFFICIENT_MEMORY:
+ err = NSERROR_NOMEM;
+ break;
+ default:
+ err = NSERROR_GIF_ERROR;
+ break;
+ }
+
+ return err;
+}
+
+/**
* Performs any necessary animation.
*
* \param p The content to animate
*/
-static void nsgif_animate(void *p)
+static nserror gif__animate(gif_content *gif, bool redraw)
{
- nsgif_content *gif = p;
- union content_msg_data data;
- int delay;
- int f;
-
- /* Advance by a frame, updating the loop count accordingly */
- gif->current_frame++;
- if (gif->current_frame == (int)gif->gif->frame_count_partial) {
- gif->current_frame = 0;
-
- /* A loop count of 0 has a special meaning of infinite */
- if (gif->gif->loop_count != 0) {
- gif->gif->loop_count--;
- if (gif->gif->loop_count == 0) {
- gif->current_frame =
- gif->gif->frame_count_partial - 1;
- gif->gif->loop_count = -1;
- }
- }
+ nsgif_result gif_res;
+ nsgif_rect rect;
+ uint32_t delay;
+ uint32_t f;
+
+ gif_res = nsgif_frame_prepare(gif->gif, &rect, &delay, &f);
+ if (gif_res != NSGIF_OK) {
+ return gif__nsgif_error_to_ns(gif_res);
}
+ gif->current_frame = f;
+
/* Continue animating if we should */
- if (gif->gif->loop_count >= 0) {
- delay = gif->gif->frames[gif->current_frame].frame_delay;
- if (delay <= 1) {
- /* Assuming too fast to be intended, set default. */
- delay = 10;
- }
- guit->misc->schedule(delay * 10, nsgif_animate, gif);
+ if (nsoption_bool(animate_images) && delay != NSGIF_INFINITE) {
+ guit->misc->schedule(delay * 10, gif_animate_cb, gif);
}
- if ((!nsoption_bool(animate_images)) ||
- (!gif->gif->frames[gif->current_frame].display)) {
- return;
- }
+ if (redraw) {
+ union content_msg_data data;
- /* area within gif to redraw */
- f = gif->current_frame;
- data.redraw.x = gif->gif->frames[f].redraw_x;
- data.redraw.y = gif->gif->frames[f].redraw_y;
- data.redraw.width = gif->gif->frames[f].redraw_width;
- data.redraw.height = gif->gif->frames[f].redraw_height;
-
- /* redraw background (true) or plot on top (false) */
- if (gif->current_frame > 0) {
- /* previous frame needed clearing: expand the redraw area to
- * cover it */
- if (gif->gif->frames[f - 1].redraw_required) {
- if (data.redraw.x >
- (int)(gif->gif->frames[f - 1].redraw_x)) {
- data.redraw.width += data.redraw.x -
- gif->gif->frames[f - 1].redraw_x;
- data.redraw.x =
- gif->gif->frames[f - 1].redraw_x;
- }
- if (data.redraw.y >
- (int)(gif->gif->frames[f - 1].redraw_y)) {
- data.redraw.height += (data.redraw.y -
- gif->gif->frames[f - 1].redraw_y);
- data.redraw.y =
- gif->gif->frames[f - 1].redraw_y;
- }
- if ((int)(gif->gif->frames[f - 1].redraw_x +
- gif->gif->frames[f - 1].redraw_width) >
- (data.redraw.x + data.redraw.width))
- data.redraw.width =
- gif->gif->frames[f - 1].redraw_x -
- data.redraw.x +
- gif->gif->frames[f - 1].redraw_width;
- if ((int)(gif->gif->frames[f - 1].redraw_y +
- gif->gif->frames[f - 1].redraw_height) >
- (data.redraw.y + data.redraw.height))
- data.redraw.height =
- gif->gif->frames[f - 1].redraw_y -
- data.redraw.y +
- gif->gif->frames[f - 1].redraw_height;
- }
+ /* area within gif to redraw */
+ data.redraw.x = rect.x0;
+ data.redraw.y = rect.y0;
+ data.redraw.width = rect.x1 - rect.x0;
+ data.redraw.height = rect.y1 - rect.y0;
+
+ content_broadcast(&gif->base, CONTENT_MSG_REDRAW, &data);
}
- content_broadcast(&gif->base, CONTENT_MSG_REDRAW, &data);
+ return NSERROR_OK;
}
-static bool nsgif_convert(struct content *c)
+static void gif_animate_cb(void *p)
{
- nsgif_content *gif = (nsgif_content *) c;
- int res;
+ gif_content *gif = p;
+
+ gif__animate(gif, true);
+}
+
+static bool gif_convert(struct content *c)
+{
+ gif_content *gif = (gif_content *) c;
const uint8_t *data;
+ nsgif_result res;
+ nserror err;
size_t size;
char *title;
@@ -227,24 +208,14 @@ static bool nsgif_convert(struct content *c)
/* Initialise the GIF */
do {
- res = gif_initialise(gif->gif, size, (unsigned char *) data);
- if (res != GIF_OK && res != GIF_WORKING &&
- res != GIF_INSUFFICIENT_FRAME_DATA) {
- nserror error = NSERROR_UNKNOWN;
- switch (res) {
- case GIF_FRAME_DATA_ERROR:
- case GIF_INSUFFICIENT_DATA:
- case GIF_DATA_ERROR:
- error = NSERROR_GIF_ERROR;
- break;
- case GIF_INSUFFICIENT_MEMORY:
- error = NSERROR_NOMEM;
- break;
- }
- content_broadcast_error(c, error, NULL);
+ res = nsgif_data_scan(gif->gif, size, data);
+ if (res != NSGIF_OK && res != NSGIF_WORKING &&
+ res != NSGIF_INSUFFICIENT_FRAME_DATA) {
+ err = gif__nsgif_error_to_ns(res);
+ content_broadcast_error(c, err, NULL);
return false;
}
- } while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA);
+ } while (res != NSGIF_OK && res != NSGIF_INSUFFICIENT_FRAME_DATA);
/* Abort on bad GIFs */
if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) ||
@@ -267,12 +238,11 @@ static bool nsgif_convert(struct content *c)
free(title);
}
- /* Schedule the animation if we have one */
- gif->current_frame = 0;
- if (gif->gif->frame_count_partial > 1)
- guit->misc->schedule(gif->gif->frames[0].frame_delay * 10,
- nsgif_animate,
- c);
+ err = gif__animate(gif, false);
+ if (err != NSERROR_OK) {
+ content_broadcast_error(c, NSERROR_GIF_ERROR, NULL);
+ return false;
+ }
/* Exit as a success */
content_set_ready(c);
@@ -283,68 +253,50 @@ static bool nsgif_convert(struct content *c)
return true;
}
-
/**
* Updates the GIF bitmap to display the current frame
*
* \param gif The gif context to update.
- * \return GIF_OK on success else apropriate error code.
+ * \return NSGIF_OK on success else apropriate error code.
*/
-static gif_result nsgif_get_frame(nsgif_content *gif)
+static nsgif_result gif_get_frame(gif_content *gif)
{
- int previous_frame, current_frame, frame;
- gif_result res = GIF_OK;
-
- current_frame = gif->current_frame;
+ uint32_t current_frame = gif->current_frame;
if (!nsoption_bool(animate_images)) {
current_frame = 0;
}
- if (current_frame < gif->gif->decoded_frame) {
- previous_frame = 0;
- } else {
- previous_frame = gif->gif->decoded_frame + 1;
- }
-
- for (frame = previous_frame; frame <= current_frame; frame++) {
- res = gif_decode_frame(gif->gif, frame);
- }
-
- return res;
+ return nsgif_frame_decode(gif->gif, current_frame);
}
-static bool nsgif_redraw(struct content *c, struct content_redraw_data *data,
+static bool gif_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
- nsgif_content *gif = (nsgif_content *) c;
+ gif_content *gif = (gif_content *) c;
- if (gif->current_frame != gif->gif->decoded_frame) {
- if (nsgif_get_frame(gif) != GIF_OK) {
- return false;
- }
+ if (gif_get_frame(gif) != NSGIF_OK) {
+ return false;
}
return image_bitmap_plot(gif->gif->frame_image, data, clip, ctx);
}
-
-static void nsgif_destroy(struct content *c)
+static void gif_destroy(struct content *c)
{
- nsgif_content *gif = (nsgif_content *) c;
+ gif_content *gif = (gif_content *) c;
/* Free all the associated memory buffers */
- guit->misc->schedule(-1, nsgif_animate, c);
- gif_finalise(gif->gif);
+ guit->misc->schedule(-1, gif_animate_cb, c);
+ nsgif_finalise(gif->gif);
free(gif->gif);
}
-
-static nserror nsgif_clone(const struct content *old, struct content **newc)
+static nserror gif_clone(const struct content *old, struct content **newc)
{
- nsgif_content *gif;
+ gif_content *gif;
nserror error;
- gif = calloc(1, sizeof(nsgif_content));
+ gif = calloc(1, sizeof(gif_content));
if (gif == NULL)
return NSERROR_NOMEM;
@@ -355,7 +307,7 @@ static nserror nsgif_clone(const struct content *old, struct content **newc)
}
/* Simply replay creation and conversion of content */
- error = nsgif_create_gif_data(gif);
+ error = gif_create_gif_data(gif);
if (error != NSERROR_OK) {
content_destroy(&gif->base);
return error;
@@ -363,7 +315,7 @@ static nserror nsgif_clone(const struct content *old, struct content **newc)
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
- if (nsgif_convert(&gif->base) == false) {
+ if (gif_convert(&gif->base) == false) {
content_destroy(&gif->base);
return NSERROR_CLONE_FAILED;
}
@@ -374,9 +326,9 @@ static nserror nsgif_clone(const struct content *old, struct content **newc)
return NSERROR_OK;
}
-static void nsgif_add_user(struct content *c)
+static void gif_add_user(struct content *c)
{
- nsgif_content *gif = (nsgif_content *) c;
+ gif_content *gif = (gif_content *) c;
/* Ensure this content has already been converted.
* If it hasn't, the animation will start at the conversion phase instead. */
@@ -384,67 +336,63 @@ static void nsgif_add_user(struct content *c)
if (content_count_users(c) == 1) {
/* First user, and content already converted, so start the animation. */
- if (gif->gif->frame_count_partial > 1) {
- guit->misc->schedule(gif->gif->frames[0].frame_delay * 10,
- nsgif_animate, c);
+ if (nsgif_reset(gif->gif) == NSGIF_OK) {
+ gif__animate(gif, true);
}
}
}
-static void nsgif_remove_user(struct content *c)
+static void gif_remove_user(struct content *c)
{
if (content_count_users(c) == 1) {
/* Last user is about to be removed from this content, so stop the animation. */
- guit->misc->schedule(-1, nsgif_animate, c);
+ guit->misc->schedule(-1, gif_animate_cb, c);
}
}
-static void *nsgif_get_internal(const struct content *c, void *context)
+static void *gif_get_internal(const struct content *c, void *context)
{
- nsgif_content *gif = (nsgif_content *) c;
+ gif_content *gif = (gif_content *) c;
- if (gif->current_frame != gif->gif->decoded_frame) {
- if (nsgif_get_frame(gif) != GIF_OK)
- return NULL;
+ if (gif_get_frame(gif) != NSGIF_OK) {
+ return NULL;
}
return gif->gif->frame_image;
}
-static content_type nsgif_content_type(void)
+static content_type gif_content_type(void)
{
return CONTENT_IMAGE;
}
-static bool nsgif_content_is_opaque(struct content *c)
+static bool gif_content_is_opaque(struct content *c)
{
- nsgif_content *gif = (nsgif_content *) c;
+ gif_content *gif = (gif_content *) c;
- if (gif->current_frame != gif->gif->decoded_frame) {
- if (nsgif_get_frame(gif) != GIF_OK) {
- return false;
- }
+ if (gif_get_frame(gif) != NSGIF_OK) {
+ return false;
}
return guit->bitmap->get_opaque(gif->gif->frame_image);
}
-static const content_handler nsgif_content_handler = {
- .create = nsgif_create,
- .data_complete = nsgif_convert,
- .destroy = nsgif_destroy,
- .redraw = nsgif_redraw,
- .clone = nsgif_clone,
- .add_user = nsgif_add_user,
- .remove_user = nsgif_remove_user,
- .get_internal = nsgif_get_internal,
- .type = nsgif_content_type,
- .is_opaque = nsgif_content_is_opaque,
+static const content_handler gif_content_handler = {
+ .create = gif_create,
+ .data_complete = gif_convert,
+ .destroy = gif_destroy,
+ .redraw = gif_redraw,
+ .clone = gif_clone,
+ .add_user = gif_add_user,
+ .remove_user = gif_remove_user,
+ .get_internal = gif_get_internal,
+ .type = gif_content_type,
+ .is_opaque = gif_content_is_opaque,
.no_share = false,
};
-static const char *nsgif_types[] = {
+static const char *gif_types[] = {
"image/gif"
};
-CONTENT_FACTORY_REGISTER_TYPES(nsgif, nsgif_types, nsgif_content_handler);
+CONTENT_FACTORY_REGISTER_TYPES(nsgif, gif_types, gif_content_handler);
-----------------------------------------------------------------------
--
NetSurf Browser
1 year, 8 months
libnsgif: branch tlsa/gif-api created. release/0.2.1-128-g3fdfe53
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/3fdfe53755954ba41b20...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/3fdfe53755954ba41b2003...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/3fdfe53755954ba41b2003a5...
The branch, tlsa/gif-api has been created
at 3fdfe53755954ba41b2003a5d05c7e705d075d98 (commit)
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=3fdfe53755954ba41b...
commit 3fdfe53755954ba41b2003a5d05c7e705d075d98
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
WIP
diff --git a/include/nsgif.h b/include/nsgif.h
index 5e69b7e..0c95f88 100644
--- a/include/nsgif.h
+++ b/include/nsgif.h
@@ -18,6 +18,9 @@
#include <stdint.h>
#include <stdbool.h>
+#include <inttypes.h>
+
+#define NSGIF_INFINITE (UINT32_MAX)
/* Error return values */
typedef enum {
@@ -29,19 +32,28 @@ typedef enum {
NSGIF_DATA_ERROR = -4,
NSGIF_INSUFFICIENT_MEMORY = -5,
NSGIF_FRAME_NO_DISPLAY = -6,
- NSGIF_END_OF_FRAME = -7
+ NSGIF_END_OF_FRAME = -7,
+ NSGIF_FRAME_INVALID = -8,
+ NSGIF_ANIMATION_COMPLETE = -9,
} nsgif_result;
-/** GIF rectangle structure. */
+/**
+ * GIF rectangle structure.
+ *
+ * * Top left coordinate is `(x0, y0)`.
+ * * Width is `x1 - x0`.
+ * * Height is `y1 - y0`.
+ * * Units are pixels.
+ */
typedef struct nsgif_rect {
- /** x co-ordinate of redraw rectangle */
- uint32_t x;
- /** y co-ordinate of redraw rectangle */
- uint32_t y;
- /** width of redraw rectangle */
- uint32_t w;
- /** height of redraw rectangle */
- uint32_t h;
+ /** x co-ordinate of redraw rectangle, left */
+ uint32_t x0;
+ /** y co-ordinate of redraw rectangle, top */
+ uint32_t y0;
+ /** x co-ordinate of redraw rectangle, right */
+ uint32_t x1;
+ /** y co-ordinate of redraw rectangle, bottom */
+ uint32_t y1;
} nsgif_rect;
/** GIF frame data */
@@ -119,12 +131,16 @@ typedef struct nsgif {
uint32_t frame_count_partial;
/** decoded frames */
nsgif_frame *frames;
+ /** current frame */
+ uint32_t frame;
/** current frame decoded to bitmap */
- int decoded_frame;
+ uint32_t decoded_frame;
/** currently decoded image; stored as bitmap from bitmap_create callback */
void *frame_image;
- /** number of times to loop animation */
+ /** number of animation loops so far */
int loop_count;
+ /** number of times to loop animation */
+ int loop_max;
/* Internal members are listed below */
@@ -151,14 +167,17 @@ typedef struct nsgif {
/** current colour table */
uint32_t *colour_table;
+ uint16_t delay_min;
+ uint16_t delay_default;
+
/** previous frame for NSGIF_FRAME_RESTORE */
void *prev_frame;
/** previous frame index */
- int prev_index;
+ uint32_t prev_index;
/** previous frame width */
- unsigned prev_width;
+ uint32_t prev_width;
/** previous frame height */
- unsigned prev_height;
+ uint32_t prev_height;
} nsgif;
/**
@@ -167,9 +186,26 @@ typedef struct nsgif {
void nsgif_create(nsgif *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
/**
- * Initialises any workspace held by the animation and attempts to decode
- * any information that hasn't already been decoded.
- * If an error occurs, all previously decoded frames are retained.
+ * Scan the source image data.
+ *
+ * This is used to feed the source data into LibNSGIF. This must be called
+ * before calling \ref nsgif_frame_decode.
+ *
+ * It can be called multiple times with, with increasing sizes. If it is called
+ * several times, as more data is available (e.g. slow network fetch) the data
+ * already given to \ref nsgif_data_scan must be provided each time.
+ *
+ * For example, if you call \ref nsgif_data_scan with 25 bytes of data, and then
+ * fetch another 10 bytes, you would need to call \ref nsgif_data with a size of
+ * 35 bytes, and the whole 35 bytes must be contiguous memory. It is safe to
+ * `realloc` the source buffer between calls to \ref nsgif_data_scan. (The
+ * actual data pointer is allowed to be different.)
+ *
+ * If an error occurs, all previously scanned frames are retained.
+ *
+ * \param[in] gif The nsgif object.
+ * \param[in] size Number of bytes in data.
+ * \param[in] data Raw source GIF data.
*
* \return Error return value.
* - NSGIF_FRAME_DATA_ERROR for GIF frame data error
@@ -179,11 +215,30 @@ void nsgif_create(nsgif *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
* - NSGIF_OK for successful decoding
* - NSGIF_WORKING for successful decoding if more frames are expected
*/
-nsgif_result nsgif_initialise(nsgif *gif, size_t size, const uint8_t *data);
+nsgif_result nsgif_data_scan(
+ nsgif *gif,
+ size_t size,
+ const uint8_t *data);
+
+/**
+ * Prepare to show a frame.
+ *
+ * \param[in] gif The nsgif object.
+ * \param[out] area The area in pixels that must be redrawn.
+ * \param[out] delay_cs Time to wait after frame_new before next frame in cs.
+ * \param[out] frame_new The frame to decode.
+ */
+nsgif_result nsgif_frame_prepare(
+ nsgif *gif,
+ nsgif_rect *area,
+ uint32_t *delay_cs,
+ uint32_t *frame_new);
/**
* Decodes a GIF frame.
*
+ * \param[in] gif The nsgif object.
+ * \param[in] frame The frame number to decode.
* \return Error return value.
* - NSGIF_FRAME_DATA_ERROR for GIF frame data error
* - NSGIF_DATA_ERROR for GIF error (invalid frame header)
@@ -191,7 +246,37 @@ nsgif_result nsgif_initialise(nsgif *gif, size_t size, const uint8_t *data);
* - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
* - NSGIF_OK for successful decoding
*/
-nsgif_result nsgif_decode_frame(nsgif *gif, uint32_t frame);
+nsgif_result nsgif_frame_decode(
+ nsgif *gif,
+ uint32_t frame);
+
+nsgif_result nsgif_reset(
+ nsgif *gif);
+
+/*
+
+get next frame
+ 1. could wrap back to 0
+ 2. could be no next frame
+ 3. could be an un-displayable frame
+ 4. could be an un-displayable frame at the end
+ 5. could be a frame we don't have enough data for
+ 6. could think we don't have enough data, but actually it's the last anyway
+
+want to be able to get next frame if there is one
+want to know if there isn't because more data is needed
+want to be able to know if we have all frames
+
+1. nsgif_data_scan(gif, data, size, &frames);
+2. nsgif_frame_prepare(gif, 0, &redraw_area, &delay_cs);
+
+render:
+3. nsgif_decode(gif, 0);
+
+animate:
+4. nsgif_frame_prepare(gif, N, &redraw_area, &delay_cs);
+
+*/
/**
* Releases any workspace held by a gif
diff --git a/src/gif.c b/src/gif.c
index 2c11466..4019062 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -35,7 +35,7 @@
#define NSGIF_PROCESS_COLOURS 0xaa000000
/** Internal flag that a frame is invalid/unprocessed */
-#define NSGIF_INVALID_FRAME -1
+#define NSGIF_FRAME_INVALID UINT32_MAX
/** Transparent colour */
#define NSGIF_TRANSPARENT_COLOUR 0x00
@@ -183,7 +183,7 @@ static void nsgif__record_frame(
bool need_alloc = gif->prev_frame == NULL;
uint32_t *prev_frame;
- if (gif->decoded_frame == NSGIF_INVALID_FRAME ||
+ if (gif->decoded_frame == NSGIF_FRAME_INVALID ||
gif->decoded_frame == gif->prev_index) {
/* No frame to copy, or already have this frame recorded. */
return;
@@ -430,10 +430,10 @@ static inline nsgif_result nsgif__decode(
};
nsgif_result ret;
- uint32_t width = frame->redraw.w;
- uint32_t height = frame->redraw.h;
- uint32_t offset_x = frame->redraw.x;
- uint32_t offset_y = frame->redraw.y;
+ uint32_t width = frame->redraw.x1 - frame->redraw.x0;
+ uint32_t height = frame->redraw.y1 - frame->redraw.y0;
+ uint32_t offset_x = frame->redraw.x0;
+ uint32_t offset_y = frame->redraw.y0;
uint32_t interlace = frame->flags & GIF_MASK_INTERLACE;
uint32_t transparency_index = frame->transparency_index;
uint32_t *restrict colour_table = gif->colour_table;
@@ -468,10 +468,10 @@ static void nsgif__restore_bg(
memset(bitmap, NSGIF_TRANSPARENT_COLOUR,
gif->width * gif->height * sizeof(*bitmap));
} else {
- uint32_t width = frame->redraw.w;
- uint32_t height = frame->redraw.h;
- uint32_t offset_x = frame->redraw.x;
- uint32_t offset_y = frame->redraw.y;
+ uint32_t width = frame->redraw.x1 - frame->redraw.x0;
+ uint32_t height = frame->redraw.y1 - frame->redraw.y0;
+ uint32_t offset_x = frame->redraw.x0;
+ uint32_t offset_y = frame->redraw.y0;
if (frame->display == false) {
return;
@@ -514,7 +514,7 @@ static nsgif_result nsgif__update_bitmap(
/* Handle any bitmap clearing/restoration required before decoding this
* frame. */
- if (frame_idx == 0 || gif->decoded_frame == NSGIF_INVALID_FRAME) {
+ if (frame_idx == 0 || gif->decoded_frame == NSGIF_FRAME_INVALID) {
nsgif__restore_bg(gif, NULL, bitmap);
} else {
@@ -552,6 +552,7 @@ static nsgif_result nsgif__update_bitmap(
/**
* Parse the graphic control extension
*
+ * \param[in] gif The gif object we're decoding.
* \param[in] frame The gif object we're decoding.
* \param[in] data The data to decode.
* \param[in] len Byte length of data.
@@ -559,6 +560,7 @@ static nsgif_result nsgif__update_bitmap(
* NSGIF_OK for success.
*/
static nsgif_result nsgif__parse_extension_graphic_control(
+ const struct nsgif *gif,
struct nsgif_frame *frame,
const uint8_t *data,
size_t len)
@@ -585,6 +587,10 @@ static nsgif_result nsgif__parse_extension_graphic_control(
}
frame->frame_delay = data[3] | (data[4] << 8);
+ if (frame->frame_delay < gif->delay_min) {
+ frame->frame_delay = gif->delay_default;
+ }
+
if (data[2] & GIF_MASK_TRANSPARENCY) {
frame->transparency = true;
frame->transparency_index = data[5];
@@ -639,7 +645,7 @@ static nsgif_result nsgif__parse_extension_application(
if ((data[1] == 0x0b) &&
(strncmp((const char *)data + 2, "NETSCAPE2.0", 11) == 0) &&
(data[13] == 0x03) && (data[14] == 0x01)) {
- gif->loop_count = data[15] | (data[16] << 8);
+ gif->loop_max = data[15] | (data[16] << 8);
}
return NSGIF_OK;
@@ -689,7 +695,9 @@ static nsgif_result nsgif__parse_frame_extensions(
case GIF_EXT_GRAPHIC_CONTROL:
if (decode) {
ret = nsgif__parse_extension_graphic_control(
- frame, nsgif_data, nsgif_bytes);
+ gif, frame,
+ nsgif_data,
+ nsgif_bytes);
if (ret != NSGIF_OK) {
return ret;
}
@@ -793,7 +801,7 @@ static nsgif_result nsgif__parse_image_descriptor(
}
if (decode) {
- unsigned x, y, w, h;
+ uint32_t x, y, w, h;
if (data[0] != NSGIF_IMAGE_SEPARATOR) {
return NSGIF_FRAME_DATA_ERROR;
@@ -805,10 +813,10 @@ static nsgif_result nsgif__parse_image_descriptor(
h = data[7] | (data[8] << 8);
frame->flags = data[9];
- frame->redraw.x = x;
- frame->redraw.y = y;
- frame->redraw.w = w;
- frame->redraw.h = h;
+ frame->redraw.x0 = x;
+ frame->redraw.y0 = y;
+ frame->redraw.x1 = x + w;
+ frame->redraw.y1 = y + h;
/* Frame size may have grown. */
gif->width = (x + w > gif->width ) ? x + w : gif->width;
@@ -965,7 +973,7 @@ static nsgif_result nsgif__parse_image_data(
while (block_size != 1) {
if (len < 1) return NSGIF_INSUFFICIENT_DATA;
block_size = data[0] + 1;
- /* Check if the frame data runs off the end of the file */
+ /* Check if the frame data runs off the end of the file */
if (block_size > len) {
block_size = len;
return NSGIF_OK;
@@ -1074,7 +1082,7 @@ static nsgif_result nsgif__process_frame(
}
/* Done if frame is already decoded */
- if ((int)frame_idx == gif->decoded_frame) {
+ if (frame_idx == gif->decoded_frame) {
return NSGIF_OK;
}
} else {
@@ -1121,13 +1129,16 @@ cleanup:
return ret;
}
-/* exported function documented in libnsgif.h */
+/* exported function documented in nsgif.h */
void nsgif_create(nsgif *gif, nsgif_bitmap_cb_vt *bitmap)
{
memset(gif, 0, sizeof(nsgif));
gif->bitmap = *bitmap;
- gif->decoded_frame = NSGIF_INVALID_FRAME;
- gif->prev_index = NSGIF_INVALID_FRAME;
+ gif->decoded_frame = NSGIF_FRAME_INVALID;
+ gif->prev_index = NSGIF_FRAME_INVALID;
+
+ gif->delay_min = 2;
+ gif->delay_default = 10;
}
/**
@@ -1208,14 +1219,17 @@ static nsgif_result nsgif__parse_logical_screen_descriptor(
gif->colour_table_size = 2 << (data[4] & NSGIF_COLOUR_TABLE_SIZE_MASK);
gif->bg_index = data[5];
gif->aspect_ratio = data[6];
- gif->loop_count = 1;
+ gif->loop_max = 1;
*pos += 7;
return NSGIF_OK;
}
-/* exported function documented in libnsgif.h */
-nsgif_result nsgif_initialise(nsgif *gif, size_t size, const uint8_t *data)
+/* exported function documented in nsgif.h */
+nsgif_result nsgif_data_scan(
+ nsgif *gif,
+ size_t size,
+ const uint8_t *data)
{
const uint8_t *nsgif_data;
nsgif_result ret;
@@ -1241,7 +1255,8 @@ nsgif_result nsgif_initialise(nsgif *gif, size_t size, const uint8_t *data)
/* The caller may have been lazy and not reset any values */
gif->frame_count = 0;
gif->frame_count_partial = 0;
- gif->decoded_frame = NSGIF_INVALID_FRAME;
+ gif->decoded_frame = NSGIF_FRAME_INVALID;
+ gif->frame = NSGIF_FRAME_INVALID;
ret = nsgif__parse_header(gif, &nsgif_data, false);
if (ret != NSGIF_OK) {
@@ -1356,13 +1371,172 @@ nsgif_result nsgif_initialise(nsgif *gif, size_t size, const uint8_t *data)
return ret;
}
-/* exported function documented in libnsgif.h */
-nsgif_result nsgif_decode_frame(nsgif *gif, uint32_t frame)
+static void nsgif__redraw_rect_extend(const nsgif_rect *frame, nsgif_rect *redraw)
+{
+ if (redraw->x1 == 0 || redraw->y1 == 0) {
+ *redraw = *frame;
+ } else {
+ if (redraw->x0 > frame->x0) {
+ redraw->x0 = frame->x0;
+ }
+ if (redraw->x1 < frame->x1) {
+ redraw->x1 = frame->x1;
+ }
+ if (redraw->y0 > frame->y0) {
+ redraw->y0 = frame->y0;
+ }
+ if (redraw->y1 < frame->y1) {
+ redraw->y1 = frame->y1;
+ }
+ }
+}
+
+static uint32_t nsgif__frame_next(
+ nsgif *gif,
+ bool partial,
+ uint32_t frame)
+{
+ uint32_t frames = partial ?
+ gif->frame_count_partial :
+ gif->frame_count;
+
+ if (frames == 0) {
+ return NSGIF_FRAME_INVALID;
+ }
+
+ frame++;
+ return (frame >= frames) ? 0 : frame;
+}
+
+static nsgif_result nsgif__next_displayable_frame(
+ nsgif *gif,
+ uint32_t *frame,
+ uint32_t *delay)
{
- return nsgif__process_frame(gif, frame, true);
+ uint32_t next = *frame;
+
+ do {
+ next = nsgif__frame_next(gif, false, next);
+ if (next == *frame || next == NSGIF_FRAME_INVALID) {
+ return NSGIF_FRAME_NO_DISPLAY;
+ }
+
+ if (delay != NULL) {
+ *delay += gif->frames[next].frame_delay;
+ }
+
+ } while (gif->frames[next].display == false);
+
+ *frame = next;
+ return NSGIF_OK;
+}
+
+static inline bool nsgif__animation_complete(int count, int max)
+{
+ if (max == 0) {
+ return false;
+ }
+
+ return (count >= max);
+}
+
+nsgif_result nsgif_reset(
+ nsgif *gif)
+{
+ gif->loop_count = 0;
+ gif->frame = NSGIF_FRAME_INVALID;
+
+ return NSGIF_OK;
+}
+
+/* exported function documented in nsgif.h */
+nsgif_result nsgif_frame_prepare(
+ nsgif *gif,
+ nsgif_rect *area,
+ uint32_t *delay_cs,
+ uint32_t *frame_new)
+{
+ nsgif_result ret;
+ nsgif_rect rect = {
+ .x1 = 0,
+ .y1 = 0,
+ };
+ uint32_t delay = 0;
+ uint32_t frame = gif->frame;
+ uint32_t frame_next;
+
+ if (gif->frame != NSGIF_FRAME_INVALID &&
+ gif->frame != 0 &&
+ gif->frame < gif->frame_count &&
+ gif->frames[gif->frame].display) {
+ rect = gif->frames[gif->frame].redraw;
+ }
+
+ if (nsgif__animation_complete(gif->loop_count, gif->loop_max)) {
+ return NSGIF_ANIMATION_COMPLETE;
+ }
+
+ ret = nsgif__next_displayable_frame(gif, &frame, NULL);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+
+ if (gif->frame != NSGIF_FRAME_INVALID && frame < gif->frame) {
+ gif->loop_count++;
+ }
+
+ frame_next = frame;
+ ret = nsgif__next_displayable_frame(gif, &frame_next, &delay);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+
+ if (frame_next < frame) {
+ if (nsgif__animation_complete(
+ gif->loop_count + 1,
+ gif->loop_max)) {
+ delay = NSGIF_INFINITE;
+ }
+ }
+
+ gif->frame = frame;
+ nsgif__redraw_rect_extend(&gif->frames[frame].redraw, &rect);
+
+ *frame_new = gif->frame;
+ *delay_cs = delay;
+ *area = rect;
+
+ return NSGIF_OK;
+}
+
+/* exported function documented in nsgif.h */
+nsgif_result nsgif_frame_decode(nsgif *gif, uint32_t frame)
+{
+ uint32_t start_frame;
+ nsgif_result ret = NSGIF_OK;
+
+ if (gif->decoded_frame == frame) {
+ return NSGIF_OK;
+
+ } else if (gif->decoded_frame >= frame ||
+ gif->decoded_frame == NSGIF_FRAME_INVALID) {
+ /* Can skip to first frame or restart. */
+ start_frame = 0;
+ } else {
+ start_frame = nsgif__frame_next(gif, false, gif->decoded_frame);
+ }
+
+ for (uint32_t f = start_frame; f <= frame; f++) {
+ ret = nsgif__process_frame(gif, f, true);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+ }
+
+ return ret;
}
-/* exported function documented in libnsgif.h */
+/* exported function documented in nsgif.h */
void nsgif_finalise(nsgif *gif)
{
/* Release all our memory blocks */
diff --git a/test/decode_gif.c b/test/decode_gif.c
index a20d5f4..853363e 100644
--- a/test/decode_gif.c
+++ b/test/decode_gif.c
@@ -125,7 +125,7 @@ static void warning(const char *context, nsgif_result code)
fprintf(stderr, "\n");
}
-static void write_ppm(FILE* fh, const char *name, nsgif *gif,
+static void write_ppm(FILE* fh, const char *name, nsgif *gif, uint32_t frames,
bool no_write)
{
unsigned int i;
@@ -136,18 +136,18 @@ static void write_ppm(FILE* fh, const char *name, nsgif *gif,
fprintf(fh, "# %s\n", name);
fprintf(fh, "# width %u \n", gif->width);
fprintf(fh, "# height %u \n", gif->height);
- fprintf(fh, "# frame_count %u \n", gif->frame_count);
+ fprintf(fh, "# frame_count %u \n", frames);
fprintf(fh, "# frame_count_partial %u \n", gif->frame_count_partial);
fprintf(fh, "# loop_count %u \n", gif->loop_count);
fprintf(fh, "%u %u 256\n", gif->width, gif->height * gif->frame_count);
}
/* decode the frames */
- for (i = 0; i != gif->frame_count; i++) {
+ for (i = 0; i != frames; i++) {
unsigned int row, col;
unsigned char *image;
- code = nsgif_decode_frame(gif, i);
+ code = nsgif_frame_decode(gif, i);
if (code != NSGIF_OK)
warning("nsgif_decode_frame", code);
@@ -184,6 +184,7 @@ int main(int argc, char *argv[])
};
nsgif gif;
size_t size;
+ uint32_t frames;
nsgif_result code;
unsigned char *data;
FILE *outf = stdout;
@@ -220,16 +221,16 @@ int main(int argc, char *argv[])
/* begin decoding */
do {
- code = nsgif_initialise(&gif, size, data);
+ code = nsgif_data_scan(&gif, size, data, &frames);
if (code != NSGIF_OK && code != NSGIF_WORKING) {
- warning("nsgif_initialise", code);
+ warning("nsgif_data_scan", code);
nsgif_finalise(&gif);
free(data);
return 1;
}
} while (code != NSGIF_OK);
- write_ppm(outf, argv[1], &gif, no_write);
+ write_ppm(outf, argv[1], &gif, frames, no_write);
if (argc > 2 && !no_write) {
fclose(outf);
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=cfe1f467ed248ebd81...
commit cfe1f467ed248ebd8131b29634eadac89e00aa4d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
API: Rename nsgif_animation to nsgif.
diff --git a/include/nsgif.h b/include/nsgif.h
index 8e84519..5e69b7e 100644
--- a/include/nsgif.h
+++ b/include/nsgif.h
@@ -102,7 +102,7 @@ typedef struct nsgif_bitmap_cb_vt {
} nsgif_bitmap_cb_vt;
/** GIF animation data */
-typedef struct nsgif_animation {
+typedef struct nsgif {
/** LZW decode context */
void *lzw_ctx;
/** callbacks for bitmap functions */
@@ -159,12 +159,12 @@ typedef struct nsgif_animation {
unsigned prev_width;
/** previous frame height */
unsigned prev_height;
-} nsgif_animation;
+} nsgif;
/**
- * Initialises necessary nsgif_animation members.
+ * Initialises necessary nsgif members.
*/
-void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
+void nsgif_create(nsgif *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
/**
* Initialises any workspace held by the animation and attempts to decode
@@ -179,7 +179,7 @@ void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
* - NSGIF_OK for successful decoding
* - NSGIF_WORKING for successful decoding if more frames are expected
*/
-nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data);
+nsgif_result nsgif_initialise(nsgif *gif, size_t size, const uint8_t *data);
/**
* Decodes a GIF frame.
@@ -191,11 +191,11 @@ nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *
* - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
* - NSGIF_OK for successful decoding
*/
-nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame);
+nsgif_result nsgif_decode_frame(nsgif *gif, uint32_t frame);
/**
* Releases any workspace held by a gif
*/
-void nsgif_finalise(nsgif_animation *gif);
+void nsgif_finalise(nsgif *gif);
#endif
diff --git a/src/gif.c b/src/gif.c
index 96de694..2c11466 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -88,7 +88,7 @@ static nsgif_result nsgif__error_from_lzw(lzw_result l_res)
* \return NSGIF_INSUFFICIENT_MEMORY for a memory error NSGIF_OK for success
*/
static nsgif_result nsgif__initialise_sprite(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
uint32_t width,
uint32_t height)
{
@@ -113,7 +113,7 @@ static nsgif_result nsgif__initialise_sprite(
* \return Client pixel buffer for rendering into.
*/
static inline uint32_t* nsgif__bitmap_get(
- struct nsgif_animation *gif)
+ struct nsgif *gif)
{
nsgif_result ret;
@@ -134,7 +134,7 @@ static inline uint32_t* nsgif__bitmap_get(
* \param[in] gif The gif object we're decoding.
*/
static inline void nsgif__bitmap_modified(
- const struct nsgif_animation *gif)
+ const struct nsgif *gif)
{
if (gif->bitmap.modified) {
gif->bitmap.modified(gif->frame_image);
@@ -148,7 +148,7 @@ static inline void nsgif__bitmap_modified(
* \param[in] frame The frame that has been decoded.
*/
static inline void nsgif__bitmap_set_opaque(
- const struct nsgif_animation *gif,
+ const struct nsgif *gif,
const struct nsgif_frame *frame)
{
if (gif->bitmap.set_opaque) {
@@ -166,7 +166,7 @@ static inline void nsgif__bitmap_set_opaque(
* \return true if the bitmap is opaque, false otherwise.
*/
static inline bool nsgif__bitmap_get_opaque(
- const struct nsgif_animation *gif)
+ const struct nsgif *gif)
{
if (gif->bitmap.test_opaque) {
return gif->bitmap.test_opaque(
@@ -177,7 +177,7 @@ static inline bool nsgif__bitmap_get_opaque(
}
static void nsgif__record_frame(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
const uint32_t *bitmap)
{
bool need_alloc = gif->prev_frame == NULL;
@@ -218,7 +218,7 @@ static void nsgif__record_frame(
}
static nsgif_result nsgif__recover_frame(
- const struct nsgif_animation *gif,
+ const struct nsgif *gif,
uint32_t *bitmap)
{
const uint32_t *prev_frame = gif->prev_frame;
@@ -292,7 +292,7 @@ static inline bool nsgif__next_row(uint32_t interlace,
}
static nsgif_result nsgif__decode_complex(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
uint32_t width,
uint32_t height,
uint32_t offset_x,
@@ -372,7 +372,7 @@ static nsgif_result nsgif__decode_complex(
}
static nsgif_result nsgif__decode_simple(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
uint32_t height,
uint32_t offset_y,
const uint8_t *data,
@@ -420,7 +420,7 @@ static nsgif_result nsgif__decode_simple(
}
static inline nsgif_result nsgif__decode(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
struct nsgif_frame *frame,
const uint8_t *data,
uint32_t *restrict frame_data)
@@ -460,7 +460,7 @@ static inline nsgif_result nsgif__decode(
* \param[in] bitmap The bitmap to clear the frame in.
*/
static void nsgif__restore_bg(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
struct nsgif_frame *frame,
uint32_t *bitmap)
{
@@ -497,7 +497,7 @@ static void nsgif__restore_bg(
}
static nsgif_result nsgif__update_bitmap(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
struct nsgif_frame *frame,
const uint8_t *data,
uint32_t frame_idx)
@@ -620,7 +620,7 @@ static nsgif_result nsgif__parse_extension_graphic_control(
* NSGIF_OK for success.
*/
static nsgif_result nsgif__parse_extension_application(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
const uint8_t *data,
size_t len)
{
@@ -656,7 +656,7 @@ static nsgif_result nsgif__parse_extension_application(
* NSGIF_OK for success.
*/
static nsgif_result nsgif__parse_frame_extensions(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
@@ -773,7 +773,7 @@ static nsgif_result nsgif__parse_frame_extensions(
* \return NSGIF_OK on success, appropriate error otherwise.
*/
static nsgif_result nsgif__parse_image_descriptor(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
@@ -830,7 +830,7 @@ static nsgif_result nsgif__parse_image_descriptor(
* \return NSGIF_OK on success, appropriate error otherwise.
*/
static nsgif_result nsgif__colour_table_extract(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
uint32_t *colour_table,
size_t colour_table_entries,
const uint8_t **pos,
@@ -879,7 +879,7 @@ static nsgif_result nsgif__colour_table_extract(
* \return NSGIF_OK on success, appropriate error otherwise.
*/
static nsgif_result nsgif__parse_colour_table(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
@@ -917,7 +917,7 @@ static nsgif_result nsgif__parse_colour_table(
* \return NSGIF_OK on success, appropriate error otherwise.
*/
static nsgif_result nsgif__parse_image_data(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
@@ -995,7 +995,7 @@ static nsgif_result nsgif__parse_image_data(
}
static struct nsgif_frame *nsgif__get_frame(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
uint32_t frame_idx)
{
struct nsgif_frame *frame;
@@ -1044,7 +1044,7 @@ static struct nsgif_frame *nsgif__get_frame(
* - NSGIF_WORKING for successful decoding if more frames are expected
*/
static nsgif_result nsgif__process_frame(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
uint32_t frame_idx,
bool decode)
{
@@ -1122,9 +1122,9 @@ cleanup:
}
/* exported function documented in libnsgif.h */
-void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap)
+void nsgif_create(nsgif *gif, nsgif_bitmap_cb_vt *bitmap)
{
- memset(gif, 0, sizeof(nsgif_animation));
+ memset(gif, 0, sizeof(nsgif));
gif->bitmap = *bitmap;
gif->decoded_frame = NSGIF_INVALID_FRAME;
gif->prev_index = NSGIF_INVALID_FRAME;
@@ -1144,7 +1144,7 @@ void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap)
* \return NSGIF_OK on success, appropriate error otherwise.
*/
static nsgif_result nsgif__parse_header(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
const uint8_t **pos,
bool strict)
{
@@ -1192,7 +1192,7 @@ static nsgif_result nsgif__parse_header(
* \return NSGIF_OK on success, appropriate error otherwise.
*/
static nsgif_result nsgif__parse_logical_screen_descriptor(
- struct nsgif_animation *gif,
+ struct nsgif *gif,
const uint8_t **pos)
{
const uint8_t *data = *pos;
@@ -1215,7 +1215,7 @@ static nsgif_result nsgif__parse_logical_screen_descriptor(
}
/* exported function documented in libnsgif.h */
-nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data)
+nsgif_result nsgif_initialise(nsgif *gif, size_t size, const uint8_t *data)
{
const uint8_t *nsgif_data;
nsgif_result ret;
@@ -1357,13 +1357,13 @@ nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *
}
/* exported function documented in libnsgif.h */
-nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame)
+nsgif_result nsgif_decode_frame(nsgif *gif, uint32_t frame)
{
return nsgif__process_frame(gif, frame, true);
}
/* exported function documented in libnsgif.h */
-void nsgif_finalise(nsgif_animation *gif)
+void nsgif_finalise(nsgif *gif)
{
/* Release all our memory blocks */
if (gif->frame_image) {
diff --git a/test/decode_gif.c b/test/decode_gif.c
index 20cb571..a20d5f4 100644
--- a/test/decode_gif.c
+++ b/test/decode_gif.c
@@ -125,7 +125,7 @@ static void warning(const char *context, nsgif_result code)
fprintf(stderr, "\n");
}
-static void write_ppm(FILE* fh, const char *name, nsgif_animation *gif,
+static void write_ppm(FILE* fh, const char *name, nsgif *gif,
bool no_write)
{
unsigned int i;
@@ -182,7 +182,7 @@ int main(int argc, char *argv[])
bitmap_test_opaque,
bitmap_modified
};
- nsgif_animation gif;
+ nsgif gif;
size_t size;
nsgif_result code;
unsigned char *data;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=ce17f177e640bdd979...
commit ce17f177e640bdd979959782183ced4e636d7c98
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
API: Split out redraw rectangle.
diff --git a/include/nsgif.h b/include/nsgif.h
index 114addf..8e84519 100644
--- a/include/nsgif.h
+++ b/include/nsgif.h
@@ -32,6 +32,18 @@ typedef enum {
NSGIF_END_OF_FRAME = -7
} nsgif_result;
+/** GIF rectangle structure. */
+typedef struct nsgif_rect {
+ /** x co-ordinate of redraw rectangle */
+ uint32_t x;
+ /** y co-ordinate of redraw rectangle */
+ uint32_t y;
+ /** width of redraw rectangle */
+ uint32_t w;
+ /** height of redraw rectangle */
+ uint32_t h;
+} nsgif_rect;
+
/** GIF frame data */
typedef struct nsgif_frame {
/** whether the frame should be displayed/animated */
@@ -55,16 +67,11 @@ typedef struct nsgif_frame {
bool transparency;
/** the index designating a transparent pixel */
uint32_t transparency_index;
- /** x co-ordinate of redraw rectangle */
- uint32_t redraw_x;
- /** y co-ordinate of redraw rectangle */
- uint32_t redraw_y;
- /** width of redraw rectangle */
- uint32_t redraw_width;
- /** height of redraw rectangle */
- uint32_t redraw_height;
/* Frame flags */
uint32_t flags;
+
+ /** Frame's redraw rectangle. */
+ nsgif_rect redraw;
} nsgif_frame;
/* API for Bitmap callbacks */
diff --git a/src/gif.c b/src/gif.c
index 89a5a34..96de694 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -430,10 +430,10 @@ static inline nsgif_result nsgif__decode(
};
nsgif_result ret;
- uint32_t offset_x = frame->redraw_x;
- uint32_t offset_y = frame->redraw_y;
- uint32_t width = frame->redraw_width;
- uint32_t height = frame->redraw_height;
+ uint32_t width = frame->redraw.w;
+ uint32_t height = frame->redraw.h;
+ uint32_t offset_x = frame->redraw.x;
+ uint32_t offset_y = frame->redraw.y;
uint32_t interlace = frame->flags & GIF_MASK_INTERLACE;
uint32_t transparency_index = frame->transparency_index;
uint32_t *restrict colour_table = gif->colour_table;
@@ -468,10 +468,10 @@ static void nsgif__restore_bg(
memset(bitmap, NSGIF_TRANSPARENT_COLOUR,
gif->width * gif->height * sizeof(*bitmap));
} else {
- uint32_t offset_x = frame->redraw_x;
- uint32_t offset_y = frame->redraw_y;
- uint32_t width = frame->redraw_width;
- uint32_t height = frame->redraw_height;
+ uint32_t width = frame->redraw.w;
+ uint32_t height = frame->redraw.h;
+ uint32_t offset_x = frame->redraw.x;
+ uint32_t offset_y = frame->redraw.y;
if (frame->display == false) {
return;
@@ -805,10 +805,10 @@ static nsgif_result nsgif__parse_image_descriptor(
h = data[7] | (data[8] << 8);
frame->flags = data[9];
- frame->redraw_x = x;
- frame->redraw_y = y;
- frame->redraw_width = w;
- frame->redraw_height = h;
+ frame->redraw.x = x;
+ frame->redraw.y = y;
+ frame->redraw.w = w;
+ frame->redraw.h = h;
/* Frame size may have grown. */
gif->width = (x + w > gif->width ) ? x + w : gif->width;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=c1654e6dcfe4bb9f40...
commit c1654e6dcfe4bb9f400fae7a82610a13f4abc899
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
GIF: Remove redundant comment.
diff --git a/src/gif.c b/src/gif.c
index 808fa4f..89a5a34 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -1093,7 +1093,6 @@ static nsgif_result nsgif__process_frame(
}
}
- /* Initialise any extensions */
ret = nsgif__parse_frame_extensions(gif, frame, &pos, !decode);
if (ret != NSGIF_OK) {
goto cleanup;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=56b04ab7b2617e090c...
commit 56b04ab7b2617e090c1c82f828782b7e3253dfa9
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
GIF: Scope reduce frame interlace mask.
diff --git a/src/gif.c b/src/gif.c
index 9244d01..808fa4f 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -52,7 +52,6 @@ enum nsgif_disposal {
};
/* GIF Flags */
-#define NSGIF_INTERLACE_MASK 0x40
#define NSGIF_COLOUR_TABLE_MASK 0x80
#define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07
#define NSGIF_BLOCK_TERMINATOR 0x00
@@ -426,12 +425,16 @@ static inline nsgif_result nsgif__decode(
const uint8_t *data,
uint32_t *restrict frame_data)
{
+ enum {
+ GIF_MASK_INTERLACE = 0x40,
+ };
+
nsgif_result ret;
uint32_t offset_x = frame->redraw_x;
uint32_t offset_y = frame->redraw_y;
uint32_t width = frame->redraw_width;
uint32_t height = frame->redraw_height;
- uint32_t interlace = frame->flags & NSGIF_INTERLACE_MASK;
+ uint32_t interlace = frame->flags & GIF_MASK_INTERLACE;
uint32_t transparency_index = frame->transparency_index;
uint32_t *restrict colour_table = gif->colour_table;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=3efe269c0ea83df2b8...
commit 3efe269c0ea83df2b8fc5885d36e0074ff904527
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
GIF: Scope reduce graphic control extension masks.
diff --git a/src/gif.c b/src/gif.c
index dce2bb1..9244d01 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -55,8 +55,6 @@ enum nsgif_disposal {
#define NSGIF_INTERLACE_MASK 0x40
#define NSGIF_COLOUR_TABLE_MASK 0x80
#define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07
-#define NSGIF_DISPOSAL_MASK 0x1c
-#define NSGIF_TRANSPARENCY_MASK 0x01
#define NSGIF_BLOCK_TERMINATOR 0x00
#define NSGIF_TRAILER 0x3b
@@ -549,7 +547,7 @@ static nsgif_result nsgif__update_bitmap(
}
/**
- * Parse the application extension
+ * Parse the graphic control extension
*
* \param[in] frame The gif object we're decoding.
* \param[in] data The data to decode.
@@ -562,6 +560,11 @@ static nsgif_result nsgif__parse_extension_graphic_control(
const uint8_t *data,
size_t len)
{
+ enum {
+ GIF_MASK_TRANSPARENCY = 0x01,
+ GIF_MASK_DISPOSAL = 0x1c,
+ };
+
/* 6-byte Graphic Control Extension is:
*
* +0 CHAR Graphic Control Label
@@ -579,12 +582,12 @@ static nsgif_result nsgif__parse_extension_graphic_control(
}
frame->frame_delay = data[3] | (data[4] << 8);
- if (data[2] & NSGIF_TRANSPARENCY_MASK) {
+ if (data[2] & GIF_MASK_TRANSPARENCY) {
frame->transparency = true;
frame->transparency_index = data[5];
}
- frame->disposal_method = ((data[2] & NSGIF_DISPOSAL_MASK) >> 2);
+ frame->disposal_method = ((data[2] & GIF_MASK_DISPOSAL) >> 2);
/* I have encountered documentation and GIFs in the
* wild that use 0x04 to restore the previous frame,
* rather than the officially documented 0x03. I
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=5c673578e310de6e25...
commit 5c673578e310de6e254c27da735195285073483d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
GIF: Scope reduce gif extension identifier magic values.
diff --git a/src/gif.c b/src/gif.c
index 9d77894..dce2bb1 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -55,13 +55,8 @@ enum nsgif_disposal {
#define NSGIF_INTERLACE_MASK 0x40
#define NSGIF_COLOUR_TABLE_MASK 0x80
#define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07
-#define NSGIF_EXTENSION_INTRODUCER 0x21
-#define NSGIF_EXTENSION_GRAPHIC_CONTROL 0xf9
#define NSGIF_DISPOSAL_MASK 0x1c
#define NSGIF_TRANSPARENCY_MASK 0x01
-#define NSGIF_EXTENSION_COMMENT 0xfe
-#define NSGIF_EXTENSION_PLAIN_TEXT 0x01
-#define NSGIF_EXTENSION_APPLICATION 0xff
#define NSGIF_BLOCK_TERMINATOR 0x00
#define NSGIF_TRAILER 0x3b
@@ -660,12 +655,19 @@ static nsgif_result nsgif__parse_frame_extensions(
const uint8_t **pos,
bool decode)
{
+ enum {
+ GIF_EXT_INTRODUCER = 0x21,
+ GIF_EXT_GRAPHIC_CONTROL = 0xf9,
+ GIF_EXT_COMMENT = 0xfe,
+ GIF_EXT_PLAIN_TEXT = 0x01,
+ GIF_EXT_APPLICATION = 0xff,
+ };
const uint8_t *nsgif_data = *pos;
const uint8_t *nsgif_end = gif->nsgif_data + gif->buffer_size;
int nsgif_bytes = nsgif_end - nsgif_data;
/* Initialise the extensions */
- while (nsgif_bytes > 0 && nsgif_data[0] == NSGIF_EXTENSION_INTRODUCER) {
+ while (nsgif_bytes > 0 && nsgif_data[0] == GIF_EXT_INTRODUCER) {
bool block_step = true;
nsgif_result ret;
@@ -678,7 +680,7 @@ static nsgif_result nsgif__parse_frame_extensions(
/* Switch on extension label */
switch (nsgif_data[0]) {
- case NSGIF_EXTENSION_GRAPHIC_CONTROL:
+ case GIF_EXT_GRAPHIC_CONTROL:
if (decode) {
ret = nsgif__parse_extension_graphic_control(
frame, nsgif_data, nsgif_bytes);
@@ -688,7 +690,7 @@ static nsgif_result nsgif__parse_frame_extensions(
}
break;
- case NSGIF_EXTENSION_APPLICATION:
+ case GIF_EXT_APPLICATION:
if (decode) {
ret = nsgif__parse_extension_application(
gif, nsgif_data, nsgif_bytes);
@@ -698,7 +700,7 @@ static nsgif_result nsgif__parse_frame_extensions(
}
break;
- case NSGIF_EXTENSION_COMMENT:
+ case GIF_EXT_COMMENT:
/* Move the pointer to the first data sub-block Skip 1
* byte for the extension label. */
++nsgif_data;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=de0f5828f63d0db82c...
commit de0f5828f63d0db82c4157701a763796420eaa80
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
LIB: Rename public header and source file.
This allows the library header to have a name consistent with
the library soname.
diff --git a/include/libnsgif.h b/include/libnsgif.h
deleted file mode 100644
index 114addf..0000000
--- a/include/libnsgif.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2004 Richard Wilson <richard.wilson(a)netsurf-browser.org>
- * Copyright 2008 Sean Fox <dyntryx(a)gmail.com>
- * Copyright 2013-2021 Michael Drake <tlsa(a)netsurf-browser.org>
- *
- * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
- * Licenced under the MIT License,
- * http://www.opensource.org/licenses/mit-license.php
- */
-
-/**
- * \file
- * Interface to progressive animated GIF file decoding.
- */
-
-#ifndef NSNSGIF_H
-#define NSNSGIF_H
-
-#include <stdint.h>
-#include <stdbool.h>
-
-/* Error return values */
-typedef enum {
- NSGIF_WORKING = 1,
- NSGIF_OK = 0,
- NSGIF_INSUFFICIENT_DATA = -1,
- NSGIF_INSUFFICIENT_FRAME_DATA = NSGIF_INSUFFICIENT_DATA,
- NSGIF_FRAME_DATA_ERROR = -2,
- NSGIF_DATA_ERROR = -4,
- NSGIF_INSUFFICIENT_MEMORY = -5,
- NSGIF_FRAME_NO_DISPLAY = -6,
- NSGIF_END_OF_FRAME = -7
-} nsgif_result;
-
-/** GIF frame data */
-typedef struct nsgif_frame {
- /** whether the frame should be displayed/animated */
- bool display;
- /** delay (in cs) before animating the frame */
- uint32_t frame_delay;
-
- /* Internal members are listed below */
-
- /** offset (in bytes) to the GIF frame data */
- uint32_t frame_pointer;
- /** whether the frame has previously been decoded. */
- bool decoded;
- /** whether the frame is totally opaque */
- bool opaque;
- /** whether a full image redraw is required */
- bool redraw_required;
- /** how the previous frame should be disposed; affects plotting */
- uint8_t disposal_method;
- /** whether we acknowledge transparency */
- bool transparency;
- /** the index designating a transparent pixel */
- uint32_t transparency_index;
- /** x co-ordinate of redraw rectangle */
- uint32_t redraw_x;
- /** y co-ordinate of redraw rectangle */
- uint32_t redraw_y;
- /** width of redraw rectangle */
- uint32_t redraw_width;
- /** height of redraw rectangle */
- uint32_t redraw_height;
- /* Frame flags */
- uint32_t flags;
-} nsgif_frame;
-
-/* API for Bitmap callbacks */
-typedef void* (*nsgif_bitmap_cb_create)(int width, int height);
-typedef void (*nsgif_bitmap_cb_destroy)(void *bitmap);
-typedef uint8_t* (*nsgif_bitmap_cb_get_buffer)(void *bitmap);
-typedef void (*nsgif_bitmap_cb_set_opaque)(void *bitmap, bool opaque);
-typedef bool (*nsgif_bitmap_cb_test_opaque)(void *bitmap);
-typedef void (*nsgif_bitmap_cb_modified)(void *bitmap);
-
-/** Bitmap callbacks function table */
-typedef struct nsgif_bitmap_cb_vt {
- /** Create a bitmap. */
- nsgif_bitmap_cb_create create;
- /** Free a bitmap. */
- nsgif_bitmap_cb_destroy destroy;
- /** Return a pointer to the pixel data in a bitmap. */
- nsgif_bitmap_cb_get_buffer get_buffer;
-
- /* Members below are optional */
-
- /** Sets whether a bitmap should be plotted opaque. */
- nsgif_bitmap_cb_set_opaque set_opaque;
- /** Tests whether a bitmap has an opaque alpha channel. */
- nsgif_bitmap_cb_test_opaque test_opaque;
- /** The bitmap image has changed, so flush any persistent cache. */
- nsgif_bitmap_cb_modified modified;
-} nsgif_bitmap_cb_vt;
-
-/** GIF animation data */
-typedef struct nsgif_animation {
- /** LZW decode context */
- void *lzw_ctx;
- /** callbacks for bitmap functions */
- nsgif_bitmap_cb_vt bitmap;
- /** pointer to GIF data */
- const uint8_t *nsgif_data;
- /** width of GIF (may increase during decoding) */
- uint32_t width;
- /** height of GIF (may increase during decoding) */
- uint32_t height;
- /** number of frames decoded */
- uint32_t frame_count;
- /** number of frames partially decoded */
- uint32_t frame_count_partial;
- /** decoded frames */
- nsgif_frame *frames;
- /** current frame decoded to bitmap */
- int decoded_frame;
- /** currently decoded image; stored as bitmap from bitmap_create callback */
- void *frame_image;
- /** number of times to loop animation */
- int loop_count;
-
- /* Internal members are listed below */
-
- /** current index into GIF data */
- uint32_t buffer_position;
- /** total number of bytes of GIF data available */
- uint32_t buffer_size;
- /** current number of frame holders */
- uint32_t frame_holders;
- /** background index */
- uint32_t bg_index;
- /** background colour */
- uint32_t bg_colour;
- /** image aspect ratio (ignored) */
- uint32_t aspect_ratio;
- /** size of colour table (in entries) */
- uint32_t colour_table_size;
- /** whether the GIF has a global colour table */
- bool global_colours;
- /** global colour table */
- uint32_t *global_colour_table;
- /** local colour table */
- uint32_t *local_colour_table;
- /** current colour table */
- uint32_t *colour_table;
-
- /** previous frame for NSGIF_FRAME_RESTORE */
- void *prev_frame;
- /** previous frame index */
- int prev_index;
- /** previous frame width */
- unsigned prev_width;
- /** previous frame height */
- unsigned prev_height;
-} nsgif_animation;
-
-/**
- * Initialises necessary nsgif_animation members.
- */
-void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
-
-/**
- * Initialises any workspace held by the animation and attempts to decode
- * any information that hasn't already been decoded.
- * If an error occurs, all previously decoded frames are retained.
- *
- * \return Error return value.
- * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
- * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data
- * - NSGIF_INSUFFICIENT_MEMORY for memory error
- * - NSGIF_DATA_ERROR for GIF error
- * - NSGIF_OK for successful decoding
- * - NSGIF_WORKING for successful decoding if more frames are expected
- */
-nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data);
-
-/**
- * Decodes a GIF frame.
- *
- * \return Error return value.
- * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
- * - NSGIF_DATA_ERROR for GIF error (invalid frame header)
- * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data
- * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
- * - NSGIF_OK for successful decoding
- */
-nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame);
-
-/**
- * Releases any workspace held by a gif
- */
-void nsgif_finalise(nsgif_animation *gif);
-
-#endif
diff --git a/include/nsgif.h b/include/nsgif.h
new file mode 100644
index 0000000..114addf
--- /dev/null
+++ b/include/nsgif.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2004 Richard Wilson <richard.wilson(a)netsurf-browser.org>
+ * Copyright 2008 Sean Fox <dyntryx(a)gmail.com>
+ * Copyright 2013-2021 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * Interface to progressive animated GIF file decoding.
+ */
+
+#ifndef NSNSGIF_H
+#define NSNSGIF_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/* Error return values */
+typedef enum {
+ NSGIF_WORKING = 1,
+ NSGIF_OK = 0,
+ NSGIF_INSUFFICIENT_DATA = -1,
+ NSGIF_INSUFFICIENT_FRAME_DATA = NSGIF_INSUFFICIENT_DATA,
+ NSGIF_FRAME_DATA_ERROR = -2,
+ NSGIF_DATA_ERROR = -4,
+ NSGIF_INSUFFICIENT_MEMORY = -5,
+ NSGIF_FRAME_NO_DISPLAY = -6,
+ NSGIF_END_OF_FRAME = -7
+} nsgif_result;
+
+/** GIF frame data */
+typedef struct nsgif_frame {
+ /** whether the frame should be displayed/animated */
+ bool display;
+ /** delay (in cs) before animating the frame */
+ uint32_t frame_delay;
+
+ /* Internal members are listed below */
+
+ /** offset (in bytes) to the GIF frame data */
+ uint32_t frame_pointer;
+ /** whether the frame has previously been decoded. */
+ bool decoded;
+ /** whether the frame is totally opaque */
+ bool opaque;
+ /** whether a full image redraw is required */
+ bool redraw_required;
+ /** how the previous frame should be disposed; affects plotting */
+ uint8_t disposal_method;
+ /** whether we acknowledge transparency */
+ bool transparency;
+ /** the index designating a transparent pixel */
+ uint32_t transparency_index;
+ /** x co-ordinate of redraw rectangle */
+ uint32_t redraw_x;
+ /** y co-ordinate of redraw rectangle */
+ uint32_t redraw_y;
+ /** width of redraw rectangle */
+ uint32_t redraw_width;
+ /** height of redraw rectangle */
+ uint32_t redraw_height;
+ /* Frame flags */
+ uint32_t flags;
+} nsgif_frame;
+
+/* API for Bitmap callbacks */
+typedef void* (*nsgif_bitmap_cb_create)(int width, int height);
+typedef void (*nsgif_bitmap_cb_destroy)(void *bitmap);
+typedef uint8_t* (*nsgif_bitmap_cb_get_buffer)(void *bitmap);
+typedef void (*nsgif_bitmap_cb_set_opaque)(void *bitmap, bool opaque);
+typedef bool (*nsgif_bitmap_cb_test_opaque)(void *bitmap);
+typedef void (*nsgif_bitmap_cb_modified)(void *bitmap);
+
+/** Bitmap callbacks function table */
+typedef struct nsgif_bitmap_cb_vt {
+ /** Create a bitmap. */
+ nsgif_bitmap_cb_create create;
+ /** Free a bitmap. */
+ nsgif_bitmap_cb_destroy destroy;
+ /** Return a pointer to the pixel data in a bitmap. */
+ nsgif_bitmap_cb_get_buffer get_buffer;
+
+ /* Members below are optional */
+
+ /** Sets whether a bitmap should be plotted opaque. */
+ nsgif_bitmap_cb_set_opaque set_opaque;
+ /** Tests whether a bitmap has an opaque alpha channel. */
+ nsgif_bitmap_cb_test_opaque test_opaque;
+ /** The bitmap image has changed, so flush any persistent cache. */
+ nsgif_bitmap_cb_modified modified;
+} nsgif_bitmap_cb_vt;
+
+/** GIF animation data */
+typedef struct nsgif_animation {
+ /** LZW decode context */
+ void *lzw_ctx;
+ /** callbacks for bitmap functions */
+ nsgif_bitmap_cb_vt bitmap;
+ /** pointer to GIF data */
+ const uint8_t *nsgif_data;
+ /** width of GIF (may increase during decoding) */
+ uint32_t width;
+ /** height of GIF (may increase during decoding) */
+ uint32_t height;
+ /** number of frames decoded */
+ uint32_t frame_count;
+ /** number of frames partially decoded */
+ uint32_t frame_count_partial;
+ /** decoded frames */
+ nsgif_frame *frames;
+ /** current frame decoded to bitmap */
+ int decoded_frame;
+ /** currently decoded image; stored as bitmap from bitmap_create callback */
+ void *frame_image;
+ /** number of times to loop animation */
+ int loop_count;
+
+ /* Internal members are listed below */
+
+ /** current index into GIF data */
+ uint32_t buffer_position;
+ /** total number of bytes of GIF data available */
+ uint32_t buffer_size;
+ /** current number of frame holders */
+ uint32_t frame_holders;
+ /** background index */
+ uint32_t bg_index;
+ /** background colour */
+ uint32_t bg_colour;
+ /** image aspect ratio (ignored) */
+ uint32_t aspect_ratio;
+ /** size of colour table (in entries) */
+ uint32_t colour_table_size;
+ /** whether the GIF has a global colour table */
+ bool global_colours;
+ /** global colour table */
+ uint32_t *global_colour_table;
+ /** local colour table */
+ uint32_t *local_colour_table;
+ /** current colour table */
+ uint32_t *colour_table;
+
+ /** previous frame for NSGIF_FRAME_RESTORE */
+ void *prev_frame;
+ /** previous frame index */
+ int prev_index;
+ /** previous frame width */
+ unsigned prev_width;
+ /** previous frame height */
+ unsigned prev_height;
+} nsgif_animation;
+
+/**
+ * Initialises necessary nsgif_animation members.
+ */
+void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
+
+/**
+ * Initialises any workspace held by the animation and attempts to decode
+ * any information that hasn't already been decoded.
+ * If an error occurs, all previously decoded frames are retained.
+ *
+ * \return Error return value.
+ * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
+ * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data
+ * - NSGIF_INSUFFICIENT_MEMORY for memory error
+ * - NSGIF_DATA_ERROR for GIF error
+ * - NSGIF_OK for successful decoding
+ * - NSGIF_WORKING for successful decoding if more frames are expected
+ */
+nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data);
+
+/**
+ * Decodes a GIF frame.
+ *
+ * \return Error return value.
+ * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
+ * - NSGIF_DATA_ERROR for GIF error (invalid frame header)
+ * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data
+ * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
+ * - NSGIF_OK for successful decoding
+ */
+nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame);
+
+/**
+ * Releases any workspace held by a gif
+ */
+void nsgif_finalise(nsgif_animation *gif);
+
+#endif
diff --git a/src/gif.c b/src/gif.c
new file mode 100644
index 0000000..9d77894
--- /dev/null
+++ b/src/gif.c
@@ -0,0 +1,1380 @@
+/*
+ * Copyright 2004 Richard Wilson <richard.wilson(a)netsurf-browser.org>
+ * Copyright 2008 Sean Fox <dyntryx(a)gmail.com>
+ * Copyright 2013-2021 Michael Drake <tlsa(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "lzw.h"
+#include "nsgif.h"
+
+/**
+ *
+ * \file
+ * \brief GIF image decoder
+ *
+ * The GIF format is thoroughly documented; a full description can be found at
+ * http://www.w3.org/Graphics/GIF/spec-gif89a.txt
+ *
+ * \todo Plain text and comment extensions should be implemented.
+ */
+
+/** Maximum colour table size */
+#define NSGIF_MAX_COLOURS 256
+
+/** Internal flag that the colour table needs to be processed */
+#define NSGIF_PROCESS_COLOURS 0xaa000000
+
+/** Internal flag that a frame is invalid/unprocessed */
+#define NSGIF_INVALID_FRAME -1
+
+/** Transparent colour */
+#define NSGIF_TRANSPARENT_COLOUR 0x00
+
+/** No transparency */
+#define NSGIF_NO_TRANSPARENCY (0xFFFFFFFFu)
+
+enum nsgif_disposal {
+ NSGIF_DISPOSAL_UNSPECIFIED,
+ NSGIF_DISPOSAL_NONE,
+ NSGIF_DISPOSAL_RESTORE_BG,
+ NSGIF_DISPOSAL_RESTORE_PREV,
+ NSGIF_DISPOSAL_RESTORE_QUIRK, /**< Alias for NSGIF_DISPOSAL_RESTORE_PREV. */
+};
+
+/* GIF Flags */
+#define NSGIF_INTERLACE_MASK 0x40
+#define NSGIF_COLOUR_TABLE_MASK 0x80
+#define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07
+#define NSGIF_EXTENSION_INTRODUCER 0x21
+#define NSGIF_EXTENSION_GRAPHIC_CONTROL 0xf9
+#define NSGIF_DISPOSAL_MASK 0x1c
+#define NSGIF_TRANSPARENCY_MASK 0x01
+#define NSGIF_EXTENSION_COMMENT 0xfe
+#define NSGIF_EXTENSION_PLAIN_TEXT 0x01
+#define NSGIF_EXTENSION_APPLICATION 0xff
+#define NSGIF_BLOCK_TERMINATOR 0x00
+#define NSGIF_TRAILER 0x3b
+
+/**
+ * Convert an LZW result code to equivalent GIF result code.
+ *
+ * \param[in] l_res LZW response code.
+ * \return GIF result code.
+ */
+static nsgif_result nsgif__error_from_lzw(lzw_result l_res)
+{
+ static const nsgif_result g_res[] = {
+ [LZW_OK] = NSGIF_OK,
+ [LZW_OK_EOD] = NSGIF_END_OF_FRAME,
+ [LZW_NO_MEM] = NSGIF_INSUFFICIENT_MEMORY,
+ [LZW_NO_DATA] = NSGIF_INSUFFICIENT_DATA,
+ [LZW_EOI_CODE] = NSGIF_FRAME_DATA_ERROR,
+ [LZW_BAD_ICODE] = NSGIF_FRAME_DATA_ERROR,
+ [LZW_BAD_CODE] = NSGIF_FRAME_DATA_ERROR,
+ };
+ assert(l_res != LZW_BAD_PARAM);
+ assert(l_res != LZW_NO_COLOUR);
+ return g_res[l_res];
+}
+
+/**
+ * Updates the sprite memory size
+ *
+ * \param gif The animation context
+ * \param width The width of the sprite
+ * \param height The height of the sprite
+ * \return NSGIF_INSUFFICIENT_MEMORY for a memory error NSGIF_OK for success
+ */
+static nsgif_result nsgif__initialise_sprite(
+ struct nsgif_animation *gif,
+ uint32_t width,
+ uint32_t height)
+{
+ /* Already allocated? */
+ if (gif->frame_image) {
+ return NSGIF_OK;
+ }
+
+ assert(gif->bitmap.create);
+ gif->frame_image = gif->bitmap.create(width, height);
+ if (gif->frame_image == NULL) {
+ return NSGIF_INSUFFICIENT_MEMORY;
+ }
+
+ return NSGIF_OK;
+}
+
+/**
+ * Helper to get the rendering bitmap for a gif.
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \return Client pixel buffer for rendering into.
+ */
+static inline uint32_t* nsgif__bitmap_get(
+ struct nsgif_animation *gif)
+{
+ nsgif_result ret;
+
+ /* Make sure we have a buffer to decode to. */
+ ret = nsgif__initialise_sprite(gif, gif->width, gif->height);
+ if (ret != NSGIF_OK) {
+ return NULL;
+ }
+
+ /* Get the frame data */
+ assert(gif->bitmap.get_buffer);
+ return (uint32_t *)gif->bitmap.get_buffer(gif->frame_image);
+}
+
+/**
+ * Helper to tell the client that their bitmap was modified.
+ *
+ * \param[in] gif The gif object we're decoding.
+ */
+static inline void nsgif__bitmap_modified(
+ const struct nsgif_animation *gif)
+{
+ if (gif->bitmap.modified) {
+ gif->bitmap.modified(gif->frame_image);
+ }
+}
+
+/**
+ * Helper to tell the client that whether the bitmap is opaque.
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] frame The frame that has been decoded.
+ */
+static inline void nsgif__bitmap_set_opaque(
+ const struct nsgif_animation *gif,
+ const struct nsgif_frame *frame)
+{
+ if (gif->bitmap.set_opaque) {
+ gif->bitmap.set_opaque(
+ gif->frame_image, frame->opaque);
+ }
+}
+
+/**
+ * Helper to get the client to determine if the bitmap is opaque.
+ *
+ * \todo: We don't really need to get the client to do this for us.
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \return true if the bitmap is opaque, false otherwise.
+ */
+static inline bool nsgif__bitmap_get_opaque(
+ const struct nsgif_animation *gif)
+{
+ if (gif->bitmap.test_opaque) {
+ return gif->bitmap.test_opaque(
+ gif->frame_image);
+ }
+
+ return false;
+}
+
+static void nsgif__record_frame(
+ struct nsgif_animation *gif,
+ const uint32_t *bitmap)
+{
+ bool need_alloc = gif->prev_frame == NULL;
+ uint32_t *prev_frame;
+
+ if (gif->decoded_frame == NSGIF_INVALID_FRAME ||
+ gif->decoded_frame == gif->prev_index) {
+ /* No frame to copy, or already have this frame recorded. */
+ return;
+ }
+
+ bitmap = nsgif__bitmap_get(gif);
+ if (bitmap == NULL) {
+ return;
+ }
+
+ if (gif->prev_frame != NULL &&
+ gif->width * gif->height > gif->prev_width * gif->prev_height) {
+ need_alloc = true;
+ }
+
+ if (need_alloc) {
+ prev_frame = realloc(gif->prev_frame,
+ gif->width * gif->height * 4);
+ if (prev_frame == NULL) {
+ return;
+ }
+ } else {
+ prev_frame = gif->prev_frame;
+ }
+
+ memcpy(prev_frame, bitmap, gif->width * gif->height * 4);
+
+ gif->prev_frame = prev_frame;
+ gif->prev_width = gif->width;
+ gif->prev_height = gif->height;
+ gif->prev_index = gif->decoded_frame;
+}
+
+static nsgif_result nsgif__recover_frame(
+ const struct nsgif_animation *gif,
+ uint32_t *bitmap)
+{
+ const uint32_t *prev_frame = gif->prev_frame;
+ unsigned height = gif->height < gif->prev_height ? gif->height : gif->prev_height;
+ unsigned width = gif->width < gif->prev_width ? gif->width : gif->prev_width;
+
+ if (prev_frame == NULL) {
+ return NSGIF_FRAME_DATA_ERROR;
+ }
+
+ for (unsigned y = 0; y < height; y++) {
+ memcpy(bitmap, prev_frame, width * 4);
+
+ bitmap += gif->width;
+ prev_frame += gif->prev_width;
+ }
+
+ return NSGIF_OK;
+}
+
+/**
+ * Get the next line for GIF decode.
+ *
+ * Note that the step size must be initialised to 24 at the start of the frame
+ * (when y == 0). This is because of the first two passes of the frame have
+ * the same step size of 8, and the step size is used to determine the current
+ * pass.
+ *
+ * \param[in] height Frame height in pixels.
+ * \param[in,out] y Current row, starting from 0, updated on exit.
+ * \param[in,out] step Current step starting with 24, updated on exit.
+ * \return true if there is a row to process, false at the end of the frame.
+ */
+static inline bool nsgif__deinterlace(uint32_t height, uint32_t *y, uint8_t *step)
+{
+ *y += *step & 0xf;
+
+ if (*y < height) return true;
+
+ switch (*step) {
+ case 24: *y = 4; *step = 8; if (*y < height) return true;
+ /* Fall through. */
+ case 8: *y = 2; *step = 4; if (*y < height) return true;
+ /* Fall through. */
+ case 4: *y = 1; *step = 2; if (*y < height) return true;
+ /* Fall through. */
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/**
+ * Get the next line for GIF decode.
+ *
+ * \param[in] interlace Non-zero if the frame is not interlaced.
+ * \param[in] height Frame height in pixels.
+ * \param[in,out] y Current row, starting from 0, updated on exit.
+ * \param[in,out] step Current step starting with 24, updated on exit.
+ * \return true if there is a row to process, false at the end of the frame.
+ */
+static inline bool nsgif__next_row(uint32_t interlace,
+ uint32_t height, uint32_t *y, uint8_t *step)
+{
+ if (!interlace) {
+ return (++*y != height);
+ } else {
+ return nsgif__deinterlace(height, y, step);
+ }
+}
+
+static nsgif_result nsgif__decode_complex(
+ struct nsgif_animation *gif,
+ uint32_t width,
+ uint32_t height,
+ uint32_t offset_x,
+ uint32_t offset_y,
+ uint32_t interlace,
+ const uint8_t *data,
+ uint32_t transparency_index,
+ uint32_t *restrict frame_data,
+ uint32_t *restrict colour_table)
+{
+ lzw_result res;
+ nsgif_result ret = NSGIF_OK;
+ uint32_t available = 0;
+ uint8_t step = 24;
+ uint32_t y = 0;
+
+ if (height == 0) {
+ return NSGIF_OK;
+ }
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, data[0],
+ gif->nsgif_data, gif->buffer_size,
+ data + 1 - gif->nsgif_data);
+ if (res != LZW_OK) {
+ return nsgif__error_from_lzw(res);
+ }
+
+ do {
+ uint32_t x;
+ uint32_t *frame_scanline;
+
+ frame_scanline = frame_data + offset_x +
+ (y + offset_y) * gif->width;
+
+ x = width;
+ while (x > 0) {
+ const uint8_t *uncompressed;
+ unsigned row_available;
+ if (available == 0) {
+ if (res != LZW_OK) {
+ /* Unexpected end of frame, try to recover */
+ if (res == LZW_OK_EOD) {
+ ret = NSGIF_OK;
+ } else {
+ ret = nsgif__error_from_lzw(res);
+ }
+ break;
+ }
+ res = lzw_decode(gif->lzw_ctx,
+ &uncompressed, &available);
+ }
+
+ row_available = x < available ? x : available;
+ x -= row_available;
+ available -= row_available;
+ if (transparency_index > 0xFF) {
+ while (row_available-- > 0) {
+ *frame_scanline++ =
+ colour_table[*uncompressed++];
+ }
+ } else {
+ while (row_available-- > 0) {
+ register uint32_t colour;
+ colour = *uncompressed++;
+ if (colour != transparency_index) {
+ *frame_scanline =
+ colour_table[colour];
+ }
+ frame_scanline++;
+ }
+ }
+ }
+ } while (nsgif__next_row(interlace, height, &y, &step));
+
+ return ret;
+}
+
+static nsgif_result nsgif__decode_simple(
+ struct nsgif_animation *gif,
+ uint32_t height,
+ uint32_t offset_y,
+ const uint8_t *data,
+ uint32_t transparency_index,
+ uint32_t *restrict frame_data,
+ uint32_t *restrict colour_table)
+{
+ uint32_t pixels = gif->width * height;
+ uint32_t written = 0;
+ nsgif_result ret = NSGIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init_map(gif->lzw_ctx, data[0],
+ transparency_index, colour_table,
+ gif->nsgif_data, gif->buffer_size,
+ data + 1 - gif->nsgif_data);
+ if (res != LZW_OK) {
+ return nsgif__error_from_lzw(res);
+ }
+
+ frame_data += (offset_y * gif->width);
+
+ while (pixels > 0) {
+ res = lzw_decode_map(gif->lzw_ctx,
+ 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 = NSGIF_OK;
+ } else {
+ ret = nsgif__error_from_lzw(res);
+ }
+ break;
+ }
+ }
+
+ if (pixels == 0) {
+ ret = NSGIF_OK;
+ }
+
+ return ret;
+}
+
+static inline nsgif_result nsgif__decode(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
+ const uint8_t *data,
+ uint32_t *restrict frame_data)
+{
+ nsgif_result ret;
+ uint32_t offset_x = frame->redraw_x;
+ uint32_t offset_y = frame->redraw_y;
+ uint32_t width = frame->redraw_width;
+ uint32_t height = frame->redraw_height;
+ uint32_t interlace = frame->flags & NSGIF_INTERLACE_MASK;
+ uint32_t transparency_index = frame->transparency_index;
+ uint32_t *restrict colour_table = gif->colour_table;
+
+ if (interlace == false && width == gif->width && offset_x == 0) {
+ ret = nsgif__decode_simple(gif, height, offset_y,
+ data, transparency_index,
+ frame_data, colour_table);
+ } else {
+ ret = nsgif__decode_complex(gif, width, height,
+ offset_x, offset_y, interlace,
+ data, transparency_index,
+ frame_data, colour_table);
+ }
+
+ return ret;
+}
+
+/**
+ * Restore a GIF to the background colour.
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] frame The frame to clear, or NULL.
+ * \param[in] bitmap The bitmap to clear the frame in.
+ */
+static void nsgif__restore_bg(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
+ uint32_t *bitmap)
+{
+ if (frame == NULL) {
+ memset(bitmap, NSGIF_TRANSPARENT_COLOUR,
+ gif->width * gif->height * sizeof(*bitmap));
+ } else {
+ uint32_t offset_x = frame->redraw_x;
+ uint32_t offset_y = frame->redraw_y;
+ uint32_t width = frame->redraw_width;
+ uint32_t height = frame->redraw_height;
+
+ if (frame->display == false) {
+ return;
+ }
+
+ if (frame->transparency) {
+ for (uint32_t y = 0; y < height; y++) {
+ uint32_t *scanline = bitmap + offset_x +
+ (offset_y + y) * gif->width;
+ memset(scanline, NSGIF_TRANSPARENT_COLOUR,
+ width * sizeof(*bitmap));
+ }
+ } else {
+ for (uint32_t y = 0; y < height; y++) {
+ uint32_t *scanline = bitmap + offset_x +
+ (offset_y + y) * gif->width;
+ for (uint32_t x = 0; x < width; x++) {
+ scanline[x] = gif->bg_colour;
+ }
+ }
+ }
+ }
+}
+
+static nsgif_result nsgif__update_bitmap(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
+ const uint8_t *data,
+ uint32_t frame_idx)
+{
+ nsgif_result ret;
+ uint32_t *bitmap;
+
+ gif->decoded_frame = frame_idx;
+
+ bitmap = nsgif__bitmap_get(gif);
+ if (bitmap == NULL) {
+ return NSGIF_INSUFFICIENT_MEMORY;
+ }
+
+ /* Handle any bitmap clearing/restoration required before decoding this
+ * frame. */
+ if (frame_idx == 0 || gif->decoded_frame == NSGIF_INVALID_FRAME) {
+ nsgif__restore_bg(gif, NULL, bitmap);
+
+ } else {
+ struct nsgif_frame *prev = &gif->frames[frame_idx - 1];
+
+ if (prev->disposal_method == NSGIF_DISPOSAL_RESTORE_BG) {
+ nsgif__restore_bg(gif, prev, bitmap);
+
+ } else if (prev->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV) {
+ ret = nsgif__recover_frame(gif, bitmap);
+ if (ret != NSGIF_OK) {
+ nsgif__restore_bg(gif, prev, bitmap);
+ }
+ }
+ }
+
+ if (frame->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV) {
+ /* Store the previous frame for later restoration */
+ nsgif__record_frame(gif, bitmap);
+ }
+
+ ret = nsgif__decode(gif, frame, data, bitmap);
+
+ nsgif__bitmap_modified(gif);
+
+ if (!frame->decoded) {
+ frame->opaque = nsgif__bitmap_get_opaque(gif);
+ frame->decoded = true;
+ }
+ nsgif__bitmap_set_opaque(gif, frame);
+
+ return ret;
+}
+
+/**
+ * Parse the application extension
+ *
+ * \param[in] frame The gif object we're decoding.
+ * \param[in] data The data to decode.
+ * \param[in] len Byte length of data.
+ * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
+ * NSGIF_OK for success.
+ */
+static nsgif_result nsgif__parse_extension_graphic_control(
+ struct nsgif_frame *frame,
+ const uint8_t *data,
+ size_t len)
+{
+ /* 6-byte Graphic Control Extension is:
+ *
+ * +0 CHAR Graphic Control Label
+ * +1 CHAR Block Size
+ * +2 CHAR __Packed Fields__
+ * 3BITS Reserved
+ * 3BITS Disposal Method
+ * 1BIT User Input Flag
+ * 1BIT Transparent Color Flag
+ * +3 SHORT Delay Time
+ * +5 CHAR Transparent Color Index
+ */
+ if (len < 6) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ frame->frame_delay = data[3] | (data[4] << 8);
+ if (data[2] & NSGIF_TRANSPARENCY_MASK) {
+ frame->transparency = true;
+ frame->transparency_index = data[5];
+ }
+
+ frame->disposal_method = ((data[2] & NSGIF_DISPOSAL_MASK) >> 2);
+ /* I have encountered documentation and GIFs in the
+ * wild that use 0x04 to restore the previous frame,
+ * rather than the officially documented 0x03. I
+ * believe some (older?) software may even actually
+ * export this way. We handle this as a type of
+ * "quirks" mode. */
+ if (frame->disposal_method == NSGIF_DISPOSAL_RESTORE_QUIRK) {
+ frame->disposal_method = NSGIF_DISPOSAL_RESTORE_PREV;
+ }
+
+ /* if we are clearing the background then we need to
+ * redraw enough to cover the previous frame too. */
+ frame->redraw_required =
+ frame->disposal_method == NSGIF_DISPOSAL_RESTORE_BG ||
+ frame->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV;
+
+ return NSGIF_OK;
+}
+
+/**
+ * Parse the application extension
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] data The data to decode.
+ * \param[in] len Byte length of data.
+ * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
+ * NSGIF_OK for success.
+ */
+static nsgif_result nsgif__parse_extension_application(
+ struct nsgif_animation *gif,
+ const uint8_t *data,
+ size_t len)
+{
+ /* 14-byte+ Application Extension is:
+ *
+ * +0 CHAR Application Extension Label
+ * +1 CHAR Block Size
+ * +2 8CHARS Application Identifier
+ * +10 3CHARS Appl. Authentication Code
+ * +13 1-256 Application Data (Data sub-blocks)
+ */
+ if (len < 17) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ if ((data[1] == 0x0b) &&
+ (strncmp((const char *)data + 2, "NETSCAPE2.0", 11) == 0) &&
+ (data[13] == 0x03) && (data[14] == 0x01)) {
+ gif->loop_count = data[15] | (data[16] << 8);
+ }
+
+ return NSGIF_OK;
+}
+
+/**
+ * Parse the frame's extensions
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] frame The frame to parse extensions for.
+ * \param[in] pos Current position in data, updated on exit.
+ * \param[in] decode Whether to decode or skip over the extension.
+ * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
+ * NSGIF_OK for success.
+ */
+static nsgif_result nsgif__parse_frame_extensions(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
+ const uint8_t **pos,
+ bool decode)
+{
+ const uint8_t *nsgif_data = *pos;
+ const uint8_t *nsgif_end = gif->nsgif_data + gif->buffer_size;
+ int nsgif_bytes = nsgif_end - nsgif_data;
+
+ /* Initialise the extensions */
+ while (nsgif_bytes > 0 && nsgif_data[0] == NSGIF_EXTENSION_INTRODUCER) {
+ bool block_step = true;
+ nsgif_result ret;
+
+ nsgif_data++;
+ nsgif_bytes--;
+
+ if (nsgif_bytes == 0) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ /* Switch on extension label */
+ switch (nsgif_data[0]) {
+ case NSGIF_EXTENSION_GRAPHIC_CONTROL:
+ if (decode) {
+ ret = nsgif__parse_extension_graphic_control(
+ frame, nsgif_data, nsgif_bytes);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+ }
+ break;
+
+ case NSGIF_EXTENSION_APPLICATION:
+ if (decode) {
+ ret = nsgif__parse_extension_application(
+ gif, nsgif_data, nsgif_bytes);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+ }
+ break;
+
+ case NSGIF_EXTENSION_COMMENT:
+ /* Move the pointer to the first data sub-block Skip 1
+ * byte for the extension label. */
+ ++nsgif_data;
+ block_step = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if (block_step) {
+ /* Move the pointer to the first data sub-block Skip 2
+ * bytes for the extension label and size fields Skip
+ * the extension size itself
+ */
+ if (nsgif_bytes < 2) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+ nsgif_data += 2 + nsgif_data[1];
+ }
+
+ /* Repeatedly skip blocks until we get a zero block or run out
+ * of data. This data is ignored by this gif decoder. */
+ while (nsgif_data < nsgif_end && nsgif_data[0] != NSGIF_BLOCK_TERMINATOR) {
+ nsgif_data += nsgif_data[0] + 1;
+ if (nsgif_data >= nsgif_end) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+ }
+ nsgif_data++;
+ nsgif_bytes = nsgif_end - nsgif_data;
+ }
+
+ if (nsgif_data > nsgif_end) {
+ nsgif_data = nsgif_end;
+ }
+
+ /* Set buffer position and return */
+ *pos = nsgif_data;
+ return NSGIF_OK;
+}
+
+/**
+ * Parse a GIF Image Descriptor.
+ *
+ * The format is:
+ *
+ * +0 CHAR Image Separator (0x2c)
+ * +1 SHORT Image Left Position
+ * +3 SHORT Image Top Position
+ * +5 SHORT Width
+ * +7 SHORT Height
+ * +9 CHAR __Packed Fields__
+ * 1BIT Local Colour Table Flag
+ * 1BIT Interlace Flag
+ * 1BIT Sort Flag
+ * 2BITS Reserved
+ * 3BITS Size of Local Colour Table
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] frame The frame to parse an image descriptor for.
+ * \param[in] pos Current position in data, updated on exit.
+ * \param[in] decode Whether to decode the image descriptor.
+ * \return NSGIF_OK on success, appropriate error otherwise.
+ */
+static nsgif_result nsgif__parse_image_descriptor(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
+ const uint8_t **pos,
+ bool decode)
+{
+ const uint8_t *data = *pos;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
+ enum {
+ NSGIF_IMAGE_DESCRIPTOR_LEN = 10u,
+ NSGIF_IMAGE_SEPARATOR = 0x2Cu,
+ };
+
+ assert(gif != NULL);
+ assert(frame != NULL);
+
+ if (len < NSGIF_IMAGE_DESCRIPTOR_LEN) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ if (decode) {
+ unsigned x, y, w, h;
+
+ if (data[0] != NSGIF_IMAGE_SEPARATOR) {
+ return NSGIF_FRAME_DATA_ERROR;
+ }
+
+ x = data[1] | (data[2] << 8);
+ y = data[3] | (data[4] << 8);
+ w = data[5] | (data[6] << 8);
+ h = data[7] | (data[8] << 8);
+ frame->flags = data[9];
+
+ frame->redraw_x = x;
+ frame->redraw_y = y;
+ frame->redraw_width = w;
+ frame->redraw_height = h;
+
+ /* Frame size may have grown. */
+ gif->width = (x + w > gif->width ) ? x + w : gif->width;
+ gif->height = (y + h > gif->height) ? y + h : gif->height;
+ }
+
+ *pos += NSGIF_IMAGE_DESCRIPTOR_LEN;
+ return NSGIF_OK;
+}
+
+/**
+ * Extract a GIF colour table into a LibNSGIF colour table buffer.
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] colour_table The colour table to populate.
+ * \param[in] colour_table_entries The number of colour table entries.
+ * \param[in] pos Current position in data, updated on exit.
+ * \param[in] decode Whether to decode the colour table.
+ * \return NSGIF_OK on success, appropriate error otherwise.
+ */
+static nsgif_result nsgif__colour_table_extract(
+ struct nsgif_animation *gif,
+ uint32_t *colour_table,
+ size_t colour_table_entries,
+ const uint8_t **pos,
+ bool decode)
+{
+ const uint8_t *data = *pos;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
+
+ if (len < colour_table_entries * 3) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ if (decode) {
+ int count = colour_table_entries;
+ uint8_t *entry = (uint8_t *)colour_table;
+
+ while (count--) {
+ /* Gif colour map contents are r,g,b.
+ *
+ * We want to pack them bytewise into the
+ * colour table, such that the red component
+ * is in byte 0 and the alpha component is in
+ * byte 3.
+ */
+
+ *entry++ = *data++; /* r */
+ *entry++ = *data++; /* g */
+ *entry++ = *data++; /* b */
+ *entry++ = 0xff; /* a */
+ }
+ }
+
+ *pos += colour_table_entries * 3;
+ return NSGIF_OK;
+}
+
+/**
+ * Get a frame's colour table.
+ *
+ * Sets up gif->colour_table for the frame.
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] frame The frame to get the colour table for.
+ * \param[in] pos Current position in data, updated on exit.
+ * \param[in] decode Whether to decode the colour table.
+ * \return NSGIF_OK on success, appropriate error otherwise.
+ */
+static nsgif_result nsgif__parse_colour_table(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
+ const uint8_t **pos,
+ bool decode)
+{
+ nsgif_result ret;
+
+ assert(gif != NULL);
+ assert(frame != NULL);
+
+ if ((frame->flags & NSGIF_COLOUR_TABLE_MASK) == 0) {
+ gif->colour_table = gif->global_colour_table;
+ return NSGIF_OK;
+ }
+
+ ret = nsgif__colour_table_extract(gif, gif->local_colour_table,
+ 2 << (frame->flags & NSGIF_COLOUR_TABLE_SIZE_MASK),
+ pos, decode);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+
+ gif->colour_table = gif->local_colour_table;
+ return NSGIF_OK;
+}
+
+/**
+ * Parse the image data for a gif frame.
+ *
+ * Sets up gif->colour_table for the frame.
+ *
+ * \param[in] gif The gif object we're decoding.
+ * \param[in] frame The frame to parse image data for.
+ * \param[in] pos Current position in data, updated on exit.
+ * \param[in] decode Whether to decode the image data.
+ * \return NSGIF_OK on success, appropriate error otherwise.
+ */
+static nsgif_result nsgif__parse_image_data(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
+ const uint8_t **pos,
+ bool decode)
+{
+ const uint8_t *data = *pos;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
+ uint32_t frame_idx = frame - gif->frames;
+ uint8_t minimum_code_size;
+ nsgif_result ret;
+
+ assert(gif != NULL);
+ assert(frame != NULL);
+
+ if (!decode) {
+ gif->frame_count_partial = frame_idx + 1;
+ }
+
+ /* Ensure sufficient data remains. A gif trailer or a minimum lzw code
+ * followed by a gif trailer is treated as OK, although without any
+ * image data. */
+ switch (len) {
+ default: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
+ break;
+ case 2: if (data[1] == NSGIF_TRAILER) return NSGIF_OK;
+ /* Fall through. */
+ case 1: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
+ /* Fall through. */
+ case 0: return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ minimum_code_size = data[0];
+ if (minimum_code_size >= LZW_CODE_MAX) {
+ return NSGIF_DATA_ERROR;
+ }
+
+ if (decode) {
+ ret = nsgif__update_bitmap(gif, frame, data, frame_idx);
+ } else {
+ uint32_t block_size = 0;
+
+ /* Skip the minimum code size. */
+ data++;
+ len--;
+
+ while (block_size != 1) {
+ if (len < 1) return NSGIF_INSUFFICIENT_DATA;
+ block_size = data[0] + 1;
+ /* Check if the frame data runs off the end of the file */
+ if (block_size > len) {
+ block_size = len;
+ return NSGIF_OK;
+ }
+
+ len -= block_size;
+ data += block_size;
+ }
+
+ gif->frame_count = frame_idx + 1;
+ gif->frames[frame_idx].display = true;
+ *pos = data;
+
+ /* Check if we've finished */
+ if (len < 1) {
+ return NSGIF_INSUFFICIENT_DATA;
+ } else {
+ if (data[0] == NSGIF_TRAILER) {
+ return NSGIF_OK;
+ }
+ }
+
+ return NSGIF_WORKING;
+ }
+
+ return ret;
+}
+
+static struct nsgif_frame *nsgif__get_frame(
+ struct nsgif_animation *gif,
+ uint32_t frame_idx)
+{
+ struct nsgif_frame *frame;
+
+ if (gif->frame_holders > frame_idx) {
+ frame = &gif->frames[frame_idx];
+ } else {
+ /* Allocate more memory */
+ size_t count = frame_idx + 1;
+ struct nsgif_frame *temp;
+
+ temp = realloc(gif->frames, count * sizeof(*frame));
+ if (temp == NULL) {
+ return NULL;
+ }
+ gif->frames = temp;
+ gif->frame_holders = count;
+
+ frame = &gif->frames[frame_idx];
+
+ frame->transparency = false;
+ frame->transparency_index = NSGIF_NO_TRANSPARENCY;
+ frame->frame_pointer = gif->buffer_position;
+ frame->redraw_required = false;
+ frame->disposal_method = 0;
+ frame->frame_delay = 100;
+ frame->display = false;
+ frame->decoded = false;
+ }
+
+ return frame;
+}
+
+/**
+ * Attempts to initialise the next frame
+ *
+ * \param[in] gif The animation context
+ * \param[in] frame_idx The frame number to decode.
+ * \param[in] decode Whether to decode the graphical image data.
+ * \return error code
+ * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data.
+ * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
+ * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
+ * - NSGIF_DATA_ERROR for GIF error (invalid frame header)
+ * - NSGIF_OK for successful decoding
+ * - NSGIF_WORKING for successful decoding if more frames are expected
+*/
+static nsgif_result nsgif__process_frame(
+ struct nsgif_animation *gif,
+ uint32_t frame_idx,
+ bool decode)
+{
+ nsgif_result ret;
+ const uint8_t *pos;
+ const uint8_t *end;
+ struct nsgif_frame *frame;
+
+ frame = nsgif__get_frame(gif, frame_idx);
+ if (frame == NULL) {
+ return NSGIF_INSUFFICIENT_MEMORY;
+ }
+
+ end = gif->nsgif_data + gif->buffer_size;
+
+ if (decode) {
+ pos = gif->nsgif_data + frame->frame_pointer;
+
+ /* Ensure this frame is supposed to be decoded */
+ if (frame->display == false) {
+ return NSGIF_OK;
+ }
+
+ /* Ensure the frame is in range to decode */
+ if (frame_idx > gif->frame_count_partial) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ /* Done if frame is already decoded */
+ if ((int)frame_idx == gif->decoded_frame) {
+ return NSGIF_OK;
+ }
+ } else {
+ pos = (uint8_t *)(gif->nsgif_data + gif->buffer_position);
+
+ /* Check if we've finished */
+ if (pos < end && pos[0] == NSGIF_TRAILER) {
+ return NSGIF_OK;
+ }
+
+ /* We could theoretically get some junk data that gives us
+ * millions of frames, so we ensure that we don't have a
+ * silly number. */
+ if (frame_idx > 4096) {
+ return NSGIF_FRAME_DATA_ERROR;
+ }
+ }
+
+ /* Initialise any extensions */
+ ret = nsgif__parse_frame_extensions(gif, frame, &pos, !decode);
+ if (ret != NSGIF_OK) {
+ goto cleanup;
+ }
+
+ ret = nsgif__parse_image_descriptor(gif, frame, &pos, !decode);
+ if (ret != NSGIF_OK) {
+ goto cleanup;
+ }
+
+ ret = nsgif__parse_colour_table(gif, frame, &pos, decode);
+ if (ret != NSGIF_OK) {
+ goto cleanup;
+ }
+
+ ret = nsgif__parse_image_data(gif, frame, &pos, decode);
+ if (ret != NSGIF_OK) {
+ goto cleanup;
+ }
+
+cleanup:
+ if (!decode) {
+ gif->buffer_position = pos - gif->nsgif_data;
+ }
+
+ return ret;
+}
+
+/* exported function documented in libnsgif.h */
+void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap)
+{
+ memset(gif, 0, sizeof(nsgif_animation));
+ gif->bitmap = *bitmap;
+ gif->decoded_frame = NSGIF_INVALID_FRAME;
+ gif->prev_index = NSGIF_INVALID_FRAME;
+}
+
+/**
+ * Read GIF header.
+ *
+ * 6-byte GIF file header is:
+ *
+ * +0 3CHARS Signature ('GIF')
+ * +3 3CHARS Version ('87a' or '89a')
+ *
+ * \param[in] gif The GIF object we're decoding.
+ * \param[in,out] pos The current buffer position, updated on success.
+ * \param[in] strict Whether to require a known GIF version.
+ * \return NSGIF_OK on success, appropriate error otherwise.
+ */
+static nsgif_result nsgif__parse_header(
+ struct nsgif_animation *gif,
+ const uint8_t **pos,
+ bool strict)
+{
+ const uint8_t *data = *pos;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
+
+ if (len < 6) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ if (strncmp((const char *) data, "GIF", 3) != 0) {
+ return NSGIF_DATA_ERROR;
+ }
+ data += 3;
+
+ if (strict == true) {
+ if ((strncmp((const char *) data, "87a", 3) != 0) &&
+ (strncmp((const char *) data, "89a", 3) != 0)) {
+ return NSGIF_DATA_ERROR;
+ }
+ }
+ data += 3;
+
+ *pos = data;
+ return NSGIF_OK;
+}
+
+/**
+ * Read Logical Screen Descriptor.
+ *
+ * 7-byte Logical Screen Descriptor is:
+ *
+ * +0 SHORT Logical Screen Width
+ * +2 SHORT Logical Screen Height
+ * +4 CHAR __Packed Fields__
+ * 1BIT Global Colour Table Flag
+ * 3BITS Colour Resolution
+ * 1BIT Sort Flag
+ * 3BITS Size of Global Colour Table
+ * +5 CHAR Background Colour Index
+ * +6 CHAR Pixel Aspect Ratio
+ *
+ * \param[in] gif The GIF object we're decoding.
+ * \param[in,out] pos The current buffer position, updated on success.
+ * \return NSGIF_OK on success, appropriate error otherwise.
+ */
+static nsgif_result nsgif__parse_logical_screen_descriptor(
+ struct nsgif_animation *gif,
+ const uint8_t **pos)
+{
+ const uint8_t *data = *pos;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
+
+ if (len < 7) {
+ return NSGIF_INSUFFICIENT_DATA;
+ }
+
+ gif->width = data[0] | (data[1] << 8);
+ gif->height = data[2] | (data[3] << 8);
+ gif->global_colours = data[4] & NSGIF_COLOUR_TABLE_MASK;
+ gif->colour_table_size = 2 << (data[4] & NSGIF_COLOUR_TABLE_SIZE_MASK);
+ gif->bg_index = data[5];
+ gif->aspect_ratio = data[6];
+ gif->loop_count = 1;
+
+ *pos += 7;
+ return NSGIF_OK;
+}
+
+/* exported function documented in libnsgif.h */
+nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data)
+{
+ const uint8_t *nsgif_data;
+ nsgif_result ret;
+
+ /* Initialize values */
+ gif->buffer_size = size;
+ gif->nsgif_data = data;
+
+ /* Get our current processing position */
+ nsgif_data = gif->nsgif_data + gif->buffer_position;
+
+ /* See if we should initialise the GIF */
+ if (gif->buffer_position == 0) {
+ /* We want everything to be NULL before we start so we've no
+ * chance of freeing bad pointers (paranoia)
+ */
+ gif->frame_image = NULL;
+ gif->frames = NULL;
+ gif->frame_holders = 0;
+ gif->local_colour_table = NULL;
+ gif->global_colour_table = NULL;
+
+ /* The caller may have been lazy and not reset any values */
+ gif->frame_count = 0;
+ gif->frame_count_partial = 0;
+ gif->decoded_frame = NSGIF_INVALID_FRAME;
+
+ ret = nsgif__parse_header(gif, &nsgif_data, false);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+
+ ret = nsgif__parse_logical_screen_descriptor(gif, &nsgif_data);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+
+ /* Remember we've done this now */
+ gif->buffer_position = nsgif_data - gif->nsgif_data;
+
+ /* Some broken GIFs report the size as the screen size they
+ * were created in. As such, we detect for the common cases and
+ * set the sizes as 0 if they are found which results in the
+ * GIF being the maximum size of the frames.
+ */
+ if (((gif->width == 640) && (gif->height == 480)) ||
+ ((gif->width == 640) && (gif->height == 512)) ||
+ ((gif->width == 800) && (gif->height == 600)) ||
+ ((gif->width == 1024) && (gif->height == 768)) ||
+ ((gif->width == 1280) && (gif->height == 1024)) ||
+ ((gif->width == 1600) && (gif->height == 1200)) ||
+ ((gif->width == 0) || (gif->height == 0)) ||
+ ((gif->width > 2048) || (gif->height > 2048))) {
+ gif->width = 1;
+ gif->height = 1;
+ }
+
+ /* Allocate some data irrespective of whether we've got any
+ * colour tables. We always get the maximum size in case a GIF
+ * is lying to us. It's far better to give the wrong colours
+ * than to trample over some memory somewhere.
+ */
+ gif->global_colour_table = calloc(NSGIF_MAX_COLOURS, sizeof(uint32_t));
+ gif->local_colour_table = calloc(NSGIF_MAX_COLOURS, sizeof(uint32_t));
+ if ((gif->global_colour_table == NULL) ||
+ (gif->local_colour_table == NULL)) {
+ nsgif_finalise(gif);
+ return NSGIF_INSUFFICIENT_MEMORY;
+ }
+
+ /* Set the first colour to a value that will never occur in
+ * reality so we know if we've processed it
+ */
+ gif->global_colour_table[0] = NSGIF_PROCESS_COLOURS;
+
+ /* Check if the GIF has no frame data (13-byte header + 1-byte
+ * termination block) Although generally useless, the GIF
+ * specification does not expressly prohibit this
+ */
+ if (gif->buffer_size == gif->buffer_position + 1) {
+ if (nsgif_data[0] == NSGIF_TRAILER) {
+ return NSGIF_OK;
+ }
+ }
+ }
+
+ /* Do the colour map if we haven't already. As the top byte is always
+ * 0xff or 0x00 depending on the transparency we know if it's been
+ * filled in.
+ */
+ if (gif->global_colour_table[0] == NSGIF_PROCESS_COLOURS) {
+ /* Check for a global colour map signified by bit 7 */
+ if (gif->global_colours) {
+ ret = nsgif__colour_table_extract(gif,
+ gif->global_colour_table,
+ gif->colour_table_size,
+ &nsgif_data, true);
+ if (ret != NSGIF_OK) {
+ return ret;
+ }
+
+ gif->buffer_position = (nsgif_data - gif->nsgif_data);
+ } else {
+ /* Create a default colour table with the first two
+ * colours as black and white
+ */
+ uint32_t *entry = gif->global_colour_table;
+
+ entry[0] = 0x00000000;
+ /* Force Alpha channel to opaque */
+ ((uint8_t *) entry)[3] = 0xff;
+
+ entry[1] = 0xffffffff;
+ }
+
+ if (gif->global_colours &&
+ gif->bg_index < gif->colour_table_size) {
+ size_t bg_idx = gif->bg_index;
+ gif->bg_colour = gif->global_colour_table[bg_idx];
+ } else {
+ gif->bg_colour = gif->global_colour_table[0];
+ }
+ }
+
+ if (gif->lzw_ctx == NULL) {
+ lzw_result res = lzw_context_create(
+ (struct lzw_ctx **)&gif->lzw_ctx);
+ if (res != LZW_OK) {
+ return nsgif__error_from_lzw(res);
+ }
+ }
+
+ /* Repeatedly try to initialise frames */
+ do {
+ ret = nsgif__process_frame(gif, gif->frame_count, false);
+ } while (ret == NSGIF_WORKING);
+
+ return ret;
+}
+
+/* exported function documented in libnsgif.h */
+nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame)
+{
+ return nsgif__process_frame(gif, frame, true);
+}
+
+/* exported function documented in libnsgif.h */
+void nsgif_finalise(nsgif_animation *gif)
+{
+ /* Release all our memory blocks */
+ if (gif->frame_image) {
+ assert(gif->bitmap.destroy);
+ gif->bitmap.destroy(gif->frame_image);
+ }
+
+ gif->frame_image = NULL;
+ free(gif->frames);
+ gif->frames = NULL;
+ free(gif->local_colour_table);
+ gif->local_colour_table = NULL;
+ free(gif->global_colour_table);
+ gif->global_colour_table = NULL;
+
+ free(gif->prev_frame);
+ gif->prev_frame = NULL;
+
+ lzw_context_destroy(gif->lzw_ctx);
+ gif->lzw_ctx = NULL;
+}
diff --git a/src/libnsgif.c b/src/libnsgif.c
deleted file mode 100644
index 9d77894..0000000
--- a/src/libnsgif.c
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
- * Copyright 2004 Richard Wilson <richard.wilson(a)netsurf-browser.org>
- * Copyright 2008 Sean Fox <dyntryx(a)gmail.com>
- * Copyright 2013-2021 Michael Drake <tlsa(a)netsurf-browser.org>
- *
- * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
- * Licenced under the MIT License,
- * http://www.opensource.org/licenses/mit-license.php
- */
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-
-#include "lzw.h"
-#include "nsgif.h"
-
-/**
- *
- * \file
- * \brief GIF image decoder
- *
- * The GIF format is thoroughly documented; a full description can be found at
- * http://www.w3.org/Graphics/GIF/spec-gif89a.txt
- *
- * \todo Plain text and comment extensions should be implemented.
- */
-
-/** Maximum colour table size */
-#define NSGIF_MAX_COLOURS 256
-
-/** Internal flag that the colour table needs to be processed */
-#define NSGIF_PROCESS_COLOURS 0xaa000000
-
-/** Internal flag that a frame is invalid/unprocessed */
-#define NSGIF_INVALID_FRAME -1
-
-/** Transparent colour */
-#define NSGIF_TRANSPARENT_COLOUR 0x00
-
-/** No transparency */
-#define NSGIF_NO_TRANSPARENCY (0xFFFFFFFFu)
-
-enum nsgif_disposal {
- NSGIF_DISPOSAL_UNSPECIFIED,
- NSGIF_DISPOSAL_NONE,
- NSGIF_DISPOSAL_RESTORE_BG,
- NSGIF_DISPOSAL_RESTORE_PREV,
- NSGIF_DISPOSAL_RESTORE_QUIRK, /**< Alias for NSGIF_DISPOSAL_RESTORE_PREV. */
-};
-
-/* GIF Flags */
-#define NSGIF_INTERLACE_MASK 0x40
-#define NSGIF_COLOUR_TABLE_MASK 0x80
-#define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07
-#define NSGIF_EXTENSION_INTRODUCER 0x21
-#define NSGIF_EXTENSION_GRAPHIC_CONTROL 0xf9
-#define NSGIF_DISPOSAL_MASK 0x1c
-#define NSGIF_TRANSPARENCY_MASK 0x01
-#define NSGIF_EXTENSION_COMMENT 0xfe
-#define NSGIF_EXTENSION_PLAIN_TEXT 0x01
-#define NSGIF_EXTENSION_APPLICATION 0xff
-#define NSGIF_BLOCK_TERMINATOR 0x00
-#define NSGIF_TRAILER 0x3b
-
-/**
- * Convert an LZW result code to equivalent GIF result code.
- *
- * \param[in] l_res LZW response code.
- * \return GIF result code.
- */
-static nsgif_result nsgif__error_from_lzw(lzw_result l_res)
-{
- static const nsgif_result g_res[] = {
- [LZW_OK] = NSGIF_OK,
- [LZW_OK_EOD] = NSGIF_END_OF_FRAME,
- [LZW_NO_MEM] = NSGIF_INSUFFICIENT_MEMORY,
- [LZW_NO_DATA] = NSGIF_INSUFFICIENT_DATA,
- [LZW_EOI_CODE] = NSGIF_FRAME_DATA_ERROR,
- [LZW_BAD_ICODE] = NSGIF_FRAME_DATA_ERROR,
- [LZW_BAD_CODE] = NSGIF_FRAME_DATA_ERROR,
- };
- assert(l_res != LZW_BAD_PARAM);
- assert(l_res != LZW_NO_COLOUR);
- return g_res[l_res];
-}
-
-/**
- * Updates the sprite memory size
- *
- * \param gif The animation context
- * \param width The width of the sprite
- * \param height The height of the sprite
- * \return NSGIF_INSUFFICIENT_MEMORY for a memory error NSGIF_OK for success
- */
-static nsgif_result nsgif__initialise_sprite(
- struct nsgif_animation *gif,
- uint32_t width,
- uint32_t height)
-{
- /* Already allocated? */
- if (gif->frame_image) {
- return NSGIF_OK;
- }
-
- assert(gif->bitmap.create);
- gif->frame_image = gif->bitmap.create(width, height);
- if (gif->frame_image == NULL) {
- return NSGIF_INSUFFICIENT_MEMORY;
- }
-
- return NSGIF_OK;
-}
-
-/**
- * Helper to get the rendering bitmap for a gif.
- *
- * \param[in] gif The gif object we're decoding.
- * \return Client pixel buffer for rendering into.
- */
-static inline uint32_t* nsgif__bitmap_get(
- struct nsgif_animation *gif)
-{
- nsgif_result ret;
-
- /* Make sure we have a buffer to decode to. */
- ret = nsgif__initialise_sprite(gif, gif->width, gif->height);
- if (ret != NSGIF_OK) {
- return NULL;
- }
-
- /* Get the frame data */
- assert(gif->bitmap.get_buffer);
- return (uint32_t *)gif->bitmap.get_buffer(gif->frame_image);
-}
-
-/**
- * Helper to tell the client that their bitmap was modified.
- *
- * \param[in] gif The gif object we're decoding.
- */
-static inline void nsgif__bitmap_modified(
- const struct nsgif_animation *gif)
-{
- if (gif->bitmap.modified) {
- gif->bitmap.modified(gif->frame_image);
- }
-}
-
-/**
- * Helper to tell the client that whether the bitmap is opaque.
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] frame The frame that has been decoded.
- */
-static inline void nsgif__bitmap_set_opaque(
- const struct nsgif_animation *gif,
- const struct nsgif_frame *frame)
-{
- if (gif->bitmap.set_opaque) {
- gif->bitmap.set_opaque(
- gif->frame_image, frame->opaque);
- }
-}
-
-/**
- * Helper to get the client to determine if the bitmap is opaque.
- *
- * \todo: We don't really need to get the client to do this for us.
- *
- * \param[in] gif The gif object we're decoding.
- * \return true if the bitmap is opaque, false otherwise.
- */
-static inline bool nsgif__bitmap_get_opaque(
- const struct nsgif_animation *gif)
-{
- if (gif->bitmap.test_opaque) {
- return gif->bitmap.test_opaque(
- gif->frame_image);
- }
-
- return false;
-}
-
-static void nsgif__record_frame(
- struct nsgif_animation *gif,
- const uint32_t *bitmap)
-{
- bool need_alloc = gif->prev_frame == NULL;
- uint32_t *prev_frame;
-
- if (gif->decoded_frame == NSGIF_INVALID_FRAME ||
- gif->decoded_frame == gif->prev_index) {
- /* No frame to copy, or already have this frame recorded. */
- return;
- }
-
- bitmap = nsgif__bitmap_get(gif);
- if (bitmap == NULL) {
- return;
- }
-
- if (gif->prev_frame != NULL &&
- gif->width * gif->height > gif->prev_width * gif->prev_height) {
- need_alloc = true;
- }
-
- if (need_alloc) {
- prev_frame = realloc(gif->prev_frame,
- gif->width * gif->height * 4);
- if (prev_frame == NULL) {
- return;
- }
- } else {
- prev_frame = gif->prev_frame;
- }
-
- memcpy(prev_frame, bitmap, gif->width * gif->height * 4);
-
- gif->prev_frame = prev_frame;
- gif->prev_width = gif->width;
- gif->prev_height = gif->height;
- gif->prev_index = gif->decoded_frame;
-}
-
-static nsgif_result nsgif__recover_frame(
- const struct nsgif_animation *gif,
- uint32_t *bitmap)
-{
- const uint32_t *prev_frame = gif->prev_frame;
- unsigned height = gif->height < gif->prev_height ? gif->height : gif->prev_height;
- unsigned width = gif->width < gif->prev_width ? gif->width : gif->prev_width;
-
- if (prev_frame == NULL) {
- return NSGIF_FRAME_DATA_ERROR;
- }
-
- for (unsigned y = 0; y < height; y++) {
- memcpy(bitmap, prev_frame, width * 4);
-
- bitmap += gif->width;
- prev_frame += gif->prev_width;
- }
-
- return NSGIF_OK;
-}
-
-/**
- * Get the next line for GIF decode.
- *
- * Note that the step size must be initialised to 24 at the start of the frame
- * (when y == 0). This is because of the first two passes of the frame have
- * the same step size of 8, and the step size is used to determine the current
- * pass.
- *
- * \param[in] height Frame height in pixels.
- * \param[in,out] y Current row, starting from 0, updated on exit.
- * \param[in,out] step Current step starting with 24, updated on exit.
- * \return true if there is a row to process, false at the end of the frame.
- */
-static inline bool nsgif__deinterlace(uint32_t height, uint32_t *y, uint8_t *step)
-{
- *y += *step & 0xf;
-
- if (*y < height) return true;
-
- switch (*step) {
- case 24: *y = 4; *step = 8; if (*y < height) return true;
- /* Fall through. */
- case 8: *y = 2; *step = 4; if (*y < height) return true;
- /* Fall through. */
- case 4: *y = 1; *step = 2; if (*y < height) return true;
- /* Fall through. */
- default:
- break;
- }
-
- return false;
-}
-
-/**
- * Get the next line for GIF decode.
- *
- * \param[in] interlace Non-zero if the frame is not interlaced.
- * \param[in] height Frame height in pixels.
- * \param[in,out] y Current row, starting from 0, updated on exit.
- * \param[in,out] step Current step starting with 24, updated on exit.
- * \return true if there is a row to process, false at the end of the frame.
- */
-static inline bool nsgif__next_row(uint32_t interlace,
- uint32_t height, uint32_t *y, uint8_t *step)
-{
- if (!interlace) {
- return (++*y != height);
- } else {
- return nsgif__deinterlace(height, y, step);
- }
-}
-
-static nsgif_result nsgif__decode_complex(
- struct nsgif_animation *gif,
- uint32_t width,
- uint32_t height,
- uint32_t offset_x,
- uint32_t offset_y,
- uint32_t interlace,
- const uint8_t *data,
- uint32_t transparency_index,
- uint32_t *restrict frame_data,
- uint32_t *restrict colour_table)
-{
- lzw_result res;
- nsgif_result ret = NSGIF_OK;
- uint32_t available = 0;
- uint8_t step = 24;
- uint32_t y = 0;
-
- if (height == 0) {
- return NSGIF_OK;
- }
-
- /* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, data[0],
- gif->nsgif_data, gif->buffer_size,
- data + 1 - gif->nsgif_data);
- if (res != LZW_OK) {
- return nsgif__error_from_lzw(res);
- }
-
- do {
- uint32_t x;
- uint32_t *frame_scanline;
-
- frame_scanline = frame_data + offset_x +
- (y + offset_y) * gif->width;
-
- x = width;
- while (x > 0) {
- const uint8_t *uncompressed;
- unsigned row_available;
- if (available == 0) {
- if (res != LZW_OK) {
- /* Unexpected end of frame, try to recover */
- if (res == LZW_OK_EOD) {
- ret = NSGIF_OK;
- } else {
- ret = nsgif__error_from_lzw(res);
- }
- break;
- }
- res = lzw_decode(gif->lzw_ctx,
- &uncompressed, &available);
- }
-
- row_available = x < available ? x : available;
- x -= row_available;
- available -= row_available;
- if (transparency_index > 0xFF) {
- while (row_available-- > 0) {
- *frame_scanline++ =
- colour_table[*uncompressed++];
- }
- } else {
- while (row_available-- > 0) {
- register uint32_t colour;
- colour = *uncompressed++;
- if (colour != transparency_index) {
- *frame_scanline =
- colour_table[colour];
- }
- frame_scanline++;
- }
- }
- }
- } while (nsgif__next_row(interlace, height, &y, &step));
-
- return ret;
-}
-
-static nsgif_result nsgif__decode_simple(
- struct nsgif_animation *gif,
- uint32_t height,
- uint32_t offset_y,
- const uint8_t *data,
- uint32_t transparency_index,
- uint32_t *restrict frame_data,
- uint32_t *restrict colour_table)
-{
- uint32_t pixels = gif->width * height;
- uint32_t written = 0;
- nsgif_result ret = NSGIF_OK;
- lzw_result res;
-
- /* Initialise the LZW decoding */
- res = lzw_decode_init_map(gif->lzw_ctx, data[0],
- transparency_index, colour_table,
- gif->nsgif_data, gif->buffer_size,
- data + 1 - gif->nsgif_data);
- if (res != LZW_OK) {
- return nsgif__error_from_lzw(res);
- }
-
- frame_data += (offset_y * gif->width);
-
- while (pixels > 0) {
- res = lzw_decode_map(gif->lzw_ctx,
- 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 = NSGIF_OK;
- } else {
- ret = nsgif__error_from_lzw(res);
- }
- break;
- }
- }
-
- if (pixels == 0) {
- ret = NSGIF_OK;
- }
-
- return ret;
-}
-
-static inline nsgif_result nsgif__decode(
- struct nsgif_animation *gif,
- struct nsgif_frame *frame,
- const uint8_t *data,
- uint32_t *restrict frame_data)
-{
- nsgif_result ret;
- uint32_t offset_x = frame->redraw_x;
- uint32_t offset_y = frame->redraw_y;
- uint32_t width = frame->redraw_width;
- uint32_t height = frame->redraw_height;
- uint32_t interlace = frame->flags & NSGIF_INTERLACE_MASK;
- uint32_t transparency_index = frame->transparency_index;
- uint32_t *restrict colour_table = gif->colour_table;
-
- if (interlace == false && width == gif->width && offset_x == 0) {
- ret = nsgif__decode_simple(gif, height, offset_y,
- data, transparency_index,
- frame_data, colour_table);
- } else {
- ret = nsgif__decode_complex(gif, width, height,
- offset_x, offset_y, interlace,
- data, transparency_index,
- frame_data, colour_table);
- }
-
- return ret;
-}
-
-/**
- * Restore a GIF to the background colour.
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] frame The frame to clear, or NULL.
- * \param[in] bitmap The bitmap to clear the frame in.
- */
-static void nsgif__restore_bg(
- struct nsgif_animation *gif,
- struct nsgif_frame *frame,
- uint32_t *bitmap)
-{
- if (frame == NULL) {
- memset(bitmap, NSGIF_TRANSPARENT_COLOUR,
- gif->width * gif->height * sizeof(*bitmap));
- } else {
- uint32_t offset_x = frame->redraw_x;
- uint32_t offset_y = frame->redraw_y;
- uint32_t width = frame->redraw_width;
- uint32_t height = frame->redraw_height;
-
- if (frame->display == false) {
- return;
- }
-
- if (frame->transparency) {
- for (uint32_t y = 0; y < height; y++) {
- uint32_t *scanline = bitmap + offset_x +
- (offset_y + y) * gif->width;
- memset(scanline, NSGIF_TRANSPARENT_COLOUR,
- width * sizeof(*bitmap));
- }
- } else {
- for (uint32_t y = 0; y < height; y++) {
- uint32_t *scanline = bitmap + offset_x +
- (offset_y + y) * gif->width;
- for (uint32_t x = 0; x < width; x++) {
- scanline[x] = gif->bg_colour;
- }
- }
- }
- }
-}
-
-static nsgif_result nsgif__update_bitmap(
- struct nsgif_animation *gif,
- struct nsgif_frame *frame,
- const uint8_t *data,
- uint32_t frame_idx)
-{
- nsgif_result ret;
- uint32_t *bitmap;
-
- gif->decoded_frame = frame_idx;
-
- bitmap = nsgif__bitmap_get(gif);
- if (bitmap == NULL) {
- return NSGIF_INSUFFICIENT_MEMORY;
- }
-
- /* Handle any bitmap clearing/restoration required before decoding this
- * frame. */
- if (frame_idx == 0 || gif->decoded_frame == NSGIF_INVALID_FRAME) {
- nsgif__restore_bg(gif, NULL, bitmap);
-
- } else {
- struct nsgif_frame *prev = &gif->frames[frame_idx - 1];
-
- if (prev->disposal_method == NSGIF_DISPOSAL_RESTORE_BG) {
- nsgif__restore_bg(gif, prev, bitmap);
-
- } else if (prev->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV) {
- ret = nsgif__recover_frame(gif, bitmap);
- if (ret != NSGIF_OK) {
- nsgif__restore_bg(gif, prev, bitmap);
- }
- }
- }
-
- if (frame->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV) {
- /* Store the previous frame for later restoration */
- nsgif__record_frame(gif, bitmap);
- }
-
- ret = nsgif__decode(gif, frame, data, bitmap);
-
- nsgif__bitmap_modified(gif);
-
- if (!frame->decoded) {
- frame->opaque = nsgif__bitmap_get_opaque(gif);
- frame->decoded = true;
- }
- nsgif__bitmap_set_opaque(gif, frame);
-
- return ret;
-}
-
-/**
- * Parse the application extension
- *
- * \param[in] frame The gif object we're decoding.
- * \param[in] data The data to decode.
- * \param[in] len Byte length of data.
- * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
- * NSGIF_OK for success.
- */
-static nsgif_result nsgif__parse_extension_graphic_control(
- struct nsgif_frame *frame,
- const uint8_t *data,
- size_t len)
-{
- /* 6-byte Graphic Control Extension is:
- *
- * +0 CHAR Graphic Control Label
- * +1 CHAR Block Size
- * +2 CHAR __Packed Fields__
- * 3BITS Reserved
- * 3BITS Disposal Method
- * 1BIT User Input Flag
- * 1BIT Transparent Color Flag
- * +3 SHORT Delay Time
- * +5 CHAR Transparent Color Index
- */
- if (len < 6) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- frame->frame_delay = data[3] | (data[4] << 8);
- if (data[2] & NSGIF_TRANSPARENCY_MASK) {
- frame->transparency = true;
- frame->transparency_index = data[5];
- }
-
- frame->disposal_method = ((data[2] & NSGIF_DISPOSAL_MASK) >> 2);
- /* I have encountered documentation and GIFs in the
- * wild that use 0x04 to restore the previous frame,
- * rather than the officially documented 0x03. I
- * believe some (older?) software may even actually
- * export this way. We handle this as a type of
- * "quirks" mode. */
- if (frame->disposal_method == NSGIF_DISPOSAL_RESTORE_QUIRK) {
- frame->disposal_method = NSGIF_DISPOSAL_RESTORE_PREV;
- }
-
- /* if we are clearing the background then we need to
- * redraw enough to cover the previous frame too. */
- frame->redraw_required =
- frame->disposal_method == NSGIF_DISPOSAL_RESTORE_BG ||
- frame->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV;
-
- return NSGIF_OK;
-}
-
-/**
- * Parse the application extension
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] data The data to decode.
- * \param[in] len Byte length of data.
- * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
- * NSGIF_OK for success.
- */
-static nsgif_result nsgif__parse_extension_application(
- struct nsgif_animation *gif,
- const uint8_t *data,
- size_t len)
-{
- /* 14-byte+ Application Extension is:
- *
- * +0 CHAR Application Extension Label
- * +1 CHAR Block Size
- * +2 8CHARS Application Identifier
- * +10 3CHARS Appl. Authentication Code
- * +13 1-256 Application Data (Data sub-blocks)
- */
- if (len < 17) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- if ((data[1] == 0x0b) &&
- (strncmp((const char *)data + 2, "NETSCAPE2.0", 11) == 0) &&
- (data[13] == 0x03) && (data[14] == 0x01)) {
- gif->loop_count = data[15] | (data[16] << 8);
- }
-
- return NSGIF_OK;
-}
-
-/**
- * Parse the frame's extensions
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] frame The frame to parse extensions for.
- * \param[in] pos Current position in data, updated on exit.
- * \param[in] decode Whether to decode or skip over the extension.
- * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
- * NSGIF_OK for success.
- */
-static nsgif_result nsgif__parse_frame_extensions(
- struct nsgif_animation *gif,
- struct nsgif_frame *frame,
- const uint8_t **pos,
- bool decode)
-{
- const uint8_t *nsgif_data = *pos;
- const uint8_t *nsgif_end = gif->nsgif_data + gif->buffer_size;
- int nsgif_bytes = nsgif_end - nsgif_data;
-
- /* Initialise the extensions */
- while (nsgif_bytes > 0 && nsgif_data[0] == NSGIF_EXTENSION_INTRODUCER) {
- bool block_step = true;
- nsgif_result ret;
-
- nsgif_data++;
- nsgif_bytes--;
-
- if (nsgif_bytes == 0) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- /* Switch on extension label */
- switch (nsgif_data[0]) {
- case NSGIF_EXTENSION_GRAPHIC_CONTROL:
- if (decode) {
- ret = nsgif__parse_extension_graphic_control(
- frame, nsgif_data, nsgif_bytes);
- if (ret != NSGIF_OK) {
- return ret;
- }
- }
- break;
-
- case NSGIF_EXTENSION_APPLICATION:
- if (decode) {
- ret = nsgif__parse_extension_application(
- gif, nsgif_data, nsgif_bytes);
- if (ret != NSGIF_OK) {
- return ret;
- }
- }
- break;
-
- case NSGIF_EXTENSION_COMMENT:
- /* Move the pointer to the first data sub-block Skip 1
- * byte for the extension label. */
- ++nsgif_data;
- block_step = false;
- break;
-
- default:
- break;
- }
-
- if (block_step) {
- /* Move the pointer to the first data sub-block Skip 2
- * bytes for the extension label and size fields Skip
- * the extension size itself
- */
- if (nsgif_bytes < 2) {
- return NSGIF_INSUFFICIENT_DATA;
- }
- nsgif_data += 2 + nsgif_data[1];
- }
-
- /* Repeatedly skip blocks until we get a zero block or run out
- * of data. This data is ignored by this gif decoder. */
- while (nsgif_data < nsgif_end && nsgif_data[0] != NSGIF_BLOCK_TERMINATOR) {
- nsgif_data += nsgif_data[0] + 1;
- if (nsgif_data >= nsgif_end) {
- return NSGIF_INSUFFICIENT_DATA;
- }
- }
- nsgif_data++;
- nsgif_bytes = nsgif_end - nsgif_data;
- }
-
- if (nsgif_data > nsgif_end) {
- nsgif_data = nsgif_end;
- }
-
- /* Set buffer position and return */
- *pos = nsgif_data;
- return NSGIF_OK;
-}
-
-/**
- * Parse a GIF Image Descriptor.
- *
- * The format is:
- *
- * +0 CHAR Image Separator (0x2c)
- * +1 SHORT Image Left Position
- * +3 SHORT Image Top Position
- * +5 SHORT Width
- * +7 SHORT Height
- * +9 CHAR __Packed Fields__
- * 1BIT Local Colour Table Flag
- * 1BIT Interlace Flag
- * 1BIT Sort Flag
- * 2BITS Reserved
- * 3BITS Size of Local Colour Table
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] frame The frame to parse an image descriptor for.
- * \param[in] pos Current position in data, updated on exit.
- * \param[in] decode Whether to decode the image descriptor.
- * \return NSGIF_OK on success, appropriate error otherwise.
- */
-static nsgif_result nsgif__parse_image_descriptor(
- struct nsgif_animation *gif,
- struct nsgif_frame *frame,
- const uint8_t **pos,
- bool decode)
-{
- const uint8_t *data = *pos;
- size_t len = gif->nsgif_data + gif->buffer_size - data;
- enum {
- NSGIF_IMAGE_DESCRIPTOR_LEN = 10u,
- NSGIF_IMAGE_SEPARATOR = 0x2Cu,
- };
-
- assert(gif != NULL);
- assert(frame != NULL);
-
- if (len < NSGIF_IMAGE_DESCRIPTOR_LEN) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- if (decode) {
- unsigned x, y, w, h;
-
- if (data[0] != NSGIF_IMAGE_SEPARATOR) {
- return NSGIF_FRAME_DATA_ERROR;
- }
-
- x = data[1] | (data[2] << 8);
- y = data[3] | (data[4] << 8);
- w = data[5] | (data[6] << 8);
- h = data[7] | (data[8] << 8);
- frame->flags = data[9];
-
- frame->redraw_x = x;
- frame->redraw_y = y;
- frame->redraw_width = w;
- frame->redraw_height = h;
-
- /* Frame size may have grown. */
- gif->width = (x + w > gif->width ) ? x + w : gif->width;
- gif->height = (y + h > gif->height) ? y + h : gif->height;
- }
-
- *pos += NSGIF_IMAGE_DESCRIPTOR_LEN;
- return NSGIF_OK;
-}
-
-/**
- * Extract a GIF colour table into a LibNSGIF colour table buffer.
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] colour_table The colour table to populate.
- * \param[in] colour_table_entries The number of colour table entries.
- * \param[in] pos Current position in data, updated on exit.
- * \param[in] decode Whether to decode the colour table.
- * \return NSGIF_OK on success, appropriate error otherwise.
- */
-static nsgif_result nsgif__colour_table_extract(
- struct nsgif_animation *gif,
- uint32_t *colour_table,
- size_t colour_table_entries,
- const uint8_t **pos,
- bool decode)
-{
- const uint8_t *data = *pos;
- size_t len = gif->nsgif_data + gif->buffer_size - data;
-
- if (len < colour_table_entries * 3) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- if (decode) {
- int count = colour_table_entries;
- uint8_t *entry = (uint8_t *)colour_table;
-
- while (count--) {
- /* Gif colour map contents are r,g,b.
- *
- * We want to pack them bytewise into the
- * colour table, such that the red component
- * is in byte 0 and the alpha component is in
- * byte 3.
- */
-
- *entry++ = *data++; /* r */
- *entry++ = *data++; /* g */
- *entry++ = *data++; /* b */
- *entry++ = 0xff; /* a */
- }
- }
-
- *pos += colour_table_entries * 3;
- return NSGIF_OK;
-}
-
-/**
- * Get a frame's colour table.
- *
- * Sets up gif->colour_table for the frame.
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] frame The frame to get the colour table for.
- * \param[in] pos Current position in data, updated on exit.
- * \param[in] decode Whether to decode the colour table.
- * \return NSGIF_OK on success, appropriate error otherwise.
- */
-static nsgif_result nsgif__parse_colour_table(
- struct nsgif_animation *gif,
- struct nsgif_frame *frame,
- const uint8_t **pos,
- bool decode)
-{
- nsgif_result ret;
-
- assert(gif != NULL);
- assert(frame != NULL);
-
- if ((frame->flags & NSGIF_COLOUR_TABLE_MASK) == 0) {
- gif->colour_table = gif->global_colour_table;
- return NSGIF_OK;
- }
-
- ret = nsgif__colour_table_extract(gif, gif->local_colour_table,
- 2 << (frame->flags & NSGIF_COLOUR_TABLE_SIZE_MASK),
- pos, decode);
- if (ret != NSGIF_OK) {
- return ret;
- }
-
- gif->colour_table = gif->local_colour_table;
- return NSGIF_OK;
-}
-
-/**
- * Parse the image data for a gif frame.
- *
- * Sets up gif->colour_table for the frame.
- *
- * \param[in] gif The gif object we're decoding.
- * \param[in] frame The frame to parse image data for.
- * \param[in] pos Current position in data, updated on exit.
- * \param[in] decode Whether to decode the image data.
- * \return NSGIF_OK on success, appropriate error otherwise.
- */
-static nsgif_result nsgif__parse_image_data(
- struct nsgif_animation *gif,
- struct nsgif_frame *frame,
- const uint8_t **pos,
- bool decode)
-{
- const uint8_t *data = *pos;
- size_t len = gif->nsgif_data + gif->buffer_size - data;
- uint32_t frame_idx = frame - gif->frames;
- uint8_t minimum_code_size;
- nsgif_result ret;
-
- assert(gif != NULL);
- assert(frame != NULL);
-
- if (!decode) {
- gif->frame_count_partial = frame_idx + 1;
- }
-
- /* Ensure sufficient data remains. A gif trailer or a minimum lzw code
- * followed by a gif trailer is treated as OK, although without any
- * image data. */
- switch (len) {
- default: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
- break;
- case 2: if (data[1] == NSGIF_TRAILER) return NSGIF_OK;
- /* Fall through. */
- case 1: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
- /* Fall through. */
- case 0: return NSGIF_INSUFFICIENT_DATA;
- }
-
- minimum_code_size = data[0];
- if (minimum_code_size >= LZW_CODE_MAX) {
- return NSGIF_DATA_ERROR;
- }
-
- if (decode) {
- ret = nsgif__update_bitmap(gif, frame, data, frame_idx);
- } else {
- uint32_t block_size = 0;
-
- /* Skip the minimum code size. */
- data++;
- len--;
-
- while (block_size != 1) {
- if (len < 1) return NSGIF_INSUFFICIENT_DATA;
- block_size = data[0] + 1;
- /* Check if the frame data runs off the end of the file */
- if (block_size > len) {
- block_size = len;
- return NSGIF_OK;
- }
-
- len -= block_size;
- data += block_size;
- }
-
- gif->frame_count = frame_idx + 1;
- gif->frames[frame_idx].display = true;
- *pos = data;
-
- /* Check if we've finished */
- if (len < 1) {
- return NSGIF_INSUFFICIENT_DATA;
- } else {
- if (data[0] == NSGIF_TRAILER) {
- return NSGIF_OK;
- }
- }
-
- return NSGIF_WORKING;
- }
-
- return ret;
-}
-
-static struct nsgif_frame *nsgif__get_frame(
- struct nsgif_animation *gif,
- uint32_t frame_idx)
-{
- struct nsgif_frame *frame;
-
- if (gif->frame_holders > frame_idx) {
- frame = &gif->frames[frame_idx];
- } else {
- /* Allocate more memory */
- size_t count = frame_idx + 1;
- struct nsgif_frame *temp;
-
- temp = realloc(gif->frames, count * sizeof(*frame));
- if (temp == NULL) {
- return NULL;
- }
- gif->frames = temp;
- gif->frame_holders = count;
-
- frame = &gif->frames[frame_idx];
-
- frame->transparency = false;
- frame->transparency_index = NSGIF_NO_TRANSPARENCY;
- frame->frame_pointer = gif->buffer_position;
- frame->redraw_required = false;
- frame->disposal_method = 0;
- frame->frame_delay = 100;
- frame->display = false;
- frame->decoded = false;
- }
-
- return frame;
-}
-
-/**
- * Attempts to initialise the next frame
- *
- * \param[in] gif The animation context
- * \param[in] frame_idx The frame number to decode.
- * \param[in] decode Whether to decode the graphical image data.
- * \return error code
- * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data.
- * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
- * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
- * - NSGIF_DATA_ERROR for GIF error (invalid frame header)
- * - NSGIF_OK for successful decoding
- * - NSGIF_WORKING for successful decoding if more frames are expected
-*/
-static nsgif_result nsgif__process_frame(
- struct nsgif_animation *gif,
- uint32_t frame_idx,
- bool decode)
-{
- nsgif_result ret;
- const uint8_t *pos;
- const uint8_t *end;
- struct nsgif_frame *frame;
-
- frame = nsgif__get_frame(gif, frame_idx);
- if (frame == NULL) {
- return NSGIF_INSUFFICIENT_MEMORY;
- }
-
- end = gif->nsgif_data + gif->buffer_size;
-
- if (decode) {
- pos = gif->nsgif_data + frame->frame_pointer;
-
- /* Ensure this frame is supposed to be decoded */
- if (frame->display == false) {
- return NSGIF_OK;
- }
-
- /* Ensure the frame is in range to decode */
- if (frame_idx > gif->frame_count_partial) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- /* Done if frame is already decoded */
- if ((int)frame_idx == gif->decoded_frame) {
- return NSGIF_OK;
- }
- } else {
- pos = (uint8_t *)(gif->nsgif_data + gif->buffer_position);
-
- /* Check if we've finished */
- if (pos < end && pos[0] == NSGIF_TRAILER) {
- return NSGIF_OK;
- }
-
- /* We could theoretically get some junk data that gives us
- * millions of frames, so we ensure that we don't have a
- * silly number. */
- if (frame_idx > 4096) {
- return NSGIF_FRAME_DATA_ERROR;
- }
- }
-
- /* Initialise any extensions */
- ret = nsgif__parse_frame_extensions(gif, frame, &pos, !decode);
- if (ret != NSGIF_OK) {
- goto cleanup;
- }
-
- ret = nsgif__parse_image_descriptor(gif, frame, &pos, !decode);
- if (ret != NSGIF_OK) {
- goto cleanup;
- }
-
- ret = nsgif__parse_colour_table(gif, frame, &pos, decode);
- if (ret != NSGIF_OK) {
- goto cleanup;
- }
-
- ret = nsgif__parse_image_data(gif, frame, &pos, decode);
- if (ret != NSGIF_OK) {
- goto cleanup;
- }
-
-cleanup:
- if (!decode) {
- gif->buffer_position = pos - gif->nsgif_data;
- }
-
- return ret;
-}
-
-/* exported function documented in libnsgif.h */
-void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap)
-{
- memset(gif, 0, sizeof(nsgif_animation));
- gif->bitmap = *bitmap;
- gif->decoded_frame = NSGIF_INVALID_FRAME;
- gif->prev_index = NSGIF_INVALID_FRAME;
-}
-
-/**
- * Read GIF header.
- *
- * 6-byte GIF file header is:
- *
- * +0 3CHARS Signature ('GIF')
- * +3 3CHARS Version ('87a' or '89a')
- *
- * \param[in] gif The GIF object we're decoding.
- * \param[in,out] pos The current buffer position, updated on success.
- * \param[in] strict Whether to require a known GIF version.
- * \return NSGIF_OK on success, appropriate error otherwise.
- */
-static nsgif_result nsgif__parse_header(
- struct nsgif_animation *gif,
- const uint8_t **pos,
- bool strict)
-{
- const uint8_t *data = *pos;
- size_t len = gif->nsgif_data + gif->buffer_size - data;
-
- if (len < 6) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- if (strncmp((const char *) data, "GIF", 3) != 0) {
- return NSGIF_DATA_ERROR;
- }
- data += 3;
-
- if (strict == true) {
- if ((strncmp((const char *) data, "87a", 3) != 0) &&
- (strncmp((const char *) data, "89a", 3) != 0)) {
- return NSGIF_DATA_ERROR;
- }
- }
- data += 3;
-
- *pos = data;
- return NSGIF_OK;
-}
-
-/**
- * Read Logical Screen Descriptor.
- *
- * 7-byte Logical Screen Descriptor is:
- *
- * +0 SHORT Logical Screen Width
- * +2 SHORT Logical Screen Height
- * +4 CHAR __Packed Fields__
- * 1BIT Global Colour Table Flag
- * 3BITS Colour Resolution
- * 1BIT Sort Flag
- * 3BITS Size of Global Colour Table
- * +5 CHAR Background Colour Index
- * +6 CHAR Pixel Aspect Ratio
- *
- * \param[in] gif The GIF object we're decoding.
- * \param[in,out] pos The current buffer position, updated on success.
- * \return NSGIF_OK on success, appropriate error otherwise.
- */
-static nsgif_result nsgif__parse_logical_screen_descriptor(
- struct nsgif_animation *gif,
- const uint8_t **pos)
-{
- const uint8_t *data = *pos;
- size_t len = gif->nsgif_data + gif->buffer_size - data;
-
- if (len < 7) {
- return NSGIF_INSUFFICIENT_DATA;
- }
-
- gif->width = data[0] | (data[1] << 8);
- gif->height = data[2] | (data[3] << 8);
- gif->global_colours = data[4] & NSGIF_COLOUR_TABLE_MASK;
- gif->colour_table_size = 2 << (data[4] & NSGIF_COLOUR_TABLE_SIZE_MASK);
- gif->bg_index = data[5];
- gif->aspect_ratio = data[6];
- gif->loop_count = 1;
-
- *pos += 7;
- return NSGIF_OK;
-}
-
-/* exported function documented in libnsgif.h */
-nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data)
-{
- const uint8_t *nsgif_data;
- nsgif_result ret;
-
- /* Initialize values */
- gif->buffer_size = size;
- gif->nsgif_data = data;
-
- /* Get our current processing position */
- nsgif_data = gif->nsgif_data + gif->buffer_position;
-
- /* See if we should initialise the GIF */
- if (gif->buffer_position == 0) {
- /* We want everything to be NULL before we start so we've no
- * chance of freeing bad pointers (paranoia)
- */
- gif->frame_image = NULL;
- gif->frames = NULL;
- gif->frame_holders = 0;
- gif->local_colour_table = NULL;
- gif->global_colour_table = NULL;
-
- /* The caller may have been lazy and not reset any values */
- gif->frame_count = 0;
- gif->frame_count_partial = 0;
- gif->decoded_frame = NSGIF_INVALID_FRAME;
-
- ret = nsgif__parse_header(gif, &nsgif_data, false);
- if (ret != NSGIF_OK) {
- return ret;
- }
-
- ret = nsgif__parse_logical_screen_descriptor(gif, &nsgif_data);
- if (ret != NSGIF_OK) {
- return ret;
- }
-
- /* Remember we've done this now */
- gif->buffer_position = nsgif_data - gif->nsgif_data;
-
- /* Some broken GIFs report the size as the screen size they
- * were created in. As such, we detect for the common cases and
- * set the sizes as 0 if they are found which results in the
- * GIF being the maximum size of the frames.
- */
- if (((gif->width == 640) && (gif->height == 480)) ||
- ((gif->width == 640) && (gif->height == 512)) ||
- ((gif->width == 800) && (gif->height == 600)) ||
- ((gif->width == 1024) && (gif->height == 768)) ||
- ((gif->width == 1280) && (gif->height == 1024)) ||
- ((gif->width == 1600) && (gif->height == 1200)) ||
- ((gif->width == 0) || (gif->height == 0)) ||
- ((gif->width > 2048) || (gif->height > 2048))) {
- gif->width = 1;
- gif->height = 1;
- }
-
- /* Allocate some data irrespective of whether we've got any
- * colour tables. We always get the maximum size in case a GIF
- * is lying to us. It's far better to give the wrong colours
- * than to trample over some memory somewhere.
- */
- gif->global_colour_table = calloc(NSGIF_MAX_COLOURS, sizeof(uint32_t));
- gif->local_colour_table = calloc(NSGIF_MAX_COLOURS, sizeof(uint32_t));
- if ((gif->global_colour_table == NULL) ||
- (gif->local_colour_table == NULL)) {
- nsgif_finalise(gif);
- return NSGIF_INSUFFICIENT_MEMORY;
- }
-
- /* Set the first colour to a value that will never occur in
- * reality so we know if we've processed it
- */
- gif->global_colour_table[0] = NSGIF_PROCESS_COLOURS;
-
- /* Check if the GIF has no frame data (13-byte header + 1-byte
- * termination block) Although generally useless, the GIF
- * specification does not expressly prohibit this
- */
- if (gif->buffer_size == gif->buffer_position + 1) {
- if (nsgif_data[0] == NSGIF_TRAILER) {
- return NSGIF_OK;
- }
- }
- }
-
- /* Do the colour map if we haven't already. As the top byte is always
- * 0xff or 0x00 depending on the transparency we know if it's been
- * filled in.
- */
- if (gif->global_colour_table[0] == NSGIF_PROCESS_COLOURS) {
- /* Check for a global colour map signified by bit 7 */
- if (gif->global_colours) {
- ret = nsgif__colour_table_extract(gif,
- gif->global_colour_table,
- gif->colour_table_size,
- &nsgif_data, true);
- if (ret != NSGIF_OK) {
- return ret;
- }
-
- gif->buffer_position = (nsgif_data - gif->nsgif_data);
- } else {
- /* Create a default colour table with the first two
- * colours as black and white
- */
- uint32_t *entry = gif->global_colour_table;
-
- entry[0] = 0x00000000;
- /* Force Alpha channel to opaque */
- ((uint8_t *) entry)[3] = 0xff;
-
- entry[1] = 0xffffffff;
- }
-
- if (gif->global_colours &&
- gif->bg_index < gif->colour_table_size) {
- size_t bg_idx = gif->bg_index;
- gif->bg_colour = gif->global_colour_table[bg_idx];
- } else {
- gif->bg_colour = gif->global_colour_table[0];
- }
- }
-
- if (gif->lzw_ctx == NULL) {
- lzw_result res = lzw_context_create(
- (struct lzw_ctx **)&gif->lzw_ctx);
- if (res != LZW_OK) {
- return nsgif__error_from_lzw(res);
- }
- }
-
- /* Repeatedly try to initialise frames */
- do {
- ret = nsgif__process_frame(gif, gif->frame_count, false);
- } while (ret == NSGIF_WORKING);
-
- return ret;
-}
-
-/* exported function documented in libnsgif.h */
-nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame)
-{
- return nsgif__process_frame(gif, frame, true);
-}
-
-/* exported function documented in libnsgif.h */
-void nsgif_finalise(nsgif_animation *gif)
-{
- /* Release all our memory blocks */
- if (gif->frame_image) {
- assert(gif->bitmap.destroy);
- gif->bitmap.destroy(gif->frame_image);
- }
-
- gif->frame_image = NULL;
- free(gif->frames);
- gif->frames = NULL;
- free(gif->local_colour_table);
- gif->local_colour_table = NULL;
- free(gif->global_colour_table);
- gif->global_colour_table = NULL;
-
- free(gif->prev_frame);
- gif->prev_frame = NULL;
-
- lzw_context_destroy(gif->lzw_ctx);
- gif->lzw_ctx = NULL;
-}
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=c1a577e96ca0067817...
commit c1a577e96ca0067817dce90a007a66321eae56a8
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
LIB: Use consistent nsgif_ / NSGIF_ namespace.
diff --git a/Makefile b/Makefile
index 2ae2406..42aba3a 100644
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,6 @@ include $(NSBUILD)/Makefile.top
# Extra installation rules
I := /$(INCLUDEDIR)
-INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/libnsgif.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsgif.h
INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR)/pkgconfig:lib$(COMPONENT).pc.in
INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR):$(OUTPUT)
diff --git a/include/libnsgif.h b/include/libnsgif.h
index 6b8d521..114addf 100644
--- a/include/libnsgif.h
+++ b/include/libnsgif.h
@@ -13,27 +13,27 @@
* Interface to progressive animated GIF file decoding.
*/
-#ifndef _LIBNSGIF_H_
-#define _LIBNSGIF_H_
+#ifndef NSNSGIF_H
+#define NSNSGIF_H
#include <stdint.h>
#include <stdbool.h>
/* Error return values */
typedef enum {
- GIF_WORKING = 1,
- GIF_OK = 0,
- GIF_INSUFFICIENT_DATA = -1,
- GIF_INSUFFICIENT_FRAME_DATA = GIF_INSUFFICIENT_DATA,
- GIF_FRAME_DATA_ERROR = -2,
- GIF_DATA_ERROR = -4,
- GIF_INSUFFICIENT_MEMORY = -5,
- GIF_FRAME_NO_DISPLAY = -6,
- GIF_END_OF_FRAME = -7
-} gif_result;
+ NSGIF_WORKING = 1,
+ NSGIF_OK = 0,
+ NSGIF_INSUFFICIENT_DATA = -1,
+ NSGIF_INSUFFICIENT_FRAME_DATA = NSGIF_INSUFFICIENT_DATA,
+ NSGIF_FRAME_DATA_ERROR = -2,
+ NSGIF_DATA_ERROR = -4,
+ NSGIF_INSUFFICIENT_MEMORY = -5,
+ NSGIF_FRAME_NO_DISPLAY = -6,
+ NSGIF_END_OF_FRAME = -7
+} nsgif_result;
/** GIF frame data */
-typedef struct gif_frame {
+typedef struct nsgif_frame {
/** whether the frame should be displayed/animated */
bool display;
/** delay (in cs) before animating the frame */
@@ -65,43 +65,43 @@ typedef struct gif_frame {
uint32_t redraw_height;
/* Frame flags */
uint32_t flags;
-} gif_frame;
+} nsgif_frame;
/* API for Bitmap callbacks */
-typedef void* (*gif_bitmap_cb_create)(int width, int height);
-typedef void (*gif_bitmap_cb_destroy)(void *bitmap);
-typedef uint8_t* (*gif_bitmap_cb_get_buffer)(void *bitmap);
-typedef void (*gif_bitmap_cb_set_opaque)(void *bitmap, bool opaque);
-typedef bool (*gif_bitmap_cb_test_opaque)(void *bitmap);
-typedef void (*gif_bitmap_cb_modified)(void *bitmap);
+typedef void* (*nsgif_bitmap_cb_create)(int width, int height);
+typedef void (*nsgif_bitmap_cb_destroy)(void *bitmap);
+typedef uint8_t* (*nsgif_bitmap_cb_get_buffer)(void *bitmap);
+typedef void (*nsgif_bitmap_cb_set_opaque)(void *bitmap, bool opaque);
+typedef bool (*nsgif_bitmap_cb_test_opaque)(void *bitmap);
+typedef void (*nsgif_bitmap_cb_modified)(void *bitmap);
/** Bitmap callbacks function table */
-typedef struct gif_bitmap_callback_vt {
+typedef struct nsgif_bitmap_cb_vt {
/** Create a bitmap. */
- gif_bitmap_cb_create bitmap_create;
+ nsgif_bitmap_cb_create create;
/** Free a bitmap. */
- gif_bitmap_cb_destroy bitmap_destroy;
+ nsgif_bitmap_cb_destroy destroy;
/** Return a pointer to the pixel data in a bitmap. */
- gif_bitmap_cb_get_buffer bitmap_get_buffer;
+ nsgif_bitmap_cb_get_buffer get_buffer;
/* Members below are optional */
/** Sets whether a bitmap should be plotted opaque. */
- gif_bitmap_cb_set_opaque bitmap_set_opaque;
+ nsgif_bitmap_cb_set_opaque set_opaque;
/** Tests whether a bitmap has an opaque alpha channel. */
- gif_bitmap_cb_test_opaque bitmap_test_opaque;
+ nsgif_bitmap_cb_test_opaque test_opaque;
/** The bitmap image has changed, so flush any persistent cache. */
- gif_bitmap_cb_modified bitmap_modified;
-} gif_bitmap_callback_vt;
+ nsgif_bitmap_cb_modified modified;
+} nsgif_bitmap_cb_vt;
/** GIF animation data */
-typedef struct gif_animation {
+typedef struct nsgif_animation {
/** LZW decode context */
void *lzw_ctx;
/** callbacks for bitmap functions */
- gif_bitmap_callback_vt bitmap_callbacks;
+ nsgif_bitmap_cb_vt bitmap;
/** pointer to GIF data */
- const uint8_t *gif_data;
+ const uint8_t *nsgif_data;
/** width of GIF (may increase during decoding) */
uint32_t width;
/** height of GIF (may increase during decoding) */
@@ -111,7 +111,7 @@ typedef struct gif_animation {
/** number of frames partially decoded */
uint32_t frame_count_partial;
/** decoded frames */
- gif_frame *frames;
+ nsgif_frame *frames;
/** current frame decoded to bitmap */
int decoded_frame;
/** currently decoded image; stored as bitmap from bitmap_create callback */
@@ -144,7 +144,7 @@ typedef struct gif_animation {
/** current colour table */
uint32_t *colour_table;
- /** previous frame for GIF_FRAME_RESTORE */
+ /** previous frame for NSGIF_FRAME_RESTORE */
void *prev_frame;
/** previous frame index */
int prev_index;
@@ -152,12 +152,12 @@ typedef struct gif_animation {
unsigned prev_width;
/** previous frame height */
unsigned prev_height;
-} gif_animation;
+} nsgif_animation;
/**
- * Initialises necessary gif_animation members.
+ * Initialises necessary nsgif_animation members.
*/
-void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks);
+void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap_callbacks);
/**
* Initialises any workspace held by the animation and attempts to decode
@@ -165,30 +165,30 @@ void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks);
* If an error occurs, all previously decoded frames are retained.
*
* \return Error return value.
- * - GIF_FRAME_DATA_ERROR for GIF frame data error
- * - GIF_INSUFFICIENT_DATA reached unexpected end of source data
- * - GIF_INSUFFICIENT_MEMORY for memory error
- * - GIF_DATA_ERROR for GIF error
- * - GIF_OK for successful decoding
- * - GIF_WORKING for successful decoding if more frames are expected
+ * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
+ * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data
+ * - NSGIF_INSUFFICIENT_MEMORY for memory error
+ * - NSGIF_DATA_ERROR for GIF error
+ * - NSGIF_OK for successful decoding
+ * - NSGIF_WORKING for successful decoding if more frames are expected
*/
-gif_result gif_initialise(gif_animation *gif, size_t size, const uint8_t *data);
+nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data);
/**
* Decodes a GIF frame.
*
* \return Error return value.
- * - GIF_FRAME_DATA_ERROR for GIF frame data error
- * - GIF_DATA_ERROR for GIF error (invalid frame header)
- * - GIF_INSUFFICIENT_DATA reached unexpected end of source data
- * - GIF_INSUFFICIENT_MEMORY for insufficient memory to process
- * - GIF_OK for successful decoding
+ * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
+ * - NSGIF_DATA_ERROR for GIF error (invalid frame header)
+ * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data
+ * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
+ * - NSGIF_OK for successful decoding
*/
-gif_result gif_decode_frame(gif_animation *gif, uint32_t frame);
+nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame);
/**
* Releases any workspace held by a gif
*/
-void gif_finalise(gif_animation *gif);
+void nsgif_finalise(nsgif_animation *gif);
#endif
diff --git a/src/Makefile b/src/Makefile
index cb5d31f..e1e1fa7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,4 +1,4 @@
# Sources
-DIR_SOURCES := libnsgif.c lzw.c
+DIR_SOURCES := gif.c lzw.c
include $(NSBUILD)/Makefile.subdir
diff --git a/src/libnsgif.c b/src/libnsgif.c
index a1c7cb4..9d77894 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -15,7 +15,7 @@
#include <stdbool.h>
#include "lzw.h"
-#include "libnsgif.h"
+#include "nsgif.h"
/**
*
@@ -29,41 +29,41 @@
*/
/** Maximum colour table size */
-#define GIF_MAX_COLOURS 256
+#define NSGIF_MAX_COLOURS 256
/** Internal flag that the colour table needs to be processed */
-#define GIF_PROCESS_COLOURS 0xaa000000
+#define NSGIF_PROCESS_COLOURS 0xaa000000
/** Internal flag that a frame is invalid/unprocessed */
-#define GIF_INVALID_FRAME -1
+#define NSGIF_INVALID_FRAME -1
/** Transparent colour */
-#define GIF_TRANSPARENT_COLOUR 0x00
+#define NSGIF_TRANSPARENT_COLOUR 0x00
/** No transparency */
-#define GIF_NO_TRANSPARENCY (0xFFFFFFFFu)
-
-enum gif_disposal {
- GIF_DISPOSAL_UNSPECIFIED,
- GIF_DISPOSAL_NONE,
- GIF_DISPOSAL_RESTORE_BG,
- GIF_DISPOSAL_RESTORE_PREV,
- GIF_DISPOSAL_RESTORE_QUIRK, /**< Alias for GIF_DISPOSAL_RESTORE_PREV. */
+#define NSGIF_NO_TRANSPARENCY (0xFFFFFFFFu)
+
+enum nsgif_disposal {
+ NSGIF_DISPOSAL_UNSPECIFIED,
+ NSGIF_DISPOSAL_NONE,
+ NSGIF_DISPOSAL_RESTORE_BG,
+ NSGIF_DISPOSAL_RESTORE_PREV,
+ NSGIF_DISPOSAL_RESTORE_QUIRK, /**< Alias for NSGIF_DISPOSAL_RESTORE_PREV. */
};
/* GIF Flags */
-#define GIF_INTERLACE_MASK 0x40
-#define GIF_COLOUR_TABLE_MASK 0x80
-#define GIF_COLOUR_TABLE_SIZE_MASK 0x07
-#define GIF_EXTENSION_INTRODUCER 0x21
-#define GIF_EXTENSION_GRAPHIC_CONTROL 0xf9
-#define GIF_DISPOSAL_MASK 0x1c
-#define GIF_TRANSPARENCY_MASK 0x01
-#define GIF_EXTENSION_COMMENT 0xfe
-#define GIF_EXTENSION_PLAIN_TEXT 0x01
-#define GIF_EXTENSION_APPLICATION 0xff
-#define GIF_BLOCK_TERMINATOR 0x00
-#define GIF_TRAILER 0x3b
+#define NSGIF_INTERLACE_MASK 0x40
+#define NSGIF_COLOUR_TABLE_MASK 0x80
+#define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07
+#define NSGIF_EXTENSION_INTRODUCER 0x21
+#define NSGIF_EXTENSION_GRAPHIC_CONTROL 0xf9
+#define NSGIF_DISPOSAL_MASK 0x1c
+#define NSGIF_TRANSPARENCY_MASK 0x01
+#define NSGIF_EXTENSION_COMMENT 0xfe
+#define NSGIF_EXTENSION_PLAIN_TEXT 0x01
+#define NSGIF_EXTENSION_APPLICATION 0xff
+#define NSGIF_BLOCK_TERMINATOR 0x00
+#define NSGIF_TRAILER 0x3b
/**
* Convert an LZW result code to equivalent GIF result code.
@@ -71,16 +71,16 @@ enum gif_disposal {
* \param[in] l_res LZW response code.
* \return GIF result code.
*/
-static gif_result gif__error_from_lzw(lzw_result l_res)
+static nsgif_result nsgif__error_from_lzw(lzw_result l_res)
{
- static const gif_result g_res[] = {
- [LZW_OK] = GIF_OK,
- [LZW_OK_EOD] = GIF_END_OF_FRAME,
- [LZW_NO_MEM] = GIF_INSUFFICIENT_MEMORY,
- [LZW_NO_DATA] = GIF_INSUFFICIENT_DATA,
- [LZW_EOI_CODE] = GIF_FRAME_DATA_ERROR,
- [LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
- [LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
+ static const nsgif_result g_res[] = {
+ [LZW_OK] = NSGIF_OK,
+ [LZW_OK_EOD] = NSGIF_END_OF_FRAME,
+ [LZW_NO_MEM] = NSGIF_INSUFFICIENT_MEMORY,
+ [LZW_NO_DATA] = NSGIF_INSUFFICIENT_DATA,
+ [LZW_EOI_CODE] = NSGIF_FRAME_DATA_ERROR,
+ [LZW_BAD_ICODE] = NSGIF_FRAME_DATA_ERROR,
+ [LZW_BAD_CODE] = NSGIF_FRAME_DATA_ERROR,
};
assert(l_res != LZW_BAD_PARAM);
assert(l_res != LZW_NO_COLOUR);
@@ -93,25 +93,25 @@ static gif_result gif__error_from_lzw(lzw_result l_res)
* \param gif The animation context
* \param width The width of the sprite
* \param height The height of the sprite
- * \return GIF_INSUFFICIENT_MEMORY for a memory error GIF_OK for success
+ * \return NSGIF_INSUFFICIENT_MEMORY for a memory error NSGIF_OK for success
*/
-static gif_result gif__initialise_sprite(
- struct gif_animation *gif,
+static nsgif_result nsgif__initialise_sprite(
+ struct nsgif_animation *gif,
uint32_t width,
uint32_t height)
{
/* Already allocated? */
if (gif->frame_image) {
- return GIF_OK;
+ return NSGIF_OK;
}
- assert(gif->bitmap_callbacks.bitmap_create);
- gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
+ assert(gif->bitmap.create);
+ gif->frame_image = gif->bitmap.create(width, height);
if (gif->frame_image == NULL) {
- return GIF_INSUFFICIENT_MEMORY;
+ return NSGIF_INSUFFICIENT_MEMORY;
}
- return GIF_OK;
+ return NSGIF_OK;
}
/**
@@ -120,21 +120,20 @@ static gif_result gif__initialise_sprite(
* \param[in] gif The gif object we're decoding.
* \return Client pixel buffer for rendering into.
*/
-static inline uint32_t* gif__bitmap_get(
- struct gif_animation *gif)
+static inline uint32_t* nsgif__bitmap_get(
+ struct nsgif_animation *gif)
{
- gif_result ret;
+ nsgif_result ret;
/* Make sure we have a buffer to decode to. */
- ret = gif__initialise_sprite(gif, gif->width, gif->height);
- if (ret != GIF_OK) {
+ ret = nsgif__initialise_sprite(gif, gif->width, gif->height);
+ if (ret != NSGIF_OK) {
return NULL;
}
/* Get the frame data */
- assert(gif->bitmap_callbacks.bitmap_get_buffer);
- return (uint32_t *)gif->bitmap_callbacks.bitmap_get_buffer(
- gif->frame_image);
+ assert(gif->bitmap.get_buffer);
+ return (uint32_t *)gif->bitmap.get_buffer(gif->frame_image);
}
/**
@@ -142,11 +141,11 @@ static inline uint32_t* gif__bitmap_get(
*
* \param[in] gif The gif object we're decoding.
*/
-static inline void gif__bitmap_modified(
- const struct gif_animation *gif)
+static inline void nsgif__bitmap_modified(
+ const struct nsgif_animation *gif)
{
- if (gif->bitmap_callbacks.bitmap_modified) {
- gif->bitmap_callbacks.bitmap_modified(gif->frame_image);
+ if (gif->bitmap.modified) {
+ gif->bitmap.modified(gif->frame_image);
}
}
@@ -156,12 +155,12 @@ static inline void gif__bitmap_modified(
* \param[in] gif The gif object we're decoding.
* \param[in] frame The frame that has been decoded.
*/
-static inline void gif__bitmap_set_opaque(
- const struct gif_animation *gif,
- const struct gif_frame *frame)
+static inline void nsgif__bitmap_set_opaque(
+ const struct nsgif_animation *gif,
+ const struct nsgif_frame *frame)
{
- if (gif->bitmap_callbacks.bitmap_set_opaque) {
- gif->bitmap_callbacks.bitmap_set_opaque(
+ if (gif->bitmap.set_opaque) {
+ gif->bitmap.set_opaque(
gif->frame_image, frame->opaque);
}
}
@@ -174,31 +173,31 @@ static inline void gif__bitmap_set_opaque(
* \param[in] gif The gif object we're decoding.
* \return true if the bitmap is opaque, false otherwise.
*/
-static inline bool gif__bitmap_get_opaque(
- const struct gif_animation *gif)
+static inline bool nsgif__bitmap_get_opaque(
+ const struct nsgif_animation *gif)
{
- if (gif->bitmap_callbacks.bitmap_test_opaque) {
- return gif->bitmap_callbacks.bitmap_test_opaque(
+ if (gif->bitmap.test_opaque) {
+ return gif->bitmap.test_opaque(
gif->frame_image);
}
return false;
}
-static void gif__record_frame(
- struct gif_animation *gif,
+static void nsgif__record_frame(
+ struct nsgif_animation *gif,
const uint32_t *bitmap)
{
bool need_alloc = gif->prev_frame == NULL;
uint32_t *prev_frame;
- if (gif->decoded_frame == GIF_INVALID_FRAME ||
+ if (gif->decoded_frame == NSGIF_INVALID_FRAME ||
gif->decoded_frame == gif->prev_index) {
/* No frame to copy, or already have this frame recorded. */
return;
}
- bitmap = gif__bitmap_get(gif);
+ bitmap = nsgif__bitmap_get(gif);
if (bitmap == NULL) {
return;
}
@@ -226,8 +225,8 @@ static void gif__record_frame(
gif->prev_index = gif->decoded_frame;
}
-static gif_result gif__recover_frame(
- const struct gif_animation *gif,
+static nsgif_result nsgif__recover_frame(
+ const struct nsgif_animation *gif,
uint32_t *bitmap)
{
const uint32_t *prev_frame = gif->prev_frame;
@@ -235,7 +234,7 @@ static gif_result gif__recover_frame(
unsigned width = gif->width < gif->prev_width ? gif->width : gif->prev_width;
if (prev_frame == NULL) {
- return GIF_FRAME_DATA_ERROR;
+ return NSGIF_FRAME_DATA_ERROR;
}
for (unsigned y = 0; y < height; y++) {
@@ -245,7 +244,7 @@ static gif_result gif__recover_frame(
prev_frame += gif->prev_width;
}
- return GIF_OK;
+ return NSGIF_OK;
}
/**
@@ -261,7 +260,7 @@ static gif_result gif__recover_frame(
* \param[in,out] step Current step starting with 24, updated on exit.
* \return true if there is a row to process, false at the end of the frame.
*/
-static inline bool gif__deinterlace(uint32_t height, uint32_t *y, uint8_t *step)
+static inline bool nsgif__deinterlace(uint32_t height, uint32_t *y, uint8_t *step)
{
*y += *step & 0xf;
@@ -290,18 +289,18 @@ static inline bool gif__deinterlace(uint32_t height, uint32_t *y, uint8_t *step)
* \param[in,out] step Current step starting with 24, updated on exit.
* \return true if there is a row to process, false at the end of the frame.
*/
-static inline bool gif__next_row(uint32_t interlace,
+static inline bool nsgif__next_row(uint32_t interlace,
uint32_t height, uint32_t *y, uint8_t *step)
{
if (!interlace) {
return (++*y != height);
} else {
- return gif__deinterlace(height, y, step);
+ return nsgif__deinterlace(height, y, step);
}
}
-static gif_result gif__decode_complex(
- struct gif_animation *gif,
+static nsgif_result nsgif__decode_complex(
+ struct nsgif_animation *gif,
uint32_t width,
uint32_t height,
uint32_t offset_x,
@@ -313,21 +312,21 @@ static gif_result gif__decode_complex(
uint32_t *restrict colour_table)
{
lzw_result res;
- gif_result ret = GIF_OK;
+ nsgif_result ret = NSGIF_OK;
uint32_t available = 0;
uint8_t step = 24;
uint32_t y = 0;
if (height == 0) {
- return GIF_OK;
+ return NSGIF_OK;
}
/* Initialise the LZW decoding */
res = lzw_decode_init(gif->lzw_ctx, data[0],
- gif->gif_data, gif->buffer_size,
- data + 1 - gif->gif_data);
+ gif->nsgif_data, gif->buffer_size,
+ data + 1 - gif->nsgif_data);
if (res != LZW_OK) {
- return gif__error_from_lzw(res);
+ return nsgif__error_from_lzw(res);
}
do {
@@ -345,9 +344,9 @@ static gif_result gif__decode_complex(
if (res != LZW_OK) {
/* Unexpected end of frame, try to recover */
if (res == LZW_OK_EOD) {
- ret = GIF_OK;
+ ret = NSGIF_OK;
} else {
- ret = gif__error_from_lzw(res);
+ ret = nsgif__error_from_lzw(res);
}
break;
}
@@ -375,13 +374,13 @@ static gif_result gif__decode_complex(
}
}
}
- } while (gif__next_row(interlace, height, &y, &step));
+ } while (nsgif__next_row(interlace, height, &y, &step));
return ret;
}
-static gif_result gif__decode_simple(
- struct gif_animation *gif,
+static nsgif_result nsgif__decode_simple(
+ struct nsgif_animation *gif,
uint32_t height,
uint32_t offset_y,
const uint8_t *data,
@@ -391,16 +390,16 @@ static gif_result gif__decode_simple(
{
uint32_t pixels = gif->width * height;
uint32_t written = 0;
- gif_result ret = GIF_OK;
+ nsgif_result ret = NSGIF_OK;
lzw_result res;
/* Initialise the LZW decoding */
res = lzw_decode_init_map(gif->lzw_ctx, data[0],
transparency_index, colour_table,
- gif->gif_data, gif->buffer_size,
- data + 1 - gif->gif_data);
+ gif->nsgif_data, gif->buffer_size,
+ data + 1 - gif->nsgif_data);
if (res != LZW_OK) {
- return gif__error_from_lzw(res);
+ return nsgif__error_from_lzw(res);
}
frame_data += (offset_y * gif->width);
@@ -413,42 +412,42 @@ static gif_result gif__decode_simple(
if (res != LZW_OK) {
/* Unexpected end of frame, try to recover */
if (res == LZW_OK_EOD) {
- ret = GIF_OK;
+ ret = NSGIF_OK;
} else {
- ret = gif__error_from_lzw(res);
+ ret = nsgif__error_from_lzw(res);
}
break;
}
}
if (pixels == 0) {
- ret = GIF_OK;
+ ret = NSGIF_OK;
}
return ret;
}
-static inline gif_result gif__decode(
- struct gif_animation *gif,
- struct gif_frame *frame,
+static inline nsgif_result nsgif__decode(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
const uint8_t *data,
uint32_t *restrict frame_data)
{
- gif_result ret;
+ nsgif_result ret;
uint32_t offset_x = frame->redraw_x;
uint32_t offset_y = frame->redraw_y;
uint32_t width = frame->redraw_width;
uint32_t height = frame->redraw_height;
- uint32_t interlace = frame->flags & GIF_INTERLACE_MASK;
+ uint32_t interlace = frame->flags & NSGIF_INTERLACE_MASK;
uint32_t transparency_index = frame->transparency_index;
uint32_t *restrict colour_table = gif->colour_table;
if (interlace == false && width == gif->width && offset_x == 0) {
- ret = gif__decode_simple(gif, height, offset_y,
+ ret = nsgif__decode_simple(gif, height, offset_y,
data, transparency_index,
frame_data, colour_table);
} else {
- ret = gif__decode_complex(gif, width, height,
+ ret = nsgif__decode_complex(gif, width, height,
offset_x, offset_y, interlace,
data, transparency_index,
frame_data, colour_table);
@@ -464,13 +463,13 @@ static inline gif_result gif__decode(
* \param[in] frame The frame to clear, or NULL.
* \param[in] bitmap The bitmap to clear the frame in.
*/
-static void gif__restore_bg(
- struct gif_animation *gif,
- struct gif_frame *frame,
+static void nsgif__restore_bg(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
uint32_t *bitmap)
{
if (frame == NULL) {
- memset(bitmap, GIF_TRANSPARENT_COLOUR,
+ memset(bitmap, NSGIF_TRANSPARENT_COLOUR,
gif->width * gif->height * sizeof(*bitmap));
} else {
uint32_t offset_x = frame->redraw_x;
@@ -486,7 +485,7 @@ static void gif__restore_bg(
for (uint32_t y = 0; y < height; y++) {
uint32_t *scanline = bitmap + offset_x +
(offset_y + y) * gif->width;
- memset(scanline, GIF_TRANSPARENT_COLOUR,
+ memset(scanline, NSGIF_TRANSPARENT_COLOUR,
width * sizeof(*bitmap));
}
} else {
@@ -501,55 +500,55 @@ static void gif__restore_bg(
}
}
-static gif_result gif__update_bitmap(
- struct gif_animation *gif,
- struct gif_frame *frame,
+static nsgif_result nsgif__update_bitmap(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
const uint8_t *data,
uint32_t frame_idx)
{
- gif_result ret;
+ nsgif_result ret;
uint32_t *bitmap;
gif->decoded_frame = frame_idx;
- bitmap = gif__bitmap_get(gif);
+ bitmap = nsgif__bitmap_get(gif);
if (bitmap == NULL) {
- return GIF_INSUFFICIENT_MEMORY;
+ return NSGIF_INSUFFICIENT_MEMORY;
}
/* Handle any bitmap clearing/restoration required before decoding this
* frame. */
- if (frame_idx == 0 || gif->decoded_frame == GIF_INVALID_FRAME) {
- gif__restore_bg(gif, NULL, bitmap);
+ if (frame_idx == 0 || gif->decoded_frame == NSGIF_INVALID_FRAME) {
+ nsgif__restore_bg(gif, NULL, bitmap);
} else {
- struct gif_frame *prev = &gif->frames[frame_idx - 1];
+ struct nsgif_frame *prev = &gif->frames[frame_idx - 1];
- if (prev->disposal_method == GIF_DISPOSAL_RESTORE_BG) {
- gif__restore_bg(gif, prev, bitmap);
+ if (prev->disposal_method == NSGIF_DISPOSAL_RESTORE_BG) {
+ nsgif__restore_bg(gif, prev, bitmap);
- } else if (prev->disposal_method == GIF_DISPOSAL_RESTORE_PREV) {
- ret = gif__recover_frame(gif, bitmap);
- if (ret != GIF_OK) {
- gif__restore_bg(gif, prev, bitmap);
+ } else if (prev->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV) {
+ ret = nsgif__recover_frame(gif, bitmap);
+ if (ret != NSGIF_OK) {
+ nsgif__restore_bg(gif, prev, bitmap);
}
}
}
- if (frame->disposal_method == GIF_DISPOSAL_RESTORE_PREV) {
+ if (frame->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV) {
/* Store the previous frame for later restoration */
- gif__record_frame(gif, bitmap);
+ nsgif__record_frame(gif, bitmap);
}
- ret = gif__decode(gif, frame, data, bitmap);
+ ret = nsgif__decode(gif, frame, data, bitmap);
- gif__bitmap_modified(gif);
+ nsgif__bitmap_modified(gif);
if (!frame->decoded) {
- frame->opaque = gif__bitmap_get_opaque(gif);
+ frame->opaque = nsgif__bitmap_get_opaque(gif);
frame->decoded = true;
}
- gif__bitmap_set_opaque(gif, frame);
+ nsgif__bitmap_set_opaque(gif, frame);
return ret;
}
@@ -560,11 +559,11 @@ static gif_result gif__update_bitmap(
* \param[in] frame The gif object we're decoding.
* \param[in] data The data to decode.
* \param[in] len Byte length of data.
- * \return GIF_INSUFFICIENT_DATA if more data is needed,
- * GIF_OK for success.
+ * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
+ * NSGIF_OK for success.
*/
-static gif_result gif__parse_extension_graphic_control(
- struct gif_frame *frame,
+static nsgif_result nsgif__parse_extension_graphic_control(
+ struct nsgif_frame *frame,
const uint8_t *data,
size_t len)
{
@@ -581,33 +580,33 @@ static gif_result gif__parse_extension_graphic_control(
* +5 CHAR Transparent Color Index
*/
if (len < 6) {
- return GIF_INSUFFICIENT_DATA;
+ return NSGIF_INSUFFICIENT_DATA;
}
frame->frame_delay = data[3] | (data[4] << 8);
- if (data[2] & GIF_TRANSPARENCY_MASK) {
+ if (data[2] & NSGIF_TRANSPARENCY_MASK) {
frame->transparency = true;
frame->transparency_index = data[5];
}
- frame->disposal_method = ((data[2] & GIF_DISPOSAL_MASK) >> 2);
+ frame->disposal_method = ((data[2] & NSGIF_DISPOSAL_MASK) >> 2);
/* I have encountered documentation and GIFs in the
* wild that use 0x04 to restore the previous frame,
* rather than the officially documented 0x03. I
* believe some (older?) software may even actually
* export this way. We handle this as a type of
* "quirks" mode. */
- if (frame->disposal_method == GIF_DISPOSAL_RESTORE_QUIRK) {
- frame->disposal_method = GIF_DISPOSAL_RESTORE_PREV;
+ if (frame->disposal_method == NSGIF_DISPOSAL_RESTORE_QUIRK) {
+ frame->disposal_method = NSGIF_DISPOSAL_RESTORE_PREV;
}
/* if we are clearing the background then we need to
* redraw enough to cover the previous frame too. */
frame->redraw_required =
- frame->disposal_method == GIF_DISPOSAL_RESTORE_BG ||
- frame->disposal_method == GIF_DISPOSAL_RESTORE_PREV;
+ frame->disposal_method == NSGIF_DISPOSAL_RESTORE_BG ||
+ frame->disposal_method == NSGIF_DISPOSAL_RESTORE_PREV;
- return GIF_OK;
+ return NSGIF_OK;
}
/**
@@ -616,11 +615,11 @@ static gif_result gif__parse_extension_graphic_control(
* \param[in] gif The gif object we're decoding.
* \param[in] data The data to decode.
* \param[in] len Byte length of data.
- * \return GIF_INSUFFICIENT_DATA if more data is needed,
- * GIF_OK for success.
+ * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
+ * NSGIF_OK for success.
*/
-static gif_result gif__parse_extension_application(
- struct gif_animation *gif,
+static nsgif_result nsgif__parse_extension_application(
+ struct nsgif_animation *gif,
const uint8_t *data,
size_t len)
{
@@ -633,7 +632,7 @@ static gif_result gif__parse_extension_application(
* +13 1-256 Application Data (Data sub-blocks)
*/
if (len < 17) {
- return GIF_INSUFFICIENT_DATA;
+ return NSGIF_INSUFFICIENT_DATA;
}
if ((data[1] == 0x0b) &&
@@ -642,7 +641,7 @@ static gif_result gif__parse_extension_application(
gif->loop_count = data[15] | (data[16] << 8);
}
- return GIF_OK;
+ return NSGIF_OK;
}
/**
@@ -652,57 +651,57 @@ static gif_result gif__parse_extension_application(
* \param[in] frame The frame to parse extensions for.
* \param[in] pos Current position in data, updated on exit.
* \param[in] decode Whether to decode or skip over the extension.
- * \return GIF_INSUFFICIENT_DATA if more data is needed,
- * GIF_OK for success.
+ * \return NSGIF_INSUFFICIENT_DATA if more data is needed,
+ * NSGIF_OK for success.
*/
-static gif_result gif__parse_frame_extensions(
- struct gif_animation *gif,
- struct gif_frame *frame,
+static nsgif_result nsgif__parse_frame_extensions(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
{
- const uint8_t *gif_data = *pos;
- const uint8_t *gif_end = gif->gif_data + gif->buffer_size;
- int gif_bytes = gif_end - gif_data;
+ const uint8_t *nsgif_data = *pos;
+ const uint8_t *nsgif_end = gif->nsgif_data + gif->buffer_size;
+ int nsgif_bytes = nsgif_end - nsgif_data;
/* Initialise the extensions */
- while (gif_bytes > 0 && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
+ while (nsgif_bytes > 0 && nsgif_data[0] == NSGIF_EXTENSION_INTRODUCER) {
bool block_step = true;
- gif_result ret;
+ nsgif_result ret;
- gif_data++;
- gif_bytes--;
+ nsgif_data++;
+ nsgif_bytes--;
- if (gif_bytes == 0) {
- return GIF_INSUFFICIENT_DATA;
+ if (nsgif_bytes == 0) {
+ return NSGIF_INSUFFICIENT_DATA;
}
/* Switch on extension label */
- switch (gif_data[0]) {
- case GIF_EXTENSION_GRAPHIC_CONTROL:
+ switch (nsgif_data[0]) {
+ case NSGIF_EXTENSION_GRAPHIC_CONTROL:
if (decode) {
- ret = gif__parse_extension_graphic_control(
- frame, gif_data, gif_bytes);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_extension_graphic_control(
+ frame, nsgif_data, nsgif_bytes);
+ if (ret != NSGIF_OK) {
return ret;
}
}
break;
- case GIF_EXTENSION_APPLICATION:
+ case NSGIF_EXTENSION_APPLICATION:
if (decode) {
- ret = gif__parse_extension_application(
- gif, gif_data, gif_bytes);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_extension_application(
+ gif, nsgif_data, nsgif_bytes);
+ if (ret != NSGIF_OK) {
return ret;
}
}
break;
- case GIF_EXTENSION_COMMENT:
+ case NSGIF_EXTENSION_COMMENT:
/* Move the pointer to the first data sub-block Skip 1
* byte for the extension label. */
- ++gif_data;
+ ++nsgif_data;
block_step = false;
break;
@@ -715,31 +714,31 @@ static gif_result gif__parse_frame_extensions(
* bytes for the extension label and size fields Skip
* the extension size itself
*/
- if (gif_bytes < 2) {
- return GIF_INSUFFICIENT_DATA;
+ if (nsgif_bytes < 2) {
+ return NSGIF_INSUFFICIENT_DATA;
}
- gif_data += 2 + gif_data[1];
+ nsgif_data += 2 + nsgif_data[1];
}
/* Repeatedly skip blocks until we get a zero block or run out
* of data. This data is ignored by this gif decoder. */
- while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
- gif_data += gif_data[0] + 1;
- if (gif_data >= gif_end) {
- return GIF_INSUFFICIENT_DATA;
+ while (nsgif_data < nsgif_end && nsgif_data[0] != NSGIF_BLOCK_TERMINATOR) {
+ nsgif_data += nsgif_data[0] + 1;
+ if (nsgif_data >= nsgif_end) {
+ return NSGIF_INSUFFICIENT_DATA;
}
}
- gif_data++;
- gif_bytes = gif_end - gif_data;
+ nsgif_data++;
+ nsgif_bytes = nsgif_end - nsgif_data;
}
- if (gif_data > gif_end) {
- gif_data = gif_end;
+ if (nsgif_data > nsgif_end) {
+ nsgif_data = nsgif_end;
}
/* Set buffer position and return */
- *pos = gif_data;
- return GIF_OK;
+ *pos = nsgif_data;
+ return NSGIF_OK;
}
/**
@@ -763,33 +762,33 @@ static gif_result gif__parse_frame_extensions(
* \param[in] frame The frame to parse an image descriptor for.
* \param[in] pos Current position in data, updated on exit.
* \param[in] decode Whether to decode the image descriptor.
- * \return GIF_OK on success, appropriate error otherwise.
+ * \return NSGIF_OK on success, appropriate error otherwise.
*/
-static gif_result gif__parse_image_descriptor(
- struct gif_animation *gif,
- struct gif_frame *frame,
+static nsgif_result nsgif__parse_image_descriptor(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
{
const uint8_t *data = *pos;
- size_t len = gif->gif_data + gif->buffer_size - data;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
enum {
- GIF_IMAGE_DESCRIPTOR_LEN = 10u,
- GIF_IMAGE_SEPARATOR = 0x2Cu,
+ NSGIF_IMAGE_DESCRIPTOR_LEN = 10u,
+ NSGIF_IMAGE_SEPARATOR = 0x2Cu,
};
assert(gif != NULL);
assert(frame != NULL);
- if (len < GIF_IMAGE_DESCRIPTOR_LEN) {
- return GIF_INSUFFICIENT_DATA;
+ if (len < NSGIF_IMAGE_DESCRIPTOR_LEN) {
+ return NSGIF_INSUFFICIENT_DATA;
}
if (decode) {
unsigned x, y, w, h;
- if (data[0] != GIF_IMAGE_SEPARATOR) {
- return GIF_FRAME_DATA_ERROR;
+ if (data[0] != NSGIF_IMAGE_SEPARATOR) {
+ return NSGIF_FRAME_DATA_ERROR;
}
x = data[1] | (data[2] << 8);
@@ -808,8 +807,8 @@ static gif_result gif__parse_image_descriptor(
gif->height = (y + h > gif->height) ? y + h : gif->height;
}
- *pos += GIF_IMAGE_DESCRIPTOR_LEN;
- return GIF_OK;
+ *pos += NSGIF_IMAGE_DESCRIPTOR_LEN;
+ return NSGIF_OK;
}
/**
@@ -820,20 +819,20 @@ static gif_result gif__parse_image_descriptor(
* \param[in] colour_table_entries The number of colour table entries.
* \param[in] pos Current position in data, updated on exit.
* \param[in] decode Whether to decode the colour table.
- * \return GIF_OK on success, appropriate error otherwise.
+ * \return NSGIF_OK on success, appropriate error otherwise.
*/
-static gif_result gif__colour_table_extract(
- struct gif_animation *gif,
+static nsgif_result nsgif__colour_table_extract(
+ struct nsgif_animation *gif,
uint32_t *colour_table,
size_t colour_table_entries,
const uint8_t **pos,
bool decode)
{
const uint8_t *data = *pos;
- size_t len = gif->gif_data + gif->buffer_size - data;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
if (len < colour_table_entries * 3) {
- return GIF_INSUFFICIENT_DATA;
+ return NSGIF_INSUFFICIENT_DATA;
}
if (decode) {
@@ -857,7 +856,7 @@ static gif_result gif__colour_table_extract(
}
*pos += colour_table_entries * 3;
- return GIF_OK;
+ return NSGIF_OK;
}
/**
@@ -869,33 +868,33 @@ static gif_result gif__colour_table_extract(
* \param[in] frame The frame to get the colour table for.
* \param[in] pos Current position in data, updated on exit.
* \param[in] decode Whether to decode the colour table.
- * \return GIF_OK on success, appropriate error otherwise.
+ * \return NSGIF_OK on success, appropriate error otherwise.
*/
-static gif_result gif__parse_colour_table(
- struct gif_animation *gif,
- struct gif_frame *frame,
+static nsgif_result nsgif__parse_colour_table(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
{
- gif_result ret;
+ nsgif_result ret;
assert(gif != NULL);
assert(frame != NULL);
- if ((frame->flags & GIF_COLOUR_TABLE_MASK) == 0) {
+ if ((frame->flags & NSGIF_COLOUR_TABLE_MASK) == 0) {
gif->colour_table = gif->global_colour_table;
- return GIF_OK;
+ return NSGIF_OK;
}
- ret = gif__colour_table_extract(gif, gif->local_colour_table,
- 2 << (frame->flags & GIF_COLOUR_TABLE_SIZE_MASK),
+ ret = nsgif__colour_table_extract(gif, gif->local_colour_table,
+ 2 << (frame->flags & NSGIF_COLOUR_TABLE_SIZE_MASK),
pos, decode);
- if (ret != GIF_OK) {
+ if (ret != NSGIF_OK) {
return ret;
}
gif->colour_table = gif->local_colour_table;
- return GIF_OK;
+ return NSGIF_OK;
}
/**
@@ -907,19 +906,19 @@ static gif_result gif__parse_colour_table(
* \param[in] frame The frame to parse image data for.
* \param[in] pos Current position in data, updated on exit.
* \param[in] decode Whether to decode the image data.
- * \return GIF_OK on success, appropriate error otherwise.
+ * \return NSGIF_OK on success, appropriate error otherwise.
*/
-static gif_result gif__parse_image_data(
- struct gif_animation *gif,
- struct gif_frame *frame,
+static nsgif_result nsgif__parse_image_data(
+ struct nsgif_animation *gif,
+ struct nsgif_frame *frame,
const uint8_t **pos,
bool decode)
{
const uint8_t *data = *pos;
- size_t len = gif->gif_data + gif->buffer_size - data;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
uint32_t frame_idx = frame - gif->frames;
uint8_t minimum_code_size;
- gif_result ret;
+ nsgif_result ret;
assert(gif != NULL);
assert(frame != NULL);
@@ -932,22 +931,22 @@ static gif_result gif__parse_image_data(
* followed by a gif trailer is treated as OK, although without any
* image data. */
switch (len) {
- default: if (data[0] == GIF_TRAILER) return GIF_OK;
+ default: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
break;
- case 2: if (data[1] == GIF_TRAILER) return GIF_OK;
+ case 2: if (data[1] == NSGIF_TRAILER) return NSGIF_OK;
/* Fall through. */
- case 1: if (data[0] == GIF_TRAILER) return GIF_OK;
+ case 1: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
/* Fall through. */
- case 0: return GIF_INSUFFICIENT_DATA;
+ case 0: return NSGIF_INSUFFICIENT_DATA;
}
minimum_code_size = data[0];
if (minimum_code_size >= LZW_CODE_MAX) {
- return GIF_DATA_ERROR;
+ return NSGIF_DATA_ERROR;
}
if (decode) {
- ret = gif__update_bitmap(gif, frame, data, frame_idx);
+ ret = nsgif__update_bitmap(gif, frame, data, frame_idx);
} else {
uint32_t block_size = 0;
@@ -956,12 +955,12 @@ static gif_result gif__parse_image_data(
len--;
while (block_size != 1) {
- if (len < 1) return GIF_INSUFFICIENT_DATA;
+ if (len < 1) return NSGIF_INSUFFICIENT_DATA;
block_size = data[0] + 1;
/* Check if the frame data runs off the end of the file */
if (block_size > len) {
block_size = len;
- return GIF_OK;
+ return NSGIF_OK;
}
len -= block_size;
@@ -974,31 +973,31 @@ static gif_result gif__parse_image_data(
/* Check if we've finished */
if (len < 1) {
- return GIF_INSUFFICIENT_DATA;
+ return NSGIF_INSUFFICIENT_DATA;
} else {
- if (data[0] == GIF_TRAILER) {
- return GIF_OK;
+ if (data[0] == NSGIF_TRAILER) {
+ return NSGIF_OK;
}
}
- return GIF_WORKING;
+ return NSGIF_WORKING;
}
return ret;
}
-static struct gif_frame *gif__get_frame(
- struct gif_animation *gif,
+static struct nsgif_frame *nsgif__get_frame(
+ struct nsgif_animation *gif,
uint32_t frame_idx)
{
- struct gif_frame *frame;
+ struct nsgif_frame *frame;
if (gif->frame_holders > frame_idx) {
frame = &gif->frames[frame_idx];
} else {
/* Allocate more memory */
size_t count = frame_idx + 1;
- struct gif_frame *temp;
+ struct nsgif_frame *temp;
temp = realloc(gif->frames, count * sizeof(*frame));
if (temp == NULL) {
@@ -1010,7 +1009,7 @@ static struct gif_frame *gif__get_frame(
frame = &gif->frames[frame_idx];
frame->transparency = false;
- frame->transparency_index = GIF_NO_TRANSPARENCY;
+ frame->transparency_index = NSGIF_NO_TRANSPARENCY;
frame->frame_pointer = gif->buffer_position;
frame->redraw_required = false;
frame->disposal_method = 0;
@@ -1029,99 +1028,99 @@ static struct gif_frame *gif__get_frame(
* \param[in] frame_idx The frame number to decode.
* \param[in] decode Whether to decode the graphical image data.
* \return error code
- * - GIF_INSUFFICIENT_DATA reached unexpected end of source data.
- * - GIF_FRAME_DATA_ERROR for GIF frame data error
- * - GIF_INSUFFICIENT_MEMORY for insufficient memory to process
- * - GIF_DATA_ERROR for GIF error (invalid frame header)
- * - GIF_OK for successful decoding
- * - GIF_WORKING for successful decoding if more frames are expected
+ * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data.
+ * - NSGIF_FRAME_DATA_ERROR for GIF frame data error
+ * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process
+ * - NSGIF_DATA_ERROR for GIF error (invalid frame header)
+ * - NSGIF_OK for successful decoding
+ * - NSGIF_WORKING for successful decoding if more frames are expected
*/
-static gif_result gif__process_frame(
- struct gif_animation *gif,
+static nsgif_result nsgif__process_frame(
+ struct nsgif_animation *gif,
uint32_t frame_idx,
bool decode)
{
- gif_result ret;
+ nsgif_result ret;
const uint8_t *pos;
const uint8_t *end;
- struct gif_frame *frame;
+ struct nsgif_frame *frame;
- frame = gif__get_frame(gif, frame_idx);
+ frame = nsgif__get_frame(gif, frame_idx);
if (frame == NULL) {
- return GIF_INSUFFICIENT_MEMORY;
+ return NSGIF_INSUFFICIENT_MEMORY;
}
- end = gif->gif_data + gif->buffer_size;
+ end = gif->nsgif_data + gif->buffer_size;
if (decode) {
- pos = gif->gif_data + frame->frame_pointer;
+ pos = gif->nsgif_data + frame->frame_pointer;
/* Ensure this frame is supposed to be decoded */
if (frame->display == false) {
- return GIF_OK;
+ return NSGIF_OK;
}
/* Ensure the frame is in range to decode */
if (frame_idx > gif->frame_count_partial) {
- return GIF_INSUFFICIENT_DATA;
+ return NSGIF_INSUFFICIENT_DATA;
}
/* Done if frame is already decoded */
if ((int)frame_idx == gif->decoded_frame) {
- return GIF_OK;
+ return NSGIF_OK;
}
} else {
- pos = (uint8_t *)(gif->gif_data + gif->buffer_position);
+ pos = (uint8_t *)(gif->nsgif_data + gif->buffer_position);
/* Check if we've finished */
- if (pos < end && pos[0] == GIF_TRAILER) {
- return GIF_OK;
+ if (pos < end && pos[0] == NSGIF_TRAILER) {
+ return NSGIF_OK;
}
/* We could theoretically get some junk data that gives us
* millions of frames, so we ensure that we don't have a
* silly number. */
if (frame_idx > 4096) {
- return GIF_FRAME_DATA_ERROR;
+ return NSGIF_FRAME_DATA_ERROR;
}
}
/* Initialise any extensions */
- ret = gif__parse_frame_extensions(gif, frame, &pos, !decode);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_frame_extensions(gif, frame, &pos, !decode);
+ if (ret != NSGIF_OK) {
goto cleanup;
}
- ret = gif__parse_image_descriptor(gif, frame, &pos, !decode);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_image_descriptor(gif, frame, &pos, !decode);
+ if (ret != NSGIF_OK) {
goto cleanup;
}
- ret = gif__parse_colour_table(gif, frame, &pos, decode);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_colour_table(gif, frame, &pos, decode);
+ if (ret != NSGIF_OK) {
goto cleanup;
}
- ret = gif__parse_image_data(gif, frame, &pos, decode);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_image_data(gif, frame, &pos, decode);
+ if (ret != NSGIF_OK) {
goto cleanup;
}
cleanup:
if (!decode) {
- gif->buffer_position = pos - gif->gif_data;
+ gif->buffer_position = pos - gif->nsgif_data;
}
return ret;
}
/* exported function documented in libnsgif.h */
-void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks)
+void nsgif_create(nsgif_animation *gif, nsgif_bitmap_cb_vt *bitmap)
{
- memset(gif, 0, sizeof(gif_animation));
- gif->bitmap_callbacks = *bitmap_callbacks;
- gif->decoded_frame = GIF_INVALID_FRAME;
- gif->prev_index = GIF_INVALID_FRAME;
+ memset(gif, 0, sizeof(nsgif_animation));
+ gif->bitmap = *bitmap;
+ gif->decoded_frame = NSGIF_INVALID_FRAME;
+ gif->prev_index = NSGIF_INVALID_FRAME;
}
/**
@@ -1135,35 +1134,35 @@ void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks)
* \param[in] gif The GIF object we're decoding.
* \param[in,out] pos The current buffer position, updated on success.
* \param[in] strict Whether to require a known GIF version.
- * \return GIF_OK on success, appropriate error otherwise.
+ * \return NSGIF_OK on success, appropriate error otherwise.
*/
-static gif_result gif__parse_header(
- struct gif_animation *gif,
+static nsgif_result nsgif__parse_header(
+ struct nsgif_animation *gif,
const uint8_t **pos,
bool strict)
{
const uint8_t *data = *pos;
- size_t len = gif->gif_data + gif->buffer_size - data;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
if (len < 6) {
- return GIF_INSUFFICIENT_DATA;
+ return NSGIF_INSUFFICIENT_DATA;
}
if (strncmp((const char *) data, "GIF", 3) != 0) {
- return GIF_DATA_ERROR;
+ return NSGIF_DATA_ERROR;
}
data += 3;
if (strict == true) {
if ((strncmp((const char *) data, "87a", 3) != 0) &&
(strncmp((const char *) data, "89a", 3) != 0)) {
- return GIF_DATA_ERROR;
+ return NSGIF_DATA_ERROR;
}
}
data += 3;
*pos = data;
- return GIF_OK;
+ return NSGIF_OK;
}
/**
@@ -1183,43 +1182,43 @@ static gif_result gif__parse_header(
*
* \param[in] gif The GIF object we're decoding.
* \param[in,out] pos The current buffer position, updated on success.
- * \return GIF_OK on success, appropriate error otherwise.
+ * \return NSGIF_OK on success, appropriate error otherwise.
*/
-static gif_result gif__parse_logical_screen_descriptor(
- struct gif_animation *gif,
+static nsgif_result nsgif__parse_logical_screen_descriptor(
+ struct nsgif_animation *gif,
const uint8_t **pos)
{
const uint8_t *data = *pos;
- size_t len = gif->gif_data + gif->buffer_size - data;
+ size_t len = gif->nsgif_data + gif->buffer_size - data;
if (len < 7) {
- return GIF_INSUFFICIENT_DATA;
+ return NSGIF_INSUFFICIENT_DATA;
}
gif->width = data[0] | (data[1] << 8);
gif->height = data[2] | (data[3] << 8);
- gif->global_colours = data[4] & GIF_COLOUR_TABLE_MASK;
- gif->colour_table_size = 2 << (data[4] & GIF_COLOUR_TABLE_SIZE_MASK);
+ gif->global_colours = data[4] & NSGIF_COLOUR_TABLE_MASK;
+ gif->colour_table_size = 2 << (data[4] & NSGIF_COLOUR_TABLE_SIZE_MASK);
gif->bg_index = data[5];
gif->aspect_ratio = data[6];
gif->loop_count = 1;
*pos += 7;
- return GIF_OK;
+ return NSGIF_OK;
}
/* exported function documented in libnsgif.h */
-gif_result gif_initialise(gif_animation *gif, size_t size, const uint8_t *data)
+nsgif_result nsgif_initialise(nsgif_animation *gif, size_t size, const uint8_t *data)
{
- const uint8_t *gif_data;
- gif_result ret;
+ const uint8_t *nsgif_data;
+ nsgif_result ret;
/* Initialize values */
gif->buffer_size = size;
- gif->gif_data = data;
+ gif->nsgif_data = data;
/* Get our current processing position */
- gif_data = gif->gif_data + gif->buffer_position;
+ nsgif_data = gif->nsgif_data + gif->buffer_position;
/* See if we should initialise the GIF */
if (gif->buffer_position == 0) {
@@ -1235,20 +1234,20 @@ gif_result gif_initialise(gif_animation *gif, size_t size, const uint8_t *data)
/* The caller may have been lazy and not reset any values */
gif->frame_count = 0;
gif->frame_count_partial = 0;
- gif->decoded_frame = GIF_INVALID_FRAME;
+ gif->decoded_frame = NSGIF_INVALID_FRAME;
- ret = gif__parse_header(gif, &gif_data, false);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_header(gif, &nsgif_data, false);
+ if (ret != NSGIF_OK) {
return ret;
}
- ret = gif__parse_logical_screen_descriptor(gif, &gif_data);
- if (ret != GIF_OK) {
+ ret = nsgif__parse_logical_screen_descriptor(gif, &nsgif_data);
+ if (ret != NSGIF_OK) {
return ret;
}
/* Remember we've done this now */
- gif->buffer_position = gif_data - gif->gif_data;
+ gif->buffer_position = nsgif_data - gif->nsgif_data;
/* Some broken GIFs report the size as the screen size they
* were created in. As such, we detect for the common cases and
@@ -1272,26 +1271,26 @@ gif_result gif_initialise(gif_animation *gif, size_t size, const uint8_t *data)
* is lying to us. It's far better to give the wrong colours
* than to trample over some memory somewhere.
*/
- gif->global_colour_table = calloc(GIF_MAX_COLOURS, sizeof(uint32_t));
- gif->local_colour_table = calloc(GIF_MAX_COLOURS, sizeof(uint32_t));
+ gif->global_colour_table = calloc(NSGIF_MAX_COLOURS, sizeof(uint32_t));
+ gif->local_colour_table = calloc(NSGIF_MAX_COLOURS, sizeof(uint32_t));
if ((gif->global_colour_table == NULL) ||
(gif->local_colour_table == NULL)) {
- gif_finalise(gif);
- return GIF_INSUFFICIENT_MEMORY;
+ nsgif_finalise(gif);
+ return NSGIF_INSUFFICIENT_MEMORY;
}
/* Set the first colour to a value that will never occur in
* reality so we know if we've processed it
*/
- gif->global_colour_table[0] = GIF_PROCESS_COLOURS;
+ gif->global_colour_table[0] = NSGIF_PROCESS_COLOURS;
/* Check if the GIF has no frame data (13-byte header + 1-byte
* termination block) Although generally useless, the GIF
* specification does not expressly prohibit this
*/
if (gif->buffer_size == gif->buffer_position + 1) {
- if (gif_data[0] == GIF_TRAILER) {
- return GIF_OK;
+ if (nsgif_data[0] == NSGIF_TRAILER) {
+ return NSGIF_OK;
}
}
}
@@ -1300,18 +1299,18 @@ gif_result gif_initialise(gif_animation *gif, size_t size, const uint8_t *data)
* 0xff or 0x00 depending on the transparency we know if it's been
* filled in.
*/
- if (gif->global_colour_table[0] == GIF_PROCESS_COLOURS) {
+ if (gif->global_colour_table[0] == NSGIF_PROCESS_COLOURS) {
/* Check for a global colour map signified by bit 7 */
if (gif->global_colours) {
- ret = gif__colour_table_extract(gif,
+ ret = nsgif__colour_table_extract(gif,
gif->global_colour_table,
gif->colour_table_size,
- &gif_data, true);
- if (ret != GIF_OK) {
+ &nsgif_data, true);
+ if (ret != NSGIF_OK) {
return ret;
}
- gif->buffer_position = (gif_data - gif->gif_data);
+ gif->buffer_position = (nsgif_data - gif->nsgif_data);
} else {
/* Create a default colour table with the first two
* colours as black and white
@@ -1338,31 +1337,31 @@ gif_result gif_initialise(gif_animation *gif, size_t size, const uint8_t *data)
lzw_result res = lzw_context_create(
(struct lzw_ctx **)&gif->lzw_ctx);
if (res != LZW_OK) {
- return gif__error_from_lzw(res);
+ return nsgif__error_from_lzw(res);
}
}
/* Repeatedly try to initialise frames */
do {
- ret = gif__process_frame(gif, gif->frame_count, false);
- } while (ret == GIF_WORKING);
+ ret = nsgif__process_frame(gif, gif->frame_count, false);
+ } while (ret == NSGIF_WORKING);
return ret;
}
/* exported function documented in libnsgif.h */
-gif_result gif_decode_frame(gif_animation *gif, uint32_t frame)
+nsgif_result nsgif_decode_frame(nsgif_animation *gif, uint32_t frame)
{
- return gif__process_frame(gif, frame, true);
+ return nsgif__process_frame(gif, frame, true);
}
/* exported function documented in libnsgif.h */
-void gif_finalise(gif_animation *gif)
+void nsgif_finalise(nsgif_animation *gif)
{
/* Release all our memory blocks */
if (gif->frame_image) {
- assert(gif->bitmap_callbacks.bitmap_destroy);
- gif->bitmap_callbacks.bitmap_destroy(gif->frame_image);
+ assert(gif->bitmap.destroy);
+ gif->bitmap.destroy(gif->frame_image);
}
gif->frame_image = NULL;
diff --git a/test/decode_gif.c b/test/decode_gif.c
index dfc2b84..20cb571 100644
--- a/test/decode_gif.c
+++ b/test/decode_gif.c
@@ -15,7 +15,7 @@
#include <string.h>
#include <sys/stat.h>
-#include "../include/libnsgif.h"
+#include "../include/nsgif.h"
#define BYTES_PER_PIXEL 4
#define MAX_IMAGE_BYTES (48 * 1024 * 1024)
@@ -101,22 +101,22 @@ static unsigned char *load_file(const char *path, size_t *data_size)
return buffer;
}
-static void warning(const char *context, gif_result code)
+static void warning(const char *context, nsgif_result code)
{
fprintf(stderr, "%s failed: ", context);
switch (code)
{
- case GIF_FRAME_DATA_ERROR:
- fprintf(stderr, "GIF_FRAME_DATA_ERROR");
+ case NSGIF_FRAME_DATA_ERROR:
+ fprintf(stderr, "NSGIF_FRAME_DATA_ERROR");
break;
- case GIF_INSUFFICIENT_DATA:
- fprintf(stderr, "GIF_INSUFFICIENT_DATA");
+ case NSGIF_INSUFFICIENT_DATA:
+ fprintf(stderr, "NSGIF_INSUFFICIENT_DATA");
break;
- case GIF_DATA_ERROR:
- fprintf(stderr, "GIF_DATA_ERROR");
+ case NSGIF_DATA_ERROR:
+ fprintf(stderr, "NSGIF_DATA_ERROR");
break;
- case GIF_INSUFFICIENT_MEMORY:
- fprintf(stderr, "GIF_INSUFFICIENT_MEMORY");
+ case NSGIF_INSUFFICIENT_MEMORY:
+ fprintf(stderr, "NSGIF_INSUFFICIENT_MEMORY");
break;
default:
fprintf(stderr, "unknown code %i", code);
@@ -125,11 +125,11 @@ static void warning(const char *context, gif_result code)
fprintf(stderr, "\n");
}
-static void write_ppm(FILE* fh, const char *name, gif_animation *gif,
+static void write_ppm(FILE* fh, const char *name, nsgif_animation *gif,
bool no_write)
{
unsigned int i;
- gif_result code;
+ nsgif_result code;
if (!no_write) {
fprintf(fh, "P3\n");
@@ -147,9 +147,9 @@ static void write_ppm(FILE* fh, const char *name, gif_animation *gif,
unsigned int row, col;
unsigned char *image;
- code = gif_decode_frame(gif, i);
- if (code != GIF_OK)
- warning("gif_decode_frame", code);
+ code = nsgif_decode_frame(gif, i);
+ if (code != NSGIF_OK)
+ warning("nsgif_decode_frame", code);
if (!gif->frames[i].display) {
continue;
@@ -174,7 +174,7 @@ static void write_ppm(FILE* fh, const char *name, gif_animation *gif,
int main(int argc, char *argv[])
{
- gif_bitmap_callback_vt bitmap_callbacks = {
+ nsgif_bitmap_cb_vt bitmap_callbacks = {
bitmap_create,
bitmap_destroy,
bitmap_get_buffer,
@@ -182,9 +182,9 @@ int main(int argc, char *argv[])
bitmap_test_opaque,
bitmap_modified
};
- gif_animation gif;
+ nsgif_animation gif;
size_t size;
- gif_result code;
+ nsgif_result code;
unsigned char *data;
FILE *outf = stdout;
bool no_write = false;
@@ -213,21 +213,21 @@ int main(int argc, char *argv[])
}
/* create our gif animation */
- gif_create(&gif, &bitmap_callbacks);
+ nsgif_create(&gif, &bitmap_callbacks);
/* load file into memory */
data = load_file(argv[1], &size);
/* begin decoding */
do {
- code = gif_initialise(&gif, size, data);
- if (code != GIF_OK && code != GIF_WORKING) {
- warning("gif_initialise", code);
- gif_finalise(&gif);
+ code = nsgif_initialise(&gif, size, data);
+ if (code != NSGIF_OK && code != NSGIF_WORKING) {
+ warning("nsgif_initialise", code);
+ nsgif_finalise(&gif);
free(data);
return 1;
}
- } while (code != GIF_OK);
+ } while (code != NSGIF_OK);
write_ppm(outf, argv[1], &gif, no_write);
@@ -236,7 +236,7 @@ int main(int argc, char *argv[])
}
/* clean up */
- gif_finalise(&gif);
+ nsgif_finalise(&gif);
free(data);
return 0;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=83b32786e2a3f15fbf...
commit 83b32786e2a3f15fbf921fe5204474382480d6cb
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
GIF: Rename flag for whether the frame image has been decoded.
diff --git a/include/libnsgif.h b/include/libnsgif.h
index b281034..6b8d521 100644
--- a/include/libnsgif.h
+++ b/include/libnsgif.h
@@ -43,8 +43,8 @@ typedef struct gif_frame {
/** offset (in bytes) to the GIF frame data */
uint32_t frame_pointer;
- /** whether the frame has previously been used */
- bool virgin;
+ /** whether the frame has previously been decoded. */
+ bool decoded;
/** whether the frame is totally opaque */
bool opaque;
/** whether a full image redraw is required */
diff --git a/src/libnsgif.c b/src/libnsgif.c
index ecddf78..a1c7cb4 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -545,9 +545,9 @@ static gif_result gif__update_bitmap(
gif__bitmap_modified(gif);
- if (frame->virgin) {
+ if (!frame->decoded) {
frame->opaque = gif__bitmap_get_opaque(gif);
- frame->virgin = false;
+ frame->decoded = true;
}
gif__bitmap_set_opaque(gif, frame);
@@ -1016,7 +1016,7 @@ static struct gif_frame *gif__get_frame(
frame->disposal_method = 0;
frame->frame_delay = 100;
frame->display = false;
- frame->virgin = true;
+ frame->decoded = false;
}
return frame;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=5d732c75bf4012fe03...
commit 5d732c75bf4012fe0398a979d72806fa10713966
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Buildsystem: Add -Wextra to WARNFLAGS.
diff --git a/Makefile b/Makefile
index c348e20..2ae2406 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ include $(NSSHARED)/makefiles/Makefile.tools
TESTRUNNER = test/runtest.sh $(BUILDDIR) $(EXEEXT)
# Toolchain flags
-WARNFLAGS := -Wall -W -Wundef -Wpointer-arith -Wcast-align \
+WARNFLAGS := -Wall -Wextra -W -Wundef -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \
-Wmissing-declarations -Wnested-externs -pedantic
# BeOS/Haiku standard library headers create warnings
-----------------------------------------------------------------------
--
NetSurf GIF Decoder
1 year, 8 months
netsurf: branch master updated. release/3.10-157-g729e56d
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/729e56dccca8d480dccaf...
...commit http://git.netsurf-browser.org/netsurf.git/commit/729e56dccca8d480dccaf4e...
...tree http://git.netsurf-browser.org/netsurf.git/tree/729e56dccca8d480dccaf4ea2...
The branch, master has been updated
via 729e56dccca8d480dccaf4ea286eed5adc2e0a8f (commit)
via 4fc78449ff6fe7042aadf0f9e3706adbb21066d3 (commit)
from 88d5ea866858506aae2ff2ecbdee2b4f960ab89f (commit)
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/netsurf.git/commit/?id=729e56dccca8d480dcc...
commit 729e56dccca8d480dccaf4ea286eed5adc2e0a8f
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
GTK: Add support for word left/right keybindings.
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index 76bbd99..fa9c9cf 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -152,10 +152,14 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
case GDK_KEY(Left):
case GDK_KEY(KP_Left):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_WORD_LEFT;
return NS_KEY_LEFT;
case GDK_KEY(Right):
case GDK_KEY(KP_Right):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_WORD_RIGHT;
return NS_KEY_RIGHT;
case GDK_KEY(Up):
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=4fc78449ff6fe7042aa...
commit 4fc78449ff6fe7042aadf0f9e3706adbb21066d3
Author: Pranjal Kole <pranjal.kole7(a)gmail.com>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
textarea: always clear selection on NS_KEY_WORD_{LEFT,RIGHT}
This bug can be seen by selecting some text starting from the beginning
of a textarea (so that caret is 0) and then pressing the
NS_KEY_WORD_LEFT binding.
NS_KEY_WORD_LEFT was breaking early when caret was 0. So, to always
clear the selection, the clear selection code has been brought above the
break statement.
NS_KEY_WORD_RIGHT did not have such a break statement, so one has been
added for consistency, and because string operations are expensive.
diff --git a/desktop/textarea.c b/desktop/textarea.c
index e25c633..e0e8744 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -2743,6 +2743,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
case NS_KEY_WORD_LEFT:
if (readonly)
break;
+ if (ta->sel_start != -1) {
+ textarea_clear_selection(ta);
+ }
if (caret == 0)
break;
caret--;
@@ -2756,9 +2759,6 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
break;
}
}
- if (ta->sel_start != -1) {
- textarea_clear_selection(ta);
- }
break;
case NS_KEY_DELETE_WORD_LEFT:
if (readonly)
@@ -2807,6 +2807,11 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
case NS_KEY_WORD_RIGHT:
if (readonly)
break;
+ if (ta->sel_start != -1) {
+ textarea_clear_selection(ta);
+ }
+ if (caret == ta->show->len - 1)
+ break;
if (strchr(sep, ta->show->data[caret]) != NULL &&
caret < ta->show->len - 1) {
while (strchr(sep, ta->show->data[caret]) !=
@@ -2823,9 +2828,6 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
while (strchr(sep, ta->show->data[caret]) != NULL &&
caret < ta->show->len - 1)
caret++;
- if (ta->sel_start != -1) {
- textarea_clear_selection(ta);
- }
break;
case NS_KEY_DELETE_WORD_RIGHT:
if (readonly)
-----------------------------------------------------------------------
Summary of changes:
desktop/textarea.c | 14 ++++++++------
frontends/gtk/gui.c | 4 ++++
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/desktop/textarea.c b/desktop/textarea.c
index e25c633..e0e8744 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -2743,6 +2743,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
case NS_KEY_WORD_LEFT:
if (readonly)
break;
+ if (ta->sel_start != -1) {
+ textarea_clear_selection(ta);
+ }
if (caret == 0)
break;
caret--;
@@ -2756,9 +2759,6 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
break;
}
}
- if (ta->sel_start != -1) {
- textarea_clear_selection(ta);
- }
break;
case NS_KEY_DELETE_WORD_LEFT:
if (readonly)
@@ -2807,6 +2807,11 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
case NS_KEY_WORD_RIGHT:
if (readonly)
break;
+ if (ta->sel_start != -1) {
+ textarea_clear_selection(ta);
+ }
+ if (caret == ta->show->len - 1)
+ break;
if (strchr(sep, ta->show->data[caret]) != NULL &&
caret < ta->show->len - 1) {
while (strchr(sep, ta->show->data[caret]) !=
@@ -2823,9 +2828,6 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
while (strchr(sep, ta->show->data[caret]) != NULL &&
caret < ta->show->len - 1)
caret++;
- if (ta->sel_start != -1) {
- textarea_clear_selection(ta);
- }
break;
case NS_KEY_DELETE_WORD_RIGHT:
if (readonly)
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index 76bbd99..fa9c9cf 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -152,10 +152,14 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
case GDK_KEY(Left):
case GDK_KEY(KP_Left):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_WORD_LEFT;
return NS_KEY_LEFT;
case GDK_KEY(Right):
case GDK_KEY(KP_Right):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_WORD_RIGHT;
return NS_KEY_RIGHT;
case GDK_KEY(Up):
--
NetSurf Browser
1 year, 8 months
netsurf: branch master updated. release/3.10-155-g88d5ea8
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/88d5ea866858506aae2ff...
...commit http://git.netsurf-browser.org/netsurf.git/commit/88d5ea866858506aae2ff2e...
...tree http://git.netsurf-browser.org/netsurf.git/tree/88d5ea866858506aae2ff2ecb...
The branch, master has been updated
via 88d5ea866858506aae2ff2ecbdee2b4f960ab89f (commit)
via 76ede0f7d6e24996a7b886389c57dd502a046454 (commit)
from 9f305e4c3ba211834b194e5fac98089866c13d82 (commit)
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/netsurf.git/commit/?id=88d5ea866858506aae2...
commit 88d5ea866858506aae2ff2ecbdee2b4f960ab89f
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
GTK: Add support for word delete left/right.
These are ctrl+delete and ctrl+backspace.
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index a826b05..76bbd99 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -131,12 +131,16 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
case GDK_KEY(BackSpace):
if (key->state & GDK_SHIFT_MASK)
return NS_KEY_DELETE_LINE_START;
+ else if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_DELETE_WORD_LEFT;
else
return NS_KEY_DELETE_LEFT;
case GDK_KEY(Delete):
if (key->state & GDK_SHIFT_MASK)
return NS_KEY_DELETE_LINE_END;
+ else if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_DELETE_WORD_RIGHT;
else
return NS_KEY_DELETE_RIGHT;
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=76ede0f7d6e24996a7b...
commit 76ede0f7d6e24996a7b886389c57dd502a046454
Author: Pranjal Kole <pranjal.kole7(a)gmail.com>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
textarea: implement NS_KEY_DELETE_WORD_{LEFT,RIGHT}
NS_KEY_DELETE_WORD_{LEFT,RIGHT} have been added to
include/netsurf/keypress.h and implemented in desktop/textarea.c
An unsigned int, caret_copy, has been added since both of these require
a temporary variable to hold the original position of the caret.
The LEFT one deletes separators towards the left till it encounters a
non-separator and then deletes the non-separators until it encounters a
separator. The caret is moved towards the left by the number of
characters deleted.
The RIGHT one does the same towards the right, but the caret is kept at
its original position.
These are intended to be mapped to Ctrl+Backspace and Ctrl+Delete by
most frontends.
Additionally, some style and typo fixes have been made.
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 5bae27a..e25c633 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -58,7 +58,7 @@ struct line_info {
struct textarea_drag {
textarea_drag_type type;
union {
- struct scrollbar* scrollbar;
+ struct scrollbar *scrollbar;
} data;
};
@@ -625,7 +625,7 @@ static bool textarea_select(struct textarea *ta, int b_start, int b_end,
* \param ta Text area
* \return True on success, false otherwise
*/
-static bool textarea_select_fragment(struct textarea * ta)
+static bool textarea_select_fragment(struct textarea *ta)
{
int caret_pos;
size_t sel_start, sel_end;
@@ -676,7 +676,7 @@ static bool textarea_select_fragment(struct textarea * ta)
* \param ta textarea widget
* \return True on success, false otherwise
*/
-static bool textarea_select_paragraph(struct textarea * ta)
+static bool textarea_select_paragraph(struct textarea *ta)
{
int caret_pos;
size_t sel_start, sel_end;
@@ -1607,7 +1607,7 @@ static bool textarea_copy_to_undo_buffer(struct textarea *ta,
* \param b_end End byte index of replaced section (exclusive)
* \param rep Replacement UTF-8 text to insert
* \param rep_len Byte length of replacement UTF-8 text
- * \param add_to_clipboard True iff replaced text to be added to clipboard
+ * \param add_to_clipboard True if replaced text to be added to clipboard
* \param byte_delta Updated to change in byte count in textarea (ta->show)
* \param r Updated to area where redraw is required
* \return false on memory exhaustion, true otherwise
@@ -2452,7 +2452,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
struct textarea_msg msg;
struct rect r; /**< Redraw rectangle */
char utf8[6];
- unsigned int caret, length, b_off, b_len;
+ unsigned int caret, caret_copy, length, b_off, b_len;
int h_extent = ta->h_extent;
int v_extent = ta->v_extent;
int line;
@@ -2466,7 +2466,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
/* Word separators */
static const char *sep = " .\n";
- caret = textarea_get_caret(ta);
+ caret = caret_copy = textarea_get_caret(ta);
line = ta->caret_pos.line;
readonly = (ta->flags & TEXTAREA_READONLY ? true : false);
@@ -2760,6 +2760,50 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
textarea_clear_selection(ta);
}
break;
+ case NS_KEY_DELETE_WORD_LEFT:
+ if (readonly)
+ break;
+
+ /* If there is a selection, remove the selected
+ * characters */
+ if (ta->sel_start != -1) {
+ if (!textarea_replace_text(ta, ta->sel_start,
+ ta->sel_end, "", 0, false,
+ &byte_delta, &r))
+ return false;
+ caret = ta->sel_start;
+ textarea_clear_selection(ta);
+ redraw = true;
+ break;
+ }
+
+ if (caret == 0)
+ break;
+
+ /* caret goes left until a non-separator is
+ * encountered */
+ caret--;
+ while (strchr(sep, ta->show->data[caret]) != NULL &&
+ caret > 0)
+ caret--;
+
+ /* caret goes left until a separator is encountered */
+ for (; caret > 0; caret--) {
+ if (strchr(sep, ta->show->data[caret]) !=
+ NULL) {
+ caret++;
+ break;
+ }
+ }
+
+ /* Remove the characters from new caret position to
+ * original caret position */
+ if (!textarea_replace_text(ta, caret, caret_copy,
+ "", 0, false, &byte_delta, &r))
+ return false;
+
+ redraw = true;
+ break;
case NS_KEY_WORD_RIGHT:
if (readonly)
break;
@@ -2783,6 +2827,49 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
textarea_clear_selection(ta);
}
break;
+ case NS_KEY_DELETE_WORD_RIGHT:
+ if (readonly)
+ break;
+
+ /* If there is a selection, remove the selected
+ * characters */
+ if (ta->sel_start != -1) {
+ if (!textarea_replace_text(ta, ta->sel_start,
+ ta->sel_end, "", 0, false,
+ &byte_delta, &r))
+ return false;
+ caret = ta->sel_start;
+ textarea_clear_selection(ta);
+ redraw = true;
+ break;
+ }
+
+ if (caret == ta->show->len - 1)
+ break;
+
+ /* caret_copy goes right until a non-separator is
+ * encountered */
+ while (strchr(sep, ta->show->data[caret_copy]) != NULL
+ && caret_copy < ta->show->len - 1)
+ caret_copy++;
+
+ /* caret_copy goes right until a separator is
+ * encountered */
+ for (; caret_copy < ta->show->len - 1; caret_copy++) {
+ if (strchr(sep, ta->show->data[caret_copy]) !=
+ NULL) {
+ break;
+ }
+ }
+
+ /* Remove all the characters from original caret
+ * position to caret_copy */
+ if (!textarea_replace_text(ta, caret, caret_copy,
+ "", 0, false, &byte_delta, &r))
+ return false;
+
+ redraw = true;
+ break;
case NS_KEY_DELETE_LINE:
if (readonly)
break;
diff --git a/include/netsurf/keypress.h b/include/netsurf/keypress.h
index 604d2dd..84d9d41 100644
--- a/include/netsurf/keypress.h
+++ b/include/netsurf/keypress.h
@@ -59,7 +59,9 @@ enum input_key {
NS_KEY_TEXT_START,
NS_KEY_TEXT_END,
NS_KEY_WORD_LEFT,
+ NS_KEY_DELETE_WORD_LEFT,
NS_KEY_WORD_RIGHT,
+ NS_KEY_DELETE_WORD_RIGHT,
NS_KEY_PAGE_UP,
NS_KEY_PAGE_DOWN,
NS_KEY_DELETE_LINE_END,
-----------------------------------------------------------------------
Summary of changes:
desktop/textarea.c | 99 +++++++++++++++++++++++++++++++++++++++++---
frontends/gtk/gui.c | 4 ++
include/netsurf/keypress.h | 2 +
3 files changed, 99 insertions(+), 6 deletions(-)
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 5bae27a..e25c633 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -58,7 +58,7 @@ struct line_info {
struct textarea_drag {
textarea_drag_type type;
union {
- struct scrollbar* scrollbar;
+ struct scrollbar *scrollbar;
} data;
};
@@ -625,7 +625,7 @@ static bool textarea_select(struct textarea *ta, int b_start, int b_end,
* \param ta Text area
* \return True on success, false otherwise
*/
-static bool textarea_select_fragment(struct textarea * ta)
+static bool textarea_select_fragment(struct textarea *ta)
{
int caret_pos;
size_t sel_start, sel_end;
@@ -676,7 +676,7 @@ static bool textarea_select_fragment(struct textarea * ta)
* \param ta textarea widget
* \return True on success, false otherwise
*/
-static bool textarea_select_paragraph(struct textarea * ta)
+static bool textarea_select_paragraph(struct textarea *ta)
{
int caret_pos;
size_t sel_start, sel_end;
@@ -1607,7 +1607,7 @@ static bool textarea_copy_to_undo_buffer(struct textarea *ta,
* \param b_end End byte index of replaced section (exclusive)
* \param rep Replacement UTF-8 text to insert
* \param rep_len Byte length of replacement UTF-8 text
- * \param add_to_clipboard True iff replaced text to be added to clipboard
+ * \param add_to_clipboard True if replaced text to be added to clipboard
* \param byte_delta Updated to change in byte count in textarea (ta->show)
* \param r Updated to area where redraw is required
* \return false on memory exhaustion, true otherwise
@@ -2452,7 +2452,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
struct textarea_msg msg;
struct rect r; /**< Redraw rectangle */
char utf8[6];
- unsigned int caret, length, b_off, b_len;
+ unsigned int caret, caret_copy, length, b_off, b_len;
int h_extent = ta->h_extent;
int v_extent = ta->v_extent;
int line;
@@ -2466,7 +2466,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
/* Word separators */
static const char *sep = " .\n";
- caret = textarea_get_caret(ta);
+ caret = caret_copy = textarea_get_caret(ta);
line = ta->caret_pos.line;
readonly = (ta->flags & TEXTAREA_READONLY ? true : false);
@@ -2760,6 +2760,50 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
textarea_clear_selection(ta);
}
break;
+ case NS_KEY_DELETE_WORD_LEFT:
+ if (readonly)
+ break;
+
+ /* If there is a selection, remove the selected
+ * characters */
+ if (ta->sel_start != -1) {
+ if (!textarea_replace_text(ta, ta->sel_start,
+ ta->sel_end, "", 0, false,
+ &byte_delta, &r))
+ return false;
+ caret = ta->sel_start;
+ textarea_clear_selection(ta);
+ redraw = true;
+ break;
+ }
+
+ if (caret == 0)
+ break;
+
+ /* caret goes left until a non-separator is
+ * encountered */
+ caret--;
+ while (strchr(sep, ta->show->data[caret]) != NULL &&
+ caret > 0)
+ caret--;
+
+ /* caret goes left until a separator is encountered */
+ for (; caret > 0; caret--) {
+ if (strchr(sep, ta->show->data[caret]) !=
+ NULL) {
+ caret++;
+ break;
+ }
+ }
+
+ /* Remove the characters from new caret position to
+ * original caret position */
+ if (!textarea_replace_text(ta, caret, caret_copy,
+ "", 0, false, &byte_delta, &r))
+ return false;
+
+ redraw = true;
+ break;
case NS_KEY_WORD_RIGHT:
if (readonly)
break;
@@ -2783,6 +2827,49 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
textarea_clear_selection(ta);
}
break;
+ case NS_KEY_DELETE_WORD_RIGHT:
+ if (readonly)
+ break;
+
+ /* If there is a selection, remove the selected
+ * characters */
+ if (ta->sel_start != -1) {
+ if (!textarea_replace_text(ta, ta->sel_start,
+ ta->sel_end, "", 0, false,
+ &byte_delta, &r))
+ return false;
+ caret = ta->sel_start;
+ textarea_clear_selection(ta);
+ redraw = true;
+ break;
+ }
+
+ if (caret == ta->show->len - 1)
+ break;
+
+ /* caret_copy goes right until a non-separator is
+ * encountered */
+ while (strchr(sep, ta->show->data[caret_copy]) != NULL
+ && caret_copy < ta->show->len - 1)
+ caret_copy++;
+
+ /* caret_copy goes right until a separator is
+ * encountered */
+ for (; caret_copy < ta->show->len - 1; caret_copy++) {
+ if (strchr(sep, ta->show->data[caret_copy]) !=
+ NULL) {
+ break;
+ }
+ }
+
+ /* Remove all the characters from original caret
+ * position to caret_copy */
+ if (!textarea_replace_text(ta, caret, caret_copy,
+ "", 0, false, &byte_delta, &r))
+ return false;
+
+ redraw = true;
+ break;
case NS_KEY_DELETE_LINE:
if (readonly)
break;
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index a826b05..76bbd99 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -131,12 +131,16 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
case GDK_KEY(BackSpace):
if (key->state & GDK_SHIFT_MASK)
return NS_KEY_DELETE_LINE_START;
+ else if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_DELETE_WORD_LEFT;
else
return NS_KEY_DELETE_LEFT;
case GDK_KEY(Delete):
if (key->state & GDK_SHIFT_MASK)
return NS_KEY_DELETE_LINE_END;
+ else if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_DELETE_WORD_RIGHT;
else
return NS_KEY_DELETE_RIGHT;
diff --git a/include/netsurf/keypress.h b/include/netsurf/keypress.h
index 604d2dd..84d9d41 100644
--- a/include/netsurf/keypress.h
+++ b/include/netsurf/keypress.h
@@ -59,7 +59,9 @@ enum input_key {
NS_KEY_TEXT_START,
NS_KEY_TEXT_END,
NS_KEY_WORD_LEFT,
+ NS_KEY_DELETE_WORD_LEFT,
NS_KEY_WORD_RIGHT,
+ NS_KEY_DELETE_WORD_RIGHT,
NS_KEY_PAGE_UP,
NS_KEY_PAGE_DOWN,
NS_KEY_DELETE_LINE_END,
--
NetSurf Browser
1 year, 8 months
toolchains: branch chris/sdk-5334 created. 65ef05d3ff8daaff5c263a32f0da4dd01529c690
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/toolchains.git/shortlog/65ef05d3ff8daaff5c...
...commit http://git.netsurf-browser.org/toolchains.git/commit/65ef05d3ff8daaff5c26...
...tree http://git.netsurf-browser.org/toolchains.git/tree/65ef05d3ff8daaff5c263a...
The branch, chris/sdk-5334 has been created
at 65ef05d3ff8daaff5c263a32f0da4dd01529c690 (commit)
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/toolchains.git/commit/?id=65ef05d3ff8daaff...
commit 65ef05d3ff8daaff5c263a32f0da4dd01529c690
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
ppc-amigaos: Fix libcurl build
diff --git a/sdk/recipes/patches/libcurl/ppc-amigaos/configure.p b/sdk/recipes/patches/libcurl/ppc-amigaos/configure.p
new file mode 100644
index 0000000..91bf677
--- /dev/null
+++ b/sdk/recipes/patches/libcurl/ppc-amigaos/configure.p
@@ -0,0 +1,13 @@
+--- configure 2022-01-04 11:43:20.490235234 +0000
++++ configure 2022-01-04 11:56:40.357605123 +0000
+@@ -44201,9 +44201,7 @@ fi
+
+ if test "$USE_THREADS_POSIX" != "1"
+ then
+- CFLAGS="$CFLAGS -pthread"
+- # assign PTHREAD for pkg-config use
+- PTHREAD=" -pthread"
++
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+ $as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+ if ${ac_cv_lib_pthread_pthread_create+:} false; then :
diff --git a/sdk/recipes/patches/libcurl/ppc-amigaos/lib.curl_setup.h.p b/sdk/recipes/patches/libcurl/ppc-amigaos/lib.curl_setup.h.p
index 0e52d73..b0c6404 100644
--- a/sdk/recipes/patches/libcurl/ppc-amigaos/lib.curl_setup.h.p
+++ b/sdk/recipes/patches/libcurl/ppc-amigaos/lib.curl_setup.h.p
@@ -1,9 +1,9 @@
---- lib/curl_setup.h 2019-03-30 13:44:08.576270700 +0000
-+++ lib/curl_setup.h 2019-03-30 13:44:33.011975643 +0000
-@@ -314,7 +314,8 @@
- # include <exec/execbase.h>
+--- lib/curl_setup.h 2022-01-04 10:53:18.770467711 +0000
++++ lib/curl_setup.h 2022-01-04 10:54:58.216791681 +0000
+@@ -286,7 +286,8 @@
# include <proto/exec.h>
# include <proto/dos.h>
+ # include <unistd.h>
-# ifdef HAVE_PROTO_BSDSOCKET_H
+# define HAVE_SELECT 1
+# if 0
diff --git a/sdk/recipes/patches/libcurl/ppc-amigaos/lib.hostip4.c.p b/sdk/recipes/patches/libcurl/ppc-amigaos/lib.hostip4.c.p
index 39952b8..8d3ffa1 100644
--- a/sdk/recipes/patches/libcurl/ppc-amigaos/lib.hostip4.c.p
+++ b/sdk/recipes/patches/libcurl/ppc-amigaos/lib.hostip4.c.p
@@ -1,6 +1,6 @@
---- lib/hostip4.c 2020-01-05 09:50:51.000000000 +0000
-+++ lib/hostip4.c 2020-05-07 16:02:59.313823259 +0100
-@@ -120,6 +120,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct c
+--- lib/hostip4.c 2022-01-04 10:57:27.790270827 +0000
++++ lib/hostip4.c 2022-01-04 11:01:43.125967497 +0000
+@@ -120,6 +120,10 @@ struct Curl_addrinfo *Curl_getaddrinfo(s
* implying that only threadsafe code and function calls may be used.
*
*/
@@ -8,23 +8,23 @@
+#include <proto/exec.h>
+#include <proto/bsdsocket.h>
+#endif
- Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
- int port)
+ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
+ int port)
{
-@@ -130,6 +134,9 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const
+@@ -129,6 +133,9 @@ struct Curl_addrinfo *Curl_ipv4_resolve_
+ struct Curl_addrinfo *ai = NULL;
struct hostent *h = NULL;
- struct in_addr in;
struct hostent *buf = NULL;
+#ifdef __amigaos4__
+ struct SocketIFace *ISocket = NULL;
+#endif
- #ifdef ENABLE_IPV6
- {
-@@ -302,7 +309,20 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const
- * gethostbyname() is the preferred one.
- */
- else {
+ #if defined(HAVE_GETADDRINFO_THREADSAFE)
+ struct addrinfo hints;
+@@ -284,7 +291,20 @@ struct Curl_addrinfo *Curl_ipv4_resolve_
+ * getaddrinfo() nor gethostbyname_r() function or for which
+ * gethostbyname() is the preferred one.
+ */
+#ifdef __amigaos4__
+ struct Library *SocketBase = IExec->OpenLibrary("bsdsocket.library", 4);
+ if (SocketBase)
@@ -36,17 +36,16 @@
+ {
+ h = ISocket->gethostbyname((void*)hostname);
+ }
-+#else
- h = gethostbyname((void *)hostname);
++#else
+ h = gethostbyname((void *)hostname);
+#endif
#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
- }
-@@ -312,7 +332,14 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const
- if(buf) /* used a *_r() function */
+ if(h) {
+@@ -294,6 +314,14 @@ struct Curl_addrinfo *Curl_ipv4_resolve_
free(buf);
}
--
+
+#ifdef __amigaos4__
+ if (ISocket)
+ {
@@ -54,7 +53,7 @@
+ IExec->DropInterface((struct Interface *)ISocket);
+ IExec->CloseLibrary(SocketBase);
+ }
-+#endif
++#endif
return ai;
}
#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */
commitdiff http://git.netsurf-browser.org/toolchains.git/commit/?id=107e45072a2bf934...
commit 107e45072a2bf934494644442541b378c5fbfcb9
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
ppc-amigaos: Update SDK to v53.34
diff --git a/ppc-amigaos/Makefile b/ppc-amigaos/Makefile
index b6f8eef..ae2fa8b 100644
--- a/ppc-amigaos/Makefile
+++ b/ppc-amigaos/Makefile
@@ -18,11 +18,8 @@ UPSTREAM_MPC_VERSION := 1.0.2
UPSTREAM_MPC_TARBALL := mpc-$(UPSTREAM_MPC_VERSION).tar.gz
UPSTREAM_MPC_URI := http://ftp.gnu.org/gnu/mpc/$(UPSTREAM_MPC_TARBALL)
-UPSTREAM_NDK_TARBALL := SDK_53.29.lha
-UPSTREAM_NDK_URI := "http://hyperion-entertainment.biz/index.php/downloads?view=download&forma..."
-
-UPSTREAM_NDK_UPDATE_TARBALL := SDK_addon_final_edition_update2.zip
-UPSTREAM_NDK_UPDATE_URI := http://kas1e.mikendezign.com/aos4/SDK_addon_final_edition_update2.zip
+UPSTREAM_NDK_TARBALL := SDK_53.34.lha
+UPSTREAM_NDK_URI := "http://hyperion-entertainment.biz/index.php/downloads?view=download&forma..."
UPSTREAM_OPENURL_VERSION := 7.16
UPSTREAM_OPENURL_TARBALL := openurl-$(UPSTREAM_OPENURL_VERSION).tar.gz
@@ -92,26 +89,26 @@ $(BUILDSTEPS)/stage2.d: $(BUILDSTEPS)/srcdir-step3.d $(BUILDSTEPS)/binutils.d $(
# Rules to install the NDK
###
-$(BUILDSTEPS)/ndk.d: $(SOURCESDIR)/$(UPSTREAM_NDK_TARBALL) $(SOURCESDIR)/$(UPSTREAM_NDK_UPDATE_TARBALL) $(SOURCESDIR)/$(UPSTREAM_OPENURL_TARBALL) $(SOURCESDIR)/$(UPSTREAM_ONCHIPMEM_TARBALL) $(SOURCESDIR)/$(UPSTREAM_GUIGFX_TARBALL) $(SOURCESDIR)/$(UPSTREAM_RENDER_TARBALL) $(SOURCESDIR)/$(UPSTREAM_CODESETS_TARBALL)
+$(BUILDSTEPS)/ndk.d: $(SOURCESDIR)/$(UPSTREAM_NDK_TARBALL) $(SOURCESDIR)/$(UPSTREAM_OPENURL_TARBALL) $(SOURCESDIR)/$(UPSTREAM_ONCHIPMEM_TARBALL) $(SOURCESDIR)/$(UPSTREAM_GUIGFX_TARBALL) $(SOURCESDIR)/$(UPSTREAM_RENDER_TARBALL) $(SOURCESDIR)/$(UPSTREAM_CODESETS_TARBALL)
mkdir -p $(BUILDDIR)/ndk/tmp/
lha xw=$(BUILDDIR)/ndk $(SOURCESDIR)/$(UPSTREAM_NDK_TARBALL)
lha xw=$(BUILDDIR)/ndk/tmp $(BUILDDIR)/ndk/SDK_Install/base.lha
- lha xw=$(BUILDDIR)/ndk/tmp $(BUILDDIR)/ndk/SDK_Install/newlib-53.30.lha
+ lha xw=$(BUILDDIR)/ndk/tmp $(BUILDDIR)/ndk/SDK_Install/newlib-53.62.lha
lha xw=$(BUILDDIR)/ndk/tmp $(BUILDDIR)/ndk/SDK_Install/clib2-1.206.lha
- lha xw=$(BUILDDIR)/ndk/tmp $(BUILDDIR)/ndk/SDK_Install/pthreads-53.11.lha
+ lha xw=$(BUILDDIR)/ndk/tmp $(BUILDDIR)/ndk/SDK_Install/pthreads-53.12.lha
+ lha xw=$(BUILDDIR)/ndk/tmp $(BUILDDIR)/ndk/SDK_Install/execsg_sdk-54.26.lha
lha xw=$(BUILDDIR)/ndk/tmp $(SOURCESDIR)/$(UPSTREAM_ONCHIPMEM_TARBALL)
mkdir -p $(PREFIX)/$(TARGET_NAME)/SDK
- unzip -o $(SOURCESDIR)/$(UPSTREAM_NDK_UPDATE_TARBALL) -d $(BUILDDIR)/ndk/tmp
- cp -r $(BUILDDIR)/ndk/tmp/Include $(PREFIX)/$(TARGET_NAME)/SDK/include
- cp -r $(BUILDDIR)/ndk/tmp/newlib $(PREFIX)/$(TARGET_NAME)/SDK/newlib
- cp -r $(BUILDDIR)/ndk/tmp/clib2 $(PREFIX)/$(TARGET_NAME)/SDK/clib2
+ mkdir -p $(PREFIX)/$(TARGET_NAME)/SDK/include
+ mkdir -p $(PREFIX)/$(TARGET_NAME)/SDK/newlib
+ mkdir -p $(PREFIX)/$(TARGET_NAME)/SDK/clib2
+ cp -r $(BUILDDIR)/ndk/tmp/Include/* $(PREFIX)/$(TARGET_NAME)/SDK/include/
+ cp -r $(BUILDDIR)/ndk/tmp/newlib/* $(PREFIX)/$(TARGET_NAME)/SDK/newlib/
+ cp -r $(BUILDDIR)/ndk/tmp/clib2/* $(PREFIX)/$(TARGET_NAME)/SDK/clib2/
cp -r $(BUILDDIR)/ndk/tmp/Local/common/include/* $(PREFIX)/$(TARGET_NAME)/SDK/newlib/include/
cp -r $(BUILDDIR)/ndk/tmp/Local/newlib/lib/* $(PREFIX)/$(TARGET_NAME)/SDK/newlib/lib/
- cp -r $(BUILDDIR)/ndk/tmp/SDK/Include/* $(PREFIX)/$(TARGET_NAME)/SDK/include
- cp -r $(BUILDDIR)/ndk/tmp/SDK/newlib $(PREFIX)/$(TARGET_NAME)/SDK/newlib
- cp -r $(BUILDDIR)/ndk/tmp/SDK/local/newlib/lib/* $(PREFIX)/$(TARGET_NAME)/SDK/newlib/lib/
- cp -r $(BUILDDIR)/ndk/tmp/SDK/local/common/include/* $(PREFIX)/$(TARGET_NAME)/SDK/newlib/include/
- unzip -o $(SOURCESDIR)/$(UPSTREAM_NDK_UPDATE_TARBALL) -d $(BUILDDIR)/ndk/tmp
+ cp -r $(BUILDDIR)/ndk/tmp/SDK/Include/* $(PREFIX)/$(TARGET_NAME)/SDK/include/
+ cp -r $(BUILDDIR)/ndk/tmp/local/newlib/include/* $(PREFIX)/$(TARGET_NAME)/SDK/newlib/include/
mkdir -p $(BUILDDIR)/openurl
cd $(BUILDDIR)/openurl && tar xaf $(SOURCESDIR)/$(UPSTREAM_OPENURL_TARBALL)
cp -r $(BUILDDIR)/openurl/libopenurl-$(UPSTREAM_OPENURL_VERSION)/include/* $(PREFIX)/$(TARGET_NAME)/SDK/include/include_h/
@@ -195,9 +192,6 @@ $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL):
$(SOURCESDIR)/$(UPSTREAM_NDK_TARBALL):
wget -q -O $@ $(UPSTREAM_NDK_URI)
-$(SOURCESDIR)/$(UPSTREAM_NDK_UPDATE_TARBALL):
- wget -q -O $@ $(UPSTREAM_NDK_UPDATE_URI)
-
$(SOURCESDIR)/$(UPSTREAM_OPENURL_TARBALL):
wget -q -O $@ $(UPSTREAM_OPENURL_URI)
-----------------------------------------------------------------------
--
Cross-compilation toolchains and environments
1 year, 8 months