netsurf: branch master updated. release/3.10-135-gce23f50
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/ce23f500d13d6f32ed702...
...commit http://git.netsurf-browser.org/netsurf.git/commit/ce23f500d13d6f32ed70238...
...tree http://git.netsurf-browser.org/netsurf.git/tree/ce23f500d13d6f32ed702386c...
The branch, master has been updated
via ce23f500d13d6f32ed702386caaef7db19c112a2 (commit)
via 6f659da675917f6cfa651631ff49a244973f02df (commit)
from 93b68a9a4869cac3ec4927b35f29cac32e106832 (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=ce23f500d13d6f32ed7...
commit ce23f500d13d6f32ed702386caaef7db19c112a2
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
RISC OS: Unify both browser window redraw call paths.
diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c
index 2466236..28ef06f 100644
--- a/frontends/riscos/window.c
+++ b/frontends/riscos/window.c
@@ -1639,6 +1639,57 @@ static void ro_gui_window_close(wimp_w w)
}
}
+/**
+ * Wrapper for calls to browser_window_redraw for a wimp_draw rectangle.
+ *
+ * \param[in] gui_win Window to render.
+ * \param[in] wimp_rect The area of gui_win to render into.
+ * \param[in] use_buffer Whether to use buffered rendering.
+ */
+static inline void ro_gui_window__redraw_rect(
+ const struct gui_window *gui_win,
+ const wimp_draw *wimp_rect,
+ bool use_buffer)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
+ struct rect clip;
+
+ /* OS's redraw request coordinates are in screen coordinates,
+ * with an origin at the bottom left of the screen.
+ * Find the coordinate of the top left of the document in terms
+ * of OS screen coordinates.
+ * NOTE: OS units are 2 per px. */
+ ro_plot_origin_x = wimp_rect->box.x0 - wimp_rect->xscroll;
+ ro_plot_origin_y = wimp_rect->box.y1 - wimp_rect->yscroll;
+
+ /* Adjust clip rect for origin. */
+ ro_plot_clip_rect.x0 = wimp_rect->clip.x0 - ro_plot_origin_x;
+ ro_plot_clip_rect.y0 = ro_plot_origin_y - wimp_rect->clip.y0;
+ ro_plot_clip_rect.x1 = wimp_rect->clip.x1 - ro_plot_origin_x;
+ ro_plot_clip_rect.y1 = ro_plot_origin_y - wimp_rect->clip.y1;
+
+ /* Convert OS redraw rectangle request coordinates into NetSurf
+ * coordinates. NetSurf coordinates have origin at top left of
+ * document and units are in px. */
+ clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
+
+ if (use_buffer) {
+ ro_gui_buffer_open(wimp_rect);
+ }
+
+ browser_window_redraw(gui_win->bw, 0, 0, &clip, &ctx);
+
+ if (use_buffer) {
+ ro_gui_buffer_close();
+ }
+}
/**
* Handle a Redraw_Window_Request for a browser window.
@@ -1650,11 +1701,6 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
osbool more;
struct gui_window *g;
os_error *error;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w);
@@ -1675,37 +1721,8 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
return;
}
while (more) {
- struct rect clip;
-
- /* OS's redraw request coordinates are in screen coordinates,
- * with an origin at the bottom left of the screen.
- * Find the coordinate of the top left of the document in terms
- * of OS screen coordinates.
- * NOTE: OS units are 2 per px. */
- ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
- ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
-
- /* Adjust clip rect for origin. */
- ro_plot_clip_rect.x0 = redraw->clip.x0 - ro_plot_origin_x;
- ro_plot_clip_rect.y0 = ro_plot_origin_y - redraw->clip.y0;
- ro_plot_clip_rect.x1 = redraw->clip.x1 - ro_plot_origin_x;
- ro_plot_clip_rect.y1 = ro_plot_origin_y - redraw->clip.y1;
-
- /* Convert OS redraw rectangle request coordinates into NetSurf
- * coordinates. NetSurf coordinates have origin at top left of
- * document and units are in px. */
- clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
- clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
- clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
- clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
-
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_open(redraw);
-
- browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
-
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_close();
+ ro_gui_window__redraw_rect(g, redraw,
+ ro_gui_current_redraw_gui->option.buffer_everything);
/* Check to see if there are more rectangles to draw and
* get next one */
@@ -4676,22 +4693,15 @@ void ro_gui_window_redraw_all(void)
}
}
-
/* exported interface documented in riscos/window.h */
void ro_gui_window_update_boxes(void)
{
osbool more;
bool use_buffer;
wimp_draw update;
- struct rect clip;
os_error *error;
struct update_box *cur;
struct gui_window *g;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
for (cur = pending_updates; cur != NULL; cur = cur->next) {
g = cur->g;
@@ -4717,31 +4727,8 @@ void ro_gui_window_update_boxes(void)
/* Set the current redraw gui_window to get options from */
ro_gui_current_redraw_gui = g;
- ro_plot_origin_x = update.box.x0 - update.xscroll;
- ro_plot_origin_y = update.box.y1 - update.yscroll;
-
while (more) {
- /* Adjust clip rect for origin. */
- ro_plot_clip_rect.x0 = update.clip.x0 - ro_plot_origin_x;
- ro_plot_clip_rect.y0 = ro_plot_origin_y - update.clip.y0;
- ro_plot_clip_rect.x1 = update.clip.x1 - ro_plot_origin_x;
- ro_plot_clip_rect.y1 = ro_plot_origin_y - update.clip.y1;
-
- /* Convert OS redraw rectangle request coordinates into
- * NetSurf coordinates. NetSurf coordinates have origin
- * at top left of document and units are in px. */
- clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
- clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
- clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
- clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
-
- if (use_buffer)
- ro_gui_buffer_open(&update);
-
- browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
-
- if (use_buffer)
- ro_gui_buffer_close();
+ ro_gui_window__redraw_rect(g, &update, use_buffer);
error = xwimp_get_rectangle(&update, &more);
/* RISC OS 3.7 returns an error here if enough buffer
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=6f659da675917f6cfa6...
commit 6f659da675917f6cfa651631ff49a244973f02df
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
RISC OS: Constify redraw region through buffer API.
diff --git a/frontends/riscos/buffer.c b/frontends/riscos/buffer.c
index c63a270..9c8f8fe 100644
--- a/frontends/riscos/buffer.c
+++ b/frontends/riscos/buffer.c
@@ -81,7 +81,7 @@ static os_mode mode;
*
* \param redraw the current WIMP redraw area to buffer
*/
-void ro_gui_buffer_open(wimp_draw *redraw)
+void ro_gui_buffer_open(const wimp_draw *redraw)
{
int size;
int total_size;
diff --git a/frontends/riscos/buffer.h b/frontends/riscos/buffer.h
index a683c32..7de0ecd 100644
--- a/frontends/riscos/buffer.h
+++ b/frontends/riscos/buffer.h
@@ -25,7 +25,7 @@
#include "oslib/wimp.h"
-void ro_gui_buffer_open(wimp_draw *redraw);
+void ro_gui_buffer_open(const wimp_draw *redraw);
void ro_gui_buffer_close(void);
#endif
-----------------------------------------------------------------------
Summary of changes:
frontends/riscos/buffer.c | 2 +-
frontends/riscos/buffer.h | 2 +-
frontends/riscos/window.c | 121 ++++++++++++++++++++-------------------------
3 files changed, 56 insertions(+), 69 deletions(-)
diff --git a/frontends/riscos/buffer.c b/frontends/riscos/buffer.c
index c63a270..9c8f8fe 100644
--- a/frontends/riscos/buffer.c
+++ b/frontends/riscos/buffer.c
@@ -81,7 +81,7 @@ static os_mode mode;
*
* \param redraw the current WIMP redraw area to buffer
*/
-void ro_gui_buffer_open(wimp_draw *redraw)
+void ro_gui_buffer_open(const wimp_draw *redraw)
{
int size;
int total_size;
diff --git a/frontends/riscos/buffer.h b/frontends/riscos/buffer.h
index a683c32..7de0ecd 100644
--- a/frontends/riscos/buffer.h
+++ b/frontends/riscos/buffer.h
@@ -25,7 +25,7 @@
#include "oslib/wimp.h"
-void ro_gui_buffer_open(wimp_draw *redraw);
+void ro_gui_buffer_open(const wimp_draw *redraw);
void ro_gui_buffer_close(void);
#endif
diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c
index 2466236..28ef06f 100644
--- a/frontends/riscos/window.c
+++ b/frontends/riscos/window.c
@@ -1639,6 +1639,57 @@ static void ro_gui_window_close(wimp_w w)
}
}
+/**
+ * Wrapper for calls to browser_window_redraw for a wimp_draw rectangle.
+ *
+ * \param[in] gui_win Window to render.
+ * \param[in] wimp_rect The area of gui_win to render into.
+ * \param[in] use_buffer Whether to use buffered rendering.
+ */
+static inline void ro_gui_window__redraw_rect(
+ const struct gui_window *gui_win,
+ const wimp_draw *wimp_rect,
+ bool use_buffer)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
+ struct rect clip;
+
+ /* OS's redraw request coordinates are in screen coordinates,
+ * with an origin at the bottom left of the screen.
+ * Find the coordinate of the top left of the document in terms
+ * of OS screen coordinates.
+ * NOTE: OS units are 2 per px. */
+ ro_plot_origin_x = wimp_rect->box.x0 - wimp_rect->xscroll;
+ ro_plot_origin_y = wimp_rect->box.y1 - wimp_rect->yscroll;
+
+ /* Adjust clip rect for origin. */
+ ro_plot_clip_rect.x0 = wimp_rect->clip.x0 - ro_plot_origin_x;
+ ro_plot_clip_rect.y0 = ro_plot_origin_y - wimp_rect->clip.y0;
+ ro_plot_clip_rect.x1 = wimp_rect->clip.x1 - ro_plot_origin_x;
+ ro_plot_clip_rect.y1 = ro_plot_origin_y - wimp_rect->clip.y1;
+
+ /* Convert OS redraw rectangle request coordinates into NetSurf
+ * coordinates. NetSurf coordinates have origin at top left of
+ * document and units are in px. */
+ clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
+
+ if (use_buffer) {
+ ro_gui_buffer_open(wimp_rect);
+ }
+
+ browser_window_redraw(gui_win->bw, 0, 0, &clip, &ctx);
+
+ if (use_buffer) {
+ ro_gui_buffer_close();
+ }
+}
/**
* Handle a Redraw_Window_Request for a browser window.
@@ -1650,11 +1701,6 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
osbool more;
struct gui_window *g;
os_error *error;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w);
@@ -1675,37 +1721,8 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
return;
}
while (more) {
- struct rect clip;
-
- /* OS's redraw request coordinates are in screen coordinates,
- * with an origin at the bottom left of the screen.
- * Find the coordinate of the top left of the document in terms
- * of OS screen coordinates.
- * NOTE: OS units are 2 per px. */
- ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
- ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
-
- /* Adjust clip rect for origin. */
- ro_plot_clip_rect.x0 = redraw->clip.x0 - ro_plot_origin_x;
- ro_plot_clip_rect.y0 = ro_plot_origin_y - redraw->clip.y0;
- ro_plot_clip_rect.x1 = redraw->clip.x1 - ro_plot_origin_x;
- ro_plot_clip_rect.y1 = ro_plot_origin_y - redraw->clip.y1;
-
- /* Convert OS redraw rectangle request coordinates into NetSurf
- * coordinates. NetSurf coordinates have origin at top left of
- * document and units are in px. */
- clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
- clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
- clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
- clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
-
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_open(redraw);
-
- browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
-
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_close();
+ ro_gui_window__redraw_rect(g, redraw,
+ ro_gui_current_redraw_gui->option.buffer_everything);
/* Check to see if there are more rectangles to draw and
* get next one */
@@ -4676,22 +4693,15 @@ void ro_gui_window_redraw_all(void)
}
}
-
/* exported interface documented in riscos/window.h */
void ro_gui_window_update_boxes(void)
{
osbool more;
bool use_buffer;
wimp_draw update;
- struct rect clip;
os_error *error;
struct update_box *cur;
struct gui_window *g;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
for (cur = pending_updates; cur != NULL; cur = cur->next) {
g = cur->g;
@@ -4717,31 +4727,8 @@ void ro_gui_window_update_boxes(void)
/* Set the current redraw gui_window to get options from */
ro_gui_current_redraw_gui = g;
- ro_plot_origin_x = update.box.x0 - update.xscroll;
- ro_plot_origin_y = update.box.y1 - update.yscroll;
-
while (more) {
- /* Adjust clip rect for origin. */
- ro_plot_clip_rect.x0 = update.clip.x0 - ro_plot_origin_x;
- ro_plot_clip_rect.y0 = ro_plot_origin_y - update.clip.y0;
- ro_plot_clip_rect.x1 = update.clip.x1 - ro_plot_origin_x;
- ro_plot_clip_rect.y1 = ro_plot_origin_y - update.clip.y1;
-
- /* Convert OS redraw rectangle request coordinates into
- * NetSurf coordinates. NetSurf coordinates have origin
- * at top left of document and units are in px. */
- clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
- clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
- clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
- clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
-
- if (use_buffer)
- ro_gui_buffer_open(&update);
-
- browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
-
- if (use_buffer)
- ro_gui_buffer_close();
+ ro_gui_window__redraw_rect(g, &update, use_buffer);
error = xwimp_get_rectangle(&update, &more);
/* RISC OS 3.7 returns an error here if enough buffer
--
NetSurf Browser
2 years, 4 months
netsurf: branch master updated. release/3.10-133-g93b68a9
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/93b68a9a4869cac3ec492...
...commit http://git.netsurf-browser.org/netsurf.git/commit/93b68a9a4869cac3ec4927b...
...tree http://git.netsurf-browser.org/netsurf.git/tree/93b68a9a4869cac3ec4927b35...
The branch, master has been updated
via 93b68a9a4869cac3ec4927b35f29cac32e106832 (commit)
via c5aca9d8cecd256d957c551229be2b6856875e25 (commit)
via fb8c227ff018e21a0abd9a15852a060f4b84ba1b (commit)
from 81c40ab7c29e6bc59f4c10fa1655fd7e4a47a1ec (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=93b68a9a4869cac3ec4...
commit 93b68a9a4869cac3ec4927b35f29cac32e106832
Author: Michael Drake <michael.drake(a)codethink.co.uk>
Commit: Michael Drake <michael.drake(a)codethink.co.uk>
RISC OS: Corewindow: Fix autoscroll segfault when pointer leaves window.
diff --git a/frontends/riscos/corewindow.c b/frontends/riscos/corewindow.c
index 9216712..88bb5c3 100644
--- a/frontends/riscos/corewindow.c
+++ b/frontends/riscos/corewindow.c
@@ -52,6 +52,8 @@
#define wimp_KEY_END wimp_KEY_COPY
#endif
+static struct ro_corewindow *ro_cw_drag_cw;
+
/**
* Update a windows scrollbars.
*
@@ -255,6 +257,11 @@ static void ro_cw_mouse_at(wimp_pointer *pointer, void *data)
(unsigned int)pointer->w);
return;
}
+ if (ro_cw != ro_cw_drag_cw) {
+ NSLOG(netsurf, DEEPDEBUG, "Called without drag window: %p",
+ ro_cw);
+ return;
+ }
NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
/* Not a Menu click. */
@@ -391,6 +398,7 @@ ro_cw_drag_start(struct ro_corewindow *ro_cw,
ro_warn_user("WimpError", error->errmess);
}
+ ro_cw_drag_cw = ro_cw;
ro_mouse_drag_start(ro_cw_drag_end, ro_cw_mouse_at, NULL, NULL);
}
}
@@ -1046,6 +1054,8 @@ ro_corewindow_init(struct ro_corewindow *ro_cw,
}
/* setup context for event handlers */
+ NSLOG(netsurf, INFO, "Setting corewindow %p for window handle %p",
+ ro_cw, ro_cw->wh);
ro_gui_wimp_event_set_user_data(ro_cw->wh, ro_cw);
/* register wimp events. */
diff --git a/frontends/riscos/global_history.c b/frontends/riscos/global_history.c
index 4f0dbd4..51f5390 100644
--- a/frontends/riscos/global_history.c
+++ b/frontends/riscos/global_history.c
@@ -444,6 +444,9 @@ static nserror ro_global_history_init(void)
return res;
}
+ NSLOG(netsurf, INFO, "Created global history corewindow: %p",
+ &ncwin->core);
+
res = global_history_init(ncwin->core.cb_table,
(struct core_window *)ncwin);
if (res != NSERROR_OK) {
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=c5aca9d8cecd256d957...
commit c5aca9d8cecd256d957c551229be2b6856875e25
Author: Michael Drake <michael.drake(a)codethink.co.uk>
Commit: Michael Drake <michael.drake(a)codethink.co.uk>
RISC OS: Fix EX0 EY0 rendering glitches when scrolling.
diff --git a/frontends/riscos/corewindow.c b/frontends/riscos/corewindow.c
index 2ef05da..9216712 100644
--- a/frontends/riscos/corewindow.c
+++ b/frontends/riscos/corewindow.c
@@ -120,10 +120,15 @@ static void ro_cw_redraw(wimp_draw *redraw)
origin_x = redraw->box.x0 - redraw->xscroll;
origin_y = redraw->box.y1 + ro_cw->origin_y - redraw->yscroll;
- r.x0 = (redraw->clip.x0 - origin_x) / 2;
- r.y0 = (origin_y - redraw->clip.y1) / 2;
- r.x1 = r.x0 + ((redraw->clip.x1 - redraw->clip.x0) / 2);
- r.y1 = r.y0 + ((redraw->clip.y1 - redraw->clip.y0) / 2);
+ ro_plot_clip_rect.x0 = redraw->clip.x0 - origin_x;
+ ro_plot_clip_rect.y0 = origin_y - redraw->clip.y0;
+ ro_plot_clip_rect.x1 = redraw->clip.x1 - origin_x;
+ ro_plot_clip_rect.y1 = origin_y - redraw->clip.y1;
+
+ r.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ r.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ r.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ r.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
/* call the draw callback */
ro_cw->draw(ro_cw, origin_x, origin_y, &r);
diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h
index 831c57d..5ff17e9 100644
--- a/frontends/riscos/gui.h
+++ b/frontends/riscos/gui.h
@@ -165,6 +165,7 @@ void ro_gui_print_prepare(struct gui_window *g);
extern const struct plotter_table ro_plotters;
extern int ro_plot_origin_x;
extern int ro_plot_origin_y;
+extern struct rect ro_plot_clip_rect;
/* in theme_install.c */
bool ro_gui_theme_install_apply(wimp_w w);
diff --git a/frontends/riscos/plotters.c b/frontends/riscos/plotters.c
index 25c953f..e38e746 100644
--- a/frontends/riscos/plotters.c
+++ b/frontends/riscos/plotters.c
@@ -39,6 +39,7 @@
int ro_plot_origin_x = 0;
int ro_plot_origin_y = 0;
+struct rect ro_plot_clip_rect;
/** One version of the A9home OS is incapable of drawing patterned lines */
bool ro_plot_patterned_lines = true;
@@ -115,6 +116,14 @@ ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
int clip_x1 = clip->x1 * 2;
int clip_y1 = clip->y0 * 2;
+ /* Avoid artefacts due to clip rectangle offsetting in EX0 EY0 modes.
+ * The area the WIMP asked us to draw might have dimensions that are
+ * not a multiple of 2. */
+ if (clip_x0 < ro_plot_clip_rect.x0) clip_x0 = ro_plot_clip_rect.x0;
+ if (clip_x1 > ro_plot_clip_rect.x1) clip_x1 = ro_plot_clip_rect.x1;
+ if (clip_y0 > ro_plot_clip_rect.y0) clip_y0 = ro_plot_clip_rect.y0;
+ if (clip_y1 < ro_plot_clip_rect.y1) clip_y1 = ro_plot_clip_rect.y1;
+
clip_x0 = ro_plot_origin_x + clip_x0;
clip_y0 = ro_plot_origin_y - clip_y0;
clip_x1 = ro_plot_origin_x + clip_x1 - 1;
diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c
index f1728af..2466236 100644
--- a/frontends/riscos/window.c
+++ b/frontends/riscos/window.c
@@ -1685,13 +1685,19 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
+ /* Adjust clip rect for origin. */
+ ro_plot_clip_rect.x0 = redraw->clip.x0 - ro_plot_origin_x;
+ ro_plot_clip_rect.y0 = ro_plot_origin_y - redraw->clip.y0;
+ ro_plot_clip_rect.x1 = redraw->clip.x1 - ro_plot_origin_x;
+ ro_plot_clip_rect.y1 = ro_plot_origin_y - redraw->clip.y1;
+
/* Convert OS redraw rectangle request coordinates into NetSurf
* coordinates. NetSurf coordinates have origin at top left of
* document and units are in px. */
- clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */
- clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */
- clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */
- clip.y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */
+ clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
if (ro_gui_current_redraw_gui->option.buffer_everything)
ro_gui_buffer_open(redraw);
@@ -4715,10 +4721,19 @@ void ro_gui_window_update_boxes(void)
ro_plot_origin_y = update.box.y1 - update.yscroll;
while (more) {
- clip.x0 = (update.clip.x0 - ro_plot_origin_x) / 2;
- clip.y0 = (ro_plot_origin_y - update.clip.y1) / 2;
- clip.x1 = (update.clip.x1 - ro_plot_origin_x) / 2;
- clip.y1 = (ro_plot_origin_y - update.clip.y0) / 2;
+ /* Adjust clip rect for origin. */
+ ro_plot_clip_rect.x0 = update.clip.x0 - ro_plot_origin_x;
+ ro_plot_clip_rect.y0 = ro_plot_origin_y - update.clip.y0;
+ ro_plot_clip_rect.x1 = update.clip.x1 - ro_plot_origin_x;
+ ro_plot_clip_rect.y1 = ro_plot_origin_y - update.clip.y1;
+
+ /* Convert OS redraw rectangle request coordinates into
+ * NetSurf coordinates. NetSurf coordinates have origin
+ * at top left of document and units are in px. */
+ clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
if (use_buffer)
ro_gui_buffer_open(&update);
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=fb8c227ff018e21a0ab...
commit fb8c227ff018e21a0abd9a15852a060f4b84ba1b
Author: Michael Drake <michael.drake(a)codethink.co.uk>
Commit: Michael Drake <michael.drake(a)codethink.co.uk>
RISC OS: Plotters: On RISC OS y1 is top and y0 is bottom.
When storing RISC OS coordinates, use y0 and y1 consistently.
diff --git a/frontends/riscos/plotters.c b/frontends/riscos/plotters.c
index 2b30682..25c953f 100644
--- a/frontends/riscos/plotters.c
+++ b/frontends/riscos/plotters.c
@@ -110,12 +110,17 @@ ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
os_error *error;
char buf[12];
- int clip_x0 = ro_plot_origin_x + clip->x0 * 2;
- int clip_y0 = ro_plot_origin_y - clip->y0 * 2 - 1;
- int clip_x1 = ro_plot_origin_x + clip->x1 * 2 - 1;
- int clip_y1 = ro_plot_origin_y - clip->y1 * 2;
+ int clip_x0 = clip->x0 * 2;
+ int clip_y0 = clip->y1 * 2;
+ int clip_x1 = clip->x1 * 2;
+ int clip_y1 = clip->y0 * 2;
- if (clip_x1 < clip_x0 || clip_y0 < clip_y1) {
+ clip_x0 = ro_plot_origin_x + clip_x0;
+ clip_y0 = ro_plot_origin_y - clip_y0;
+ clip_x1 = ro_plot_origin_x + clip_x1 - 1;
+ clip_y1 = ro_plot_origin_y - clip_y1 - 1;
+
+ if (clip_x1 < clip_x0 || clip_y1 < clip_y0) {
NSLOG(netsurf, INFO, "bad clip rectangle %i %i %i %i",
clip_x0, clip_y0, clip_x1, clip_y1);
return NSERROR_BAD_SIZE;
@@ -124,12 +129,12 @@ ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
buf[0] = os_VDU_SET_GRAPHICS_WINDOW;
buf[1] = clip_x0;
buf[2] = clip_x0 >> 8;
- buf[3] = clip_y1;
- buf[4] = clip_y1 >> 8;
+ buf[3] = clip_y0;
+ buf[4] = clip_y0 >> 8;
buf[5] = clip_x1;
buf[6] = clip_x1 >> 8;
- buf[7] = clip_y0;
- buf[8] = clip_y0 >> 8;
+ buf[7] = clip_y1;
+ buf[8] = clip_y1 >> 8;
error = xos_writen(buf, 9);
if (error) {
@@ -365,7 +370,7 @@ ro_plot_rectangle(const struct redraw_context *ctx,
error = xos_plot(os_MOVE_TO,
ro_plot_origin_x + rect->x0 * 2,
- ro_plot_origin_y - rect->y0 * 2 - 1);
+ ro_plot_origin_y - rect->y1 * 2);
if (error) {
NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
error->errnum, error->errmess);
@@ -374,7 +379,7 @@ ro_plot_rectangle(const struct redraw_context *ctx,
error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO,
ro_plot_origin_x + rect->x1 * 2 - 1,
- ro_plot_origin_y - rect->y1 * 2);
+ ro_plot_origin_y - rect->y0 * 2 - 1);
if (error) {
NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
error->errnum, error->errmess);
-----------------------------------------------------------------------
Summary of changes:
frontends/riscos/corewindow.c | 23 ++++++++++++++++++----
frontends/riscos/global_history.c | 3 +++
frontends/riscos/gui.h | 1 +
frontends/riscos/plotters.c | 38 +++++++++++++++++++++++++------------
frontends/riscos/window.c | 31 ++++++++++++++++++++++--------
5 files changed, 72 insertions(+), 24 deletions(-)
diff --git a/frontends/riscos/corewindow.c b/frontends/riscos/corewindow.c
index 2ef05da..88bb5c3 100644
--- a/frontends/riscos/corewindow.c
+++ b/frontends/riscos/corewindow.c
@@ -52,6 +52,8 @@
#define wimp_KEY_END wimp_KEY_COPY
#endif
+static struct ro_corewindow *ro_cw_drag_cw;
+
/**
* Update a windows scrollbars.
*
@@ -120,10 +122,15 @@ static void ro_cw_redraw(wimp_draw *redraw)
origin_x = redraw->box.x0 - redraw->xscroll;
origin_y = redraw->box.y1 + ro_cw->origin_y - redraw->yscroll;
- r.x0 = (redraw->clip.x0 - origin_x) / 2;
- r.y0 = (origin_y - redraw->clip.y1) / 2;
- r.x1 = r.x0 + ((redraw->clip.x1 - redraw->clip.x0) / 2);
- r.y1 = r.y0 + ((redraw->clip.y1 - redraw->clip.y0) / 2);
+ ro_plot_clip_rect.x0 = redraw->clip.x0 - origin_x;
+ ro_plot_clip_rect.y0 = origin_y - redraw->clip.y0;
+ ro_plot_clip_rect.x1 = redraw->clip.x1 - origin_x;
+ ro_plot_clip_rect.y1 = origin_y - redraw->clip.y1;
+
+ r.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ r.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ r.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ r.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
/* call the draw callback */
ro_cw->draw(ro_cw, origin_x, origin_y, &r);
@@ -250,6 +257,11 @@ static void ro_cw_mouse_at(wimp_pointer *pointer, void *data)
(unsigned int)pointer->w);
return;
}
+ if (ro_cw != ro_cw_drag_cw) {
+ NSLOG(netsurf, DEEPDEBUG, "Called without drag window: %p",
+ ro_cw);
+ return;
+ }
NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
/* Not a Menu click. */
@@ -386,6 +398,7 @@ ro_cw_drag_start(struct ro_corewindow *ro_cw,
ro_warn_user("WimpError", error->errmess);
}
+ ro_cw_drag_cw = ro_cw;
ro_mouse_drag_start(ro_cw_drag_end, ro_cw_mouse_at, NULL, NULL);
}
}
@@ -1041,6 +1054,8 @@ ro_corewindow_init(struct ro_corewindow *ro_cw,
}
/* setup context for event handlers */
+ NSLOG(netsurf, INFO, "Setting corewindow %p for window handle %p",
+ ro_cw, ro_cw->wh);
ro_gui_wimp_event_set_user_data(ro_cw->wh, ro_cw);
/* register wimp events. */
diff --git a/frontends/riscos/global_history.c b/frontends/riscos/global_history.c
index 4f0dbd4..51f5390 100644
--- a/frontends/riscos/global_history.c
+++ b/frontends/riscos/global_history.c
@@ -444,6 +444,9 @@ static nserror ro_global_history_init(void)
return res;
}
+ NSLOG(netsurf, INFO, "Created global history corewindow: %p",
+ &ncwin->core);
+
res = global_history_init(ncwin->core.cb_table,
(struct core_window *)ncwin);
if (res != NSERROR_OK) {
diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h
index 831c57d..5ff17e9 100644
--- a/frontends/riscos/gui.h
+++ b/frontends/riscos/gui.h
@@ -165,6 +165,7 @@ void ro_gui_print_prepare(struct gui_window *g);
extern const struct plotter_table ro_plotters;
extern int ro_plot_origin_x;
extern int ro_plot_origin_y;
+extern struct rect ro_plot_clip_rect;
/* in theme_install.c */
bool ro_gui_theme_install_apply(wimp_w w);
diff --git a/frontends/riscos/plotters.c b/frontends/riscos/plotters.c
index 2b30682..e38e746 100644
--- a/frontends/riscos/plotters.c
+++ b/frontends/riscos/plotters.c
@@ -39,6 +39,7 @@
int ro_plot_origin_x = 0;
int ro_plot_origin_y = 0;
+struct rect ro_plot_clip_rect;
/** One version of the A9home OS is incapable of drawing patterned lines */
bool ro_plot_patterned_lines = true;
@@ -110,12 +111,25 @@ ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
os_error *error;
char buf[12];
- int clip_x0 = ro_plot_origin_x + clip->x0 * 2;
- int clip_y0 = ro_plot_origin_y - clip->y0 * 2 - 1;
- int clip_x1 = ro_plot_origin_x + clip->x1 * 2 - 1;
- int clip_y1 = ro_plot_origin_y - clip->y1 * 2;
-
- if (clip_x1 < clip_x0 || clip_y0 < clip_y1) {
+ int clip_x0 = clip->x0 * 2;
+ int clip_y0 = clip->y1 * 2;
+ int clip_x1 = clip->x1 * 2;
+ int clip_y1 = clip->y0 * 2;
+
+ /* Avoid artefacts due to clip rectangle offsetting in EX0 EY0 modes.
+ * The area the WIMP asked us to draw might have dimensions that are
+ * not a multiple of 2. */
+ if (clip_x0 < ro_plot_clip_rect.x0) clip_x0 = ro_plot_clip_rect.x0;
+ if (clip_x1 > ro_plot_clip_rect.x1) clip_x1 = ro_plot_clip_rect.x1;
+ if (clip_y0 > ro_plot_clip_rect.y0) clip_y0 = ro_plot_clip_rect.y0;
+ if (clip_y1 < ro_plot_clip_rect.y1) clip_y1 = ro_plot_clip_rect.y1;
+
+ clip_x0 = ro_plot_origin_x + clip_x0;
+ clip_y0 = ro_plot_origin_y - clip_y0;
+ clip_x1 = ro_plot_origin_x + clip_x1 - 1;
+ clip_y1 = ro_plot_origin_y - clip_y1 - 1;
+
+ if (clip_x1 < clip_x0 || clip_y1 < clip_y0) {
NSLOG(netsurf, INFO, "bad clip rectangle %i %i %i %i",
clip_x0, clip_y0, clip_x1, clip_y1);
return NSERROR_BAD_SIZE;
@@ -124,12 +138,12 @@ ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
buf[0] = os_VDU_SET_GRAPHICS_WINDOW;
buf[1] = clip_x0;
buf[2] = clip_x0 >> 8;
- buf[3] = clip_y1;
- buf[4] = clip_y1 >> 8;
+ buf[3] = clip_y0;
+ buf[4] = clip_y0 >> 8;
buf[5] = clip_x1;
buf[6] = clip_x1 >> 8;
- buf[7] = clip_y0;
- buf[8] = clip_y0 >> 8;
+ buf[7] = clip_y1;
+ buf[8] = clip_y1 >> 8;
error = xos_writen(buf, 9);
if (error) {
@@ -365,7 +379,7 @@ ro_plot_rectangle(const struct redraw_context *ctx,
error = xos_plot(os_MOVE_TO,
ro_plot_origin_x + rect->x0 * 2,
- ro_plot_origin_y - rect->y0 * 2 - 1);
+ ro_plot_origin_y - rect->y1 * 2);
if (error) {
NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
error->errnum, error->errmess);
@@ -374,7 +388,7 @@ ro_plot_rectangle(const struct redraw_context *ctx,
error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO,
ro_plot_origin_x + rect->x1 * 2 - 1,
- ro_plot_origin_y - rect->y1 * 2);
+ ro_plot_origin_y - rect->y0 * 2 - 1);
if (error) {
NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
error->errnum, error->errmess);
diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c
index f1728af..2466236 100644
--- a/frontends/riscos/window.c
+++ b/frontends/riscos/window.c
@@ -1685,13 +1685,19 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
+ /* Adjust clip rect for origin. */
+ ro_plot_clip_rect.x0 = redraw->clip.x0 - ro_plot_origin_x;
+ ro_plot_clip_rect.y0 = ro_plot_origin_y - redraw->clip.y0;
+ ro_plot_clip_rect.x1 = redraw->clip.x1 - ro_plot_origin_x;
+ ro_plot_clip_rect.y1 = ro_plot_origin_y - redraw->clip.y1;
+
/* Convert OS redraw rectangle request coordinates into NetSurf
* coordinates. NetSurf coordinates have origin at top left of
* document and units are in px. */
- clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */
- clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */
- clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */
- clip.y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */
+ clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
if (ro_gui_current_redraw_gui->option.buffer_everything)
ro_gui_buffer_open(redraw);
@@ -4715,10 +4721,19 @@ void ro_gui_window_update_boxes(void)
ro_plot_origin_y = update.box.y1 - update.yscroll;
while (more) {
- clip.x0 = (update.clip.x0 - ro_plot_origin_x) / 2;
- clip.y0 = (ro_plot_origin_y - update.clip.y1) / 2;
- clip.x1 = (update.clip.x1 - ro_plot_origin_x) / 2;
- clip.y1 = (ro_plot_origin_y - update.clip.y0) / 2;
+ /* Adjust clip rect for origin. */
+ ro_plot_clip_rect.x0 = update.clip.x0 - ro_plot_origin_x;
+ ro_plot_clip_rect.y0 = ro_plot_origin_y - update.clip.y0;
+ ro_plot_clip_rect.x1 = update.clip.x1 - ro_plot_origin_x;
+ ro_plot_clip_rect.y1 = ro_plot_origin_y - update.clip.y1;
+
+ /* Convert OS redraw rectangle request coordinates into
+ * NetSurf coordinates. NetSurf coordinates have origin
+ * at top left of document and units are in px. */
+ clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
if (use_buffer)
ro_gui_buffer_open(&update);
--
NetSurf Browser
2 years, 5 months
librufl: branch master updated. release/0.0.5-1-g6edf2b6
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/6edf2b6406c830fcccf50...
...commit http://git.netsurf-browser.org/librufl.git/commit/6edf2b6406c830fcccf5061...
...tree http://git.netsurf-browser.org/librufl.git/tree/6edf2b6406c830fcccf5061c2...
The branch, master has been updated
via 6edf2b6406c830fcccf5061c2953eeba95a40741 (commit)
from b71e72bfdf6c67a07c7978f1f9c540a6d0bc4412 (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/librufl.git/commit/?id=6edf2b6406c830fcccf...
commit 6edf2b6406c830fcccf5061c2953eeba95a40741
Author: Michael Drake <michael.drake(a)codethink.co.uk>
Commit: Michael Drake <michael.drake(a)codethink.co.uk>
OSLib headers are system headers.
diff --git a/src/rufl_decompose.c b/src/rufl_decompose.c
index edf9748..2085e8f 100644
--- a/src/rufl_decompose.c
+++ b/src/rufl_decompose.c
@@ -8,7 +8,7 @@
#include <assert.h>
#include <stdio.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index d53c2dd..0868571 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -6,7 +6,7 @@
*/
#include <limits.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl.h"
#ifdef __CC_NORCROFT
#include "strfuncs.h"
diff --git a/src/rufl_invalidate_cache.c b/src/rufl_invalidate_cache.c
index 65a3897..3ec73d9 100644
--- a/src/rufl_invalidate_cache.c
+++ b/src/rufl_invalidate_cache.c
@@ -5,7 +5,7 @@
* Copyright 2005 James Bursa <james(a)semichrome.net>
*/
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c
index af4727f..468f671 100644
--- a/src/rufl_metrics.c
+++ b/src/rufl_metrics.c
@@ -9,7 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_paint.c b/src/rufl_paint.c
index 8b9edf1..b49a158 100644
--- a/src/rufl_paint.c
+++ b/src/rufl_paint.c
@@ -10,7 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_quit.c b/src/rufl_quit.c
index fc429c0..cacc9c5 100644
--- a/src/rufl_quit.c
+++ b/src/rufl_quit.c
@@ -6,7 +6,7 @@
*/
#include <stdlib.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
-----------------------------------------------------------------------
Summary of changes:
src/rufl_decompose.c | 2 +-
src/rufl_internal.h | 2 +-
src/rufl_invalidate_cache.c | 2 +-
src/rufl_metrics.c | 2 +-
src/rufl_paint.c | 2 +-
src/rufl_quit.c | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/rufl_decompose.c b/src/rufl_decompose.c
index edf9748..2085e8f 100644
--- a/src/rufl_decompose.c
+++ b/src/rufl_decompose.c
@@ -8,7 +8,7 @@
#include <assert.h>
#include <stdio.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index d53c2dd..0868571 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -6,7 +6,7 @@
*/
#include <limits.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl.h"
#ifdef __CC_NORCROFT
#include "strfuncs.h"
diff --git a/src/rufl_invalidate_cache.c b/src/rufl_invalidate_cache.c
index 65a3897..3ec73d9 100644
--- a/src/rufl_invalidate_cache.c
+++ b/src/rufl_invalidate_cache.c
@@ -5,7 +5,7 @@
* Copyright 2005 James Bursa <james(a)semichrome.net>
*/
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c
index af4727f..468f671 100644
--- a/src/rufl_metrics.c
+++ b/src/rufl_metrics.c
@@ -9,7 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_paint.c b/src/rufl_paint.c
index 8b9edf1..b49a158 100644
--- a/src/rufl_paint.c
+++ b/src/rufl_paint.c
@@ -10,7 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
diff --git a/src/rufl_quit.c b/src/rufl_quit.c
index fc429c0..cacc9c5 100644
--- a/src/rufl_quit.c
+++ b/src/rufl_quit.c
@@ -6,7 +6,7 @@
*/
#include <stdlib.h>
-#include "oslib/font.h"
+#include <oslib/font.h>
#include "rufl_internal.h"
--
RISC OS Unicode Font Library
2 years, 5 months
libnsgif: branch master updated. release/0.2.1-36-gf29bbfb
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/f29bbfbc5cbfe36a0f4f...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/f29bbfbc5cbfe36a0f4f98...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/f29bbfbc5cbfe36a0f4f98d8...
The branch, master has been updated
via f29bbfbc5cbfe36a0f4f98d84bf1f84d6e4ee1d4 (commit)
from 7253a5b36f0f07757b99895572ceac0c95022a4e (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/libnsgif.git/commit/?id=f29bbfbc5cbfe36a0f...
commit f29bbfbc5cbfe36a0f4f98d84bf1f84d6e4ee1d4
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
gif: Whitespace fixes.
Tabs for indent, spaces for alignment.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 6d78dc2..5fa9cb6 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -79,21 +79,21 @@
*/
static gif_result
gif_initialise_sprite(gif_animation *gif,
- unsigned int width,
- unsigned int height)
+ unsigned int width,
+ unsigned int height)
{
- /* Already allocated? */
- if (gif->frame_image) {
- return GIF_OK;
- }
-
- assert(gif->bitmap_callbacks.bitmap_create);
- gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
- if (gif->frame_image == NULL) {
- return GIF_INSUFFICIENT_MEMORY;
- }
-
- return GIF_OK;
+ /* Already allocated? */
+ if (gif->frame_image) {
+ return GIF_OK;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_create);
+ gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
+ if (gif->frame_image == NULL) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ return GIF_OK;
}
@@ -108,117 +108,117 @@ gif_initialise_sprite(gif_animation *gif,
static gif_result
gif_initialise_frame_extensions(gif_animation *gif, const int frame)
{
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int block_size;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
-
- /* Initialise the extensions */
- while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
- ++gif_data;
- if ((gif_bytes = (gif_end - gif_data)) < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Switch on extension label */
- switch (gif_data[0]) {
- case GIF_EXTENSION_GRAPHIC_CONTROL:
- /* 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 (gif_bytes < 6) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4] << 8);
- if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
- gif->frames[frame].transparency = true;
- gif->frames[frame].transparency_index = gif_data[5];
- }
- gif->frames[frame].disposal_method = ((gif_data[2] & GIF_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 (gif->frames[frame].disposal_method == GIF_FRAME_QUIRKS_RESTORE) {
- gif->frames[frame].disposal_method = GIF_FRAME_RESTORE;
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_APPLICATION:
- /* 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 (gif_bytes < 17) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if ((gif_data[1] == 0x0b) &&
- (strncmp((const char *) gif_data + 2,
- "NETSCAPE2.0", 11) == 0) &&
- (gif_data[13] == 0x03) &&
- (gif_data[14] == 0x01)) {
- gif->loop_count = gif_data[15] | (gif_data[16] << 8);
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_COMMENT:
- /* Move the pointer to the first data sub-block Skip 1
- * byte for the extension label
- */
- ++gif_data;
- break;
-
- default:
- /* 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 (gif_bytes < 2) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += (2 + gif_data[1]);
- }
-
- /* Repeatedly skip blocks until we get a zero block or run out
- * of data This data is ignored by this gif decoder
- */
- gif_bytes = (gif_end - gif_data);
- block_size = 0;
- while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
- block_size = gif_data[0] + 1;
- if ((gif_bytes -= block_size) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += block_size;
- }
- ++gif_data;
- }
-
- /* Set buffer position and return */
- gif->buffer_position = (gif_data - gif->gif_data);
- return GIF_OK;
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int block_size;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+
+ /* Initialise the extensions */
+ while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
+ ++gif_data;
+ if ((gif_bytes = (gif_end - gif_data)) < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Switch on extension label */
+ switch (gif_data[0]) {
+ case GIF_EXTENSION_GRAPHIC_CONTROL:
+ /* 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 (gif_bytes < 6) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4] << 8);
+ if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
+ gif->frames[frame].transparency = true;
+ gif->frames[frame].transparency_index = gif_data[5];
+ }
+ gif->frames[frame].disposal_method = ((gif_data[2] & GIF_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 (gif->frames[frame].disposal_method == GIF_FRAME_QUIRKS_RESTORE) {
+ gif->frames[frame].disposal_method = GIF_FRAME_RESTORE;
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_APPLICATION:
+ /* 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 (gif_bytes < 17) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ if ((gif_data[1] == 0x0b) &&
+ (strncmp((const char *) gif_data + 2,
+ "NETSCAPE2.0", 11) == 0) &&
+ (gif_data[13] == 0x03) &&
+ (gif_data[14] == 0x01)) {
+ gif->loop_count = gif_data[15] | (gif_data[16] << 8);
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_COMMENT:
+ /* Move the pointer to the first data sub-block Skip 1
+ * byte for the extension label
+ */
+ ++gif_data;
+ break;
+
+ default:
+ /* 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 (gif_bytes < 2) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += (2 + gif_data[1]);
+ }
+
+ /* Repeatedly skip blocks until we get a zero block or run out
+ * of data This data is ignored by this gif decoder
+ */
+ gif_bytes = (gif_end - gif_data);
+ block_size = 0;
+ while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
+ block_size = gif_data[0] + 1;
+ if ((gif_bytes -= block_size) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += block_size;
+ }
+ ++gif_data;
+ }
+
+ /* Set buffer position and return */
+ gif->buffer_position = (gif_data - gif->gif_data);
+ return GIF_OK;
}
@@ -237,231 +237,230 @@ gif_initialise_frame_extensions(gif_animation *gif, const int frame)
*/
static gif_result gif_initialise_frame(gif_animation *gif)
{
- int frame;
- gif_frame *temp_buf;
-
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int flags = 0;
- unsigned int width, height, offset_x, offset_y;
- unsigned int block_size, colour_table_size;
- bool first_image = true;
- gif_result return_value;
-
- /* Get the frame to decode and our data position */
- frame = gif->frame_count;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
- gif_bytes = (gif_end - gif_data);
-
- /* Check if we've finished */
- if ((gif_bytes > 0) && (gif_data[0] == GIF_TRAILER)) {
- return GIF_OK;
- }
-
- /* Check if there is enough data remaining. The shortest block of data
- * is a 4-byte comment extension + 1-byte block terminator + 1-byte gif
- * trailer
- */
- if (gif_bytes < 6) {
- return GIF_INSUFFICIENT_DATA;
- }
-
- /* 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 > 4096) {
- return GIF_FRAME_DATA_ERROR;
- }
-
- /* Get some memory to store our pointers in etc. */
- if ((int)gif->frame_holders <= frame) {
- /* Allocate more memory */
- temp_buf = (gif_frame *)realloc(gif->frames, (frame + 1) * sizeof(gif_frame));
- if (temp_buf == NULL) {
- return GIF_INSUFFICIENT_MEMORY;
- }
- gif->frames = temp_buf;
- gif->frame_holders = frame + 1;
- }
-
- /* Store our frame pointer. We would do it when allocating except we
- * start off with one frame allocated so we can always use realloc.
- */
- gif->frames[frame].frame_pointer = gif->buffer_position;
- gif->frames[frame].display = false;
- gif->frames[frame].virgin = true;
- gif->frames[frame].disposal_method = 0;
- gif->frames[frame].transparency = false;
- gif->frames[frame].frame_delay = 100;
- gif->frames[frame].redraw_required = false;
-
- /* Invalidate any previous decoding we have of this frame */
- if (gif->decoded_frame == frame) {
- gif->decoded_frame = GIF_INVALID_FRAME;
- }
-
- /* We pretend to initialise the frames, but really we just skip over
- * all the data contained within. This is all basically a cut down
- * version of gif_decode_frame that doesn't have any of the LZW bits in
- * it.
- */
-
- /* Initialise any extensions */
- gif->buffer_position = gif_data - gif->gif_data;
- return_value = gif_initialise_frame_extensions(gif, frame);
- if (return_value != GIF_OK) {
- return return_value;
- }
- gif_data = (gif->gif_data + gif->buffer_position);
- gif_bytes = (gif_end - gif_data);
-
- /* Check if we've finished */
- if ((gif_bytes = (gif_end - gif_data)) < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- if (gif_data[0] == GIF_TRAILER) {
- gif->buffer_position = (gif_data - gif->gif_data);
- gif->frame_count = frame + 1;
- return GIF_OK;
- }
-
- /* If we're not done, there should be an image descriptor */
- if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
- return GIF_FRAME_DATA_ERROR;
- }
-
- /* Do some simple boundary checking */
- if (gif_bytes < 10) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- offset_x = gif_data[1] | (gif_data[2] << 8);
- offset_y = gif_data[3] | (gif_data[4] << 8);
- width = gif_data[5] | (gif_data[6] << 8);
- height = gif_data[7] | (gif_data[8] << 8);
-
- /* Set up the redraw characteristics. We have to check for extending
- * the area due to multi-image frames.
- */
- if (!first_image) {
- if (gif->frames[frame].redraw_x > offset_x) {
- gif->frames[frame].redraw_width += (gif->frames[frame].redraw_x - offset_x);
- gif->frames[frame].redraw_x = offset_x;
- }
-
- if (gif->frames[frame].redraw_y > offset_y) {
- gif->frames[frame].redraw_height += (gif->frames[frame].redraw_y - offset_y);
- gif->frames[frame].redraw_y = offset_y;
- }
-
- if ((offset_x + width) > (gif->frames[frame].redraw_x + gif->frames[frame].redraw_width)) {
- gif->frames[frame].redraw_width = (offset_x + width) - gif->frames[frame].redraw_x;
- }
-
- if ((offset_y + height) > (gif->frames[frame].redraw_y + gif->frames[frame].redraw_height)) {
- gif->frames[frame].redraw_height = (offset_y + height) - gif->frames[frame].redraw_y;
- }
- } else {
- first_image = false;
- gif->frames[frame].redraw_x = offset_x;
- gif->frames[frame].redraw_y = offset_y;
- gif->frames[frame].redraw_width = width;
- gif->frames[frame].redraw_height = height;
- }
-
- /* if we are clearing the background then we need to redraw enough to
- * cover the previous frame too
- */
- gif->frames[frame].redraw_required = ((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
- (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
-
- /* Frame size may have grown.
- */
- gif->width = (offset_x + width > gif->width) ?
- offset_x + width : gif->width;
- gif->height = (offset_y + height > gif->height) ?
- offset_y + height : gif->height;
-
- /* Decode the flags */
- flags = gif_data[9];
- colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
-
- /* Move our data onwards and remember we've got a bit of this frame */
- gif_data += 10;
- gif_bytes = (gif_end - gif_data);
- gif->frame_count_partial = frame + 1;
-
- /* Skip the local colour table */
- if (flags & GIF_COLOUR_TABLE_MASK) {
- gif_data += 3 * colour_table_size;
- if ((gif_bytes = (gif_end - gif_data)) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- }
-
- /* Ensure we have a correct code size */
- if (gif_bytes < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if (gif_data[0] >= LZW_CODE_MAX) {
- return GIF_DATA_ERROR;
- }
-
- /* Move our pointer to the actual image data */
- gif_data++;
- --gif_bytes;
-
- /* Repeatedly skip blocks until we get a zero block or run out of data
- * These blocks of image data are processed later by gif_decode_frame()
- */
- block_size = 0;
- while (block_size != 1) {
- if (gif_bytes < 1) return GIF_INSUFFICIENT_FRAME_DATA;
- block_size = gif_data[0] + 1;
- /* Check if the frame data runs off the end of the file */
- if ((int)(gif_bytes - block_size) < 0) {
- /* Try to recover by signaling the end of the gif.
- * Once we get garbage data, there is no logical way to
- * determine where the next frame is. It's probably
- * better to partially load the gif than not at all.
- */
- if (gif_bytes >= 2) {
- gif_data[0] = 0;
- gif_data[1] = GIF_TRAILER;
- gif_bytes = 1;
- ++gif_data;
- break;
- } else {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- } else {
- gif_bytes -= block_size;
- gif_data += block_size;
- }
- }
-
- /* Add the frame and set the display flag */
- gif->buffer_position = gif_data - gif->gif_data;
- gif->frame_count = frame + 1;
- gif->frames[frame].display = true;
-
- /* Check if we've finished */
- if (gif_bytes < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- } else {
- if (gif_data[0] == GIF_TRAILER) {
- return GIF_OK;
- }
- }
- return GIF_WORKING;
+ int frame;
+ gif_frame *temp_buf;
+
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int flags = 0;
+ unsigned int width, height, offset_x, offset_y;
+ unsigned int block_size, colour_table_size;
+ bool first_image = true;
+ gif_result return_value;
+
+ /* Get the frame to decode and our data position */
+ frame = gif->frame_count;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Check if we've finished */
+ if ((gif_bytes > 0) && (gif_data[0] == GIF_TRAILER)) {
+ return GIF_OK;
+ }
+
+ /* Check if there is enough data remaining. The shortest block of data
+ * is a 4-byte comment extension + 1-byte block terminator + 1-byte gif
+ * trailer
+ */
+ if (gif_bytes < 6) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+
+ /* 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 > 4096) {
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ /* Get some memory to store our pointers in etc. */
+ if ((int)gif->frame_holders <= frame) {
+ /* Allocate more memory */
+ temp_buf = (gif_frame *)realloc(gif->frames, (frame + 1) * sizeof(gif_frame));
+ if (temp_buf == NULL) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+ gif->frames = temp_buf;
+ gif->frame_holders = frame + 1;
+ }
+
+ /* Store our frame pointer. We would do it when allocating except we
+ * start off with one frame allocated so we can always use realloc.
+ */
+ gif->frames[frame].frame_pointer = gif->buffer_position;
+ gif->frames[frame].display = false;
+ gif->frames[frame].virgin = true;
+ gif->frames[frame].disposal_method = 0;
+ gif->frames[frame].transparency = false;
+ gif->frames[frame].frame_delay = 100;
+ gif->frames[frame].redraw_required = false;
+
+ /* Invalidate any previous decoding we have of this frame */
+ if (gif->decoded_frame == frame) {
+ gif->decoded_frame = GIF_INVALID_FRAME;
+ }
+
+ /* We pretend to initialise the frames, but really we just skip over
+ * all the data contained within. This is all basically a cut down
+ * version of gif_decode_frame that doesn't have any of the LZW bits in
+ * it.
+ */
+
+ /* Initialise any extensions */
+ gif->buffer_position = gif_data - gif->gif_data;
+ return_value = gif_initialise_frame_extensions(gif, frame);
+ if (return_value != GIF_OK) {
+ return return_value;
+ }
+ gif_data = (gif->gif_data + gif->buffer_position);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Check if we've finished */
+ if ((gif_bytes = (gif_end - gif_data)) < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ if (gif_data[0] == GIF_TRAILER) {
+ gif->buffer_position = (gif_data - gif->gif_data);
+ gif->frame_count = frame + 1;
+ return GIF_OK;
+ }
+
+ /* If we're not done, there should be an image descriptor */
+ if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ /* Do some simple boundary checking */
+ if (gif_bytes < 10) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ offset_x = gif_data[1] | (gif_data[2] << 8);
+ offset_y = gif_data[3] | (gif_data[4] << 8);
+ width = gif_data[5] | (gif_data[6] << 8);
+ height = gif_data[7] | (gif_data[8] << 8);
+
+ /* Set up the redraw characteristics. We have to check for extending
+ * the area due to multi-image frames.
+ */
+ if (!first_image) {
+ if (gif->frames[frame].redraw_x > offset_x) {
+ gif->frames[frame].redraw_width += (gif->frames[frame].redraw_x - offset_x);
+ gif->frames[frame].redraw_x = offset_x;
+ }
+
+ if (gif->frames[frame].redraw_y > offset_y) {
+ gif->frames[frame].redraw_height += (gif->frames[frame].redraw_y - offset_y);
+ gif->frames[frame].redraw_y = offset_y;
+ }
+
+ if ((offset_x + width) > (gif->frames[frame].redraw_x + gif->frames[frame].redraw_width)) {
+ gif->frames[frame].redraw_width = (offset_x + width) - gif->frames[frame].redraw_x;
+ }
+
+ if ((offset_y + height) > (gif->frames[frame].redraw_y + gif->frames[frame].redraw_height)) {
+ gif->frames[frame].redraw_height = (offset_y + height) - gif->frames[frame].redraw_y;
+ }
+ } else {
+ first_image = false;
+ gif->frames[frame].redraw_x = offset_x;
+ gif->frames[frame].redraw_y = offset_y;
+ gif->frames[frame].redraw_width = width;
+ gif->frames[frame].redraw_height = height;
+ }
+
+ /* if we are clearing the background then we need to redraw enough to
+ * cover the previous frame too
+ */
+ gif->frames[frame].redraw_required =
+ ((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
+ (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
+
+ /* Frame size may have grown.
+ */
+ gif->width = (offset_x + width > gif->width) ?
+ offset_x + width : gif->width;
+ gif->height = (offset_y + height > gif->height) ?
+ offset_y + height : gif->height;
+
+ /* Decode the flags */
+ flags = gif_data[9];
+ colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
+
+ /* Move our data onwards and remember we've got a bit of this frame */
+ gif_data += 10;
+ gif_bytes = (gif_end - gif_data);
+ gif->frame_count_partial = frame + 1;
+
+ /* Skip the local colour table */
+ if (flags & GIF_COLOUR_TABLE_MASK) {
+ gif_data += 3 * colour_table_size;
+ if ((gif_bytes = (gif_end - gif_data)) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ }
+
+ /* Ensure we have a correct code size */
+ if (gif_bytes < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ if (gif_data[0] >= LZW_CODE_MAX) {
+ return GIF_DATA_ERROR;
+ }
+
+ /* Move our pointer to the actual image data */
+ gif_data++;
+ --gif_bytes;
+
+ /* Repeatedly skip blocks until we get a zero block or run out of data
+ * These blocks of image data are processed later by gif_decode_frame()
+ */
+ block_size = 0;
+ while (block_size != 1) {
+ if (gif_bytes < 1) return GIF_INSUFFICIENT_FRAME_DATA;
+ block_size = gif_data[0] + 1;
+ /* Check if the frame data runs off the end of the file */
+ if ((int)(gif_bytes - block_size) < 0) {
+ /* Try to recover by signaling the end of the gif.
+ * Once we get garbage data, there is no logical way to
+ * determine where the next frame is. It's probably
+ * better to partially load the gif than not at all.
+ */
+ if (gif_bytes >= 2) {
+ gif_data[0] = 0;
+ gif_data[1] = GIF_TRAILER;
+ gif_bytes = 1;
+ ++gif_data;
+ break;
+ } else {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ } else {
+ gif_bytes -= block_size;
+ gif_data += block_size;
+ }
+ }
+
+ /* Add the frame and set the display flag */
+ gif->buffer_position = gif_data - gif->gif_data;
+ gif->frame_count = frame + 1;
+ gif->frames[frame].display = true;
+
+ /* Check if we've finished */
+ if (gif_bytes < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ } else {
+ if (gif_data[0] == GIF_TRAILER) {
+ return GIF_OK;
+ }
+ }
+ return GIF_WORKING;
}
-
-
/**
* Skips the frame's extensions (which have been previously initialised)
*
@@ -471,313 +470,313 @@ static gif_result gif_initialise_frame(gif_animation *gif)
*/
static gif_result gif_skip_frame_extensions(gif_animation *gif)
{
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int block_size;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
- gif_bytes = (gif_end - gif_data);
-
- /* Skip the extensions */
- while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
- ++gif_data;
- if (gif_data >= gif_end) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Switch on extension label */
- switch(gif_data[0]) {
- case GIF_EXTENSION_COMMENT:
- /* Move the pointer to the first data sub-block
- * 1 byte for the extension label
- */
- ++gif_data;
- break;
-
- default:
- /* Move the pointer to the first data sub-block 2 bytes
- * for the extension label and size fields Skip the
- * extension size itself
- */
- if (gif_data + 1 >= gif_end) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += (2 + gif_data[1]);
- }
-
- /* Repeatedly skip blocks until we get a zero block or run out
- * of data This data is ignored by this gif decoder
- */
- gif_bytes = (gif_end - gif_data);
- block_size = 0;
- while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
- block_size = gif_data[0] + 1;
- if ((gif_bytes -= block_size) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += block_size;
- }
- ++gif_data;
- }
-
- /* Set buffer position and return */
- gif->buffer_position = (gif_data - gif->gif_data);
- return GIF_OK;
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int block_size;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Skip the extensions */
+ while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
+ ++gif_data;
+ if (gif_data >= gif_end) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Switch on extension label */
+ switch(gif_data[0]) {
+ case GIF_EXTENSION_COMMENT:
+ /* Move the pointer to the first data sub-block
+ * 1 byte for the extension label
+ */
+ ++gif_data;
+ break;
+
+ default:
+ /* Move the pointer to the first data sub-block 2 bytes
+ * for the extension label and size fields Skip the
+ * extension size itself
+ */
+ if (gif_data + 1 >= gif_end) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += (2 + gif_data[1]);
+ }
+
+ /* Repeatedly skip blocks until we get a zero block or run out
+ * of data This data is ignored by this gif decoder
+ */
+ gif_bytes = (gif_end - gif_data);
+ block_size = 0;
+ while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
+ block_size = gif_data[0] + 1;
+ if ((gif_bytes -= block_size) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += block_size;
+ }
+ ++gif_data;
+ }
+
+ /* Set buffer position and return */
+ gif->buffer_position = (gif_data - gif->gif_data);
+ return GIF_OK;
}
static unsigned int gif_interlaced_line(int height, int y) {
- if ((y << 3) < height) {
- return (y << 3);
- }
- y -= ((height + 7) >> 3);
- if ((y << 3) < (height - 4)) {
- return (y << 3) + 4;
- }
- y -= ((height + 3) >> 3);
- if ((y << 2) < (height - 2)) {
- return (y << 2) + 2;
- }
- y -= ((height + 1) >> 2);
- return (y << 1) + 1;
+ if ((y << 3) < height) {
+ return (y << 3);
+ }
+ y -= ((height + 7) >> 3);
+ if ((y << 3) < (height - 4)) {
+ return (y << 3) + 4;
+ }
+ y -= ((height + 3) >> 3);
+ if ((y << 2) < (height - 2)) {
+ return (y << 2) + 2;
+ }
+ y -= ((height + 1) >> 2);
+ return (y << 1) + 1;
}
static gif_result gif_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_FRAME_DATA,
- [LZW_EOI_CODE] = GIF_FRAME_DATA_ERROR,
- [LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
- [LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
- };
- return g_res[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_FRAME_DATA,
+ [LZW_EOI_CODE] = GIF_FRAME_DATA_ERROR,
+ [LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
+ [LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
+ };
+ return g_res[l_res];
}
static void gif__record_previous_frame(gif_animation *gif)
{
- bool need_alloc = gif->prev_frame == NULL;
- const uint32_t *frame_data;
- uint32_t *prev_frame;
-
- if (gif->decoded_frame == GIF_INVALID_FRAME ||
- gif->decoded_frame == gif->prev_index) {
- /* No frame to copy, or already have this frame recorded. */
- return;
- }
-
- assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- 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, frame_data, 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;
+ bool need_alloc = gif->prev_frame == NULL;
+ const uint32_t *frame_data;
+ uint32_t *prev_frame;
+
+ if (gif->decoded_frame == GIF_INVALID_FRAME ||
+ gif->decoded_frame == gif->prev_index) {
+ /* No frame to copy, or already have this frame recorded. */
+ return;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ 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, frame_data, 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 gif_result gif__recover_previous_frame(const gif_animation *gif)
{
- 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;
- uint32_t *frame_data;
+ 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;
+ uint32_t *frame_data;
- if (prev_frame == NULL) {
- return GIF_FRAME_DATA_ERROR;
- }
+ if (prev_frame == NULL) {
+ return GIF_FRAME_DATA_ERROR;
+ }
- assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- return GIF_INSUFFICIENT_MEMORY;
- }
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
- for (unsigned y = 0; y < height; y++) {
- memcpy(frame_data, prev_frame, width * 4);
+ for (unsigned y = 0; y < height; y++) {
+ memcpy(frame_data, prev_frame, width * 4);
- frame_data += gif->width;
- prev_frame += gif->prev_width;
- }
+ frame_data += gif->width;
+ prev_frame += gif->prev_width;
+ }
- return GIF_OK;
+ return GIF_OK;
}
static gif_result
gif__decode_complex(gif_animation *gif,
- unsigned int frame,
- unsigned int width,
- unsigned int height,
- unsigned int offset_x,
- unsigned int offset_y,
- unsigned int interlace,
- uint8_t minimum_code_size,
- unsigned int *restrict frame_data,
- unsigned int *restrict colour_table)
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
{
- unsigned int transparency_index;
- uint32_t available = 0;
- gif_result ret = GIF_OK;
- lzw_result res;
-
- /* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
-
- transparency_index = gif->frames[frame].transparency ?
- gif->frames[frame].transparency_index :
- GIF_NO_TRANSPARENCY;
-
- for (unsigned int y = 0; y < height; y++) {
- unsigned int x;
- unsigned int decode_y;
- unsigned int *frame_scanline;
-
- if (interlace) {
- decode_y = gif_interlaced_line(height, y) + offset_y;
- } else {
- decode_y = y + offset_y;
- }
- frame_scanline = frame_data + offset_x + (decode_y * gif->width);
-
- 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 = GIF_OK;
- } else {
- ret = gif_error_from_lzw(res);
- }
- break;
- }
- res = lzw_decode_continuous(gif->lzw_ctx,
- &uncompressed, &available);
- }
-
- row_available = x < available ? x : available;
- x -= row_available;
- available -= row_available;
- while (row_available-- > 0) {
- register unsigned int colour;
- colour = *uncompressed++;
- if (colour != transparency_index) {
- *frame_scanline = colour_table[colour];
- }
- frame_scanline++;
- }
- }
- }
- return ret;
+ unsigned int transparency_index;
+ uint32_t available = 0;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
+ for (unsigned int y = 0; y < height; y++) {
+ unsigned int x;
+ unsigned int decode_y;
+ unsigned int *frame_scanline;
+
+ if (interlace) {
+ decode_y = gif_interlaced_line(height, y) + offset_y;
+ } else {
+ decode_y = y + offset_y;
+ }
+ frame_scanline = frame_data + offset_x + (decode_y * gif->width);
+
+ 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 = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ res = lzw_decode_continuous(gif->lzw_ctx,
+ &uncompressed, &available);
+ }
+
+ row_available = x < available ? x : available;
+ x -= row_available;
+ available -= row_available;
+ while (row_available-- > 0) {
+ register unsigned int colour;
+ colour = *uncompressed++;
+ if (colour != transparency_index) {
+ *frame_scanline = colour_table[colour];
+ }
+ frame_scanline++;
+ }
+ }
+ }
+ return ret;
}
static gif_result
gif__decode_simple(gif_animation *gif,
- unsigned int frame,
- unsigned int height,
- unsigned int offset_y,
- uint8_t minimum_code_size,
- unsigned int *restrict frame_data,
- unsigned int *restrict colour_table)
+ unsigned int frame,
+ unsigned int height,
+ unsigned int offset_y,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
{
- unsigned int transparency_index;
- uint32_t pixels = gif->width * height;
- uint32_t written = 0;
- gif_result ret = GIF_OK;
- lzw_result res;
-
- /* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
-
- transparency_index = gif->frames[frame].transparency ?
- gif->frames[frame].transparency_index :
- GIF_NO_TRANSPARENCY;
-
- frame_data += (offset_y * gif->width);
-
- while (pixels > 0) {
- res = lzw_decode_map_continuous(gif->lzw_ctx,
- transparency_index, colour_table,
- frame_data, pixels, &written);
- pixels -= written;
- frame_data += written;
- if (res != LZW_OK) {
- /* Unexpected end of frame, try to recover */
- if (res == LZW_OK_EOD) {
- ret = GIF_OK;
- } else {
- ret = gif_error_from_lzw(res);
- }
- break;
- }
- }
-
- if (pixels == 0) {
- ret = GIF_OK;
- }
-
- return ret;
+ unsigned int transparency_index;
+ uint32_t pixels = gif->width * height;
+ uint32_t written = 0;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
+ frame_data += (offset_y * gif->width);
+
+ while (pixels > 0) {
+ res = lzw_decode_map_continuous(gif->lzw_ctx,
+ transparency_index, colour_table,
+ frame_data, pixels, &written);
+ pixels -= written;
+ frame_data += written;
+ if (res != LZW_OK) {
+ /* Unexpected end of frame, try to recover */
+ if (res == LZW_OK_EOD) {
+ ret = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ }
+
+ if (pixels == 0) {
+ ret = GIF_OK;
+ }
+
+ return ret;
}
static inline gif_result
gif__decode(gif_animation *gif,
- unsigned int frame,
- unsigned int width,
- unsigned int height,
- unsigned int offset_x,
- unsigned int offset_y,
- unsigned int interlace,
- uint8_t minimum_code_size,
- unsigned int *restrict frame_data,
- unsigned int *restrict colour_table)
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
{
- gif_result ret;
-
- if (interlace == false && width == gif->width && offset_x == 0) {
- ret = gif__decode_simple(gif, frame, height, offset_y,
- minimum_code_size, frame_data, colour_table);
- } else {
- ret = gif__decode_complex(gif, frame, width, height,
- offset_x, offset_y, interlace,
- minimum_code_size, frame_data, colour_table);
- }
-
- return ret;
+ gif_result ret;
+
+ if (interlace == false && width == gif->width && offset_x == 0) {
+ ret = gif__decode_simple(gif, frame, height, offset_y,
+ minimum_code_size, frame_data, colour_table);
+ } else {
+ ret = gif__decode_complex(gif, frame, width, height,
+ offset_x, offset_y, interlace,
+ minimum_code_size, frame_data, colour_table);
+ }
+
+ return ret;
}
/**
@@ -789,527 +788,527 @@ gif__decode(gif_animation *gif,
*/
static gif_result
gif_internal_decode_frame(gif_animation *gif,
- unsigned int frame,
- bool clear_image)
+ unsigned int frame,
+ bool clear_image)
{
- gif_result err;
- unsigned int index = 0;
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int width, height, offset_x, offset_y;
- unsigned int flags, colour_table_size, interlace;
- unsigned int *colour_table;
- unsigned int *frame_data = 0; // Set to 0 for no warnings
- unsigned int save_buffer_position;
- unsigned int return_value = 0;
-
- /* Ensure this frame is supposed to be decoded */
- if (gif->frames[frame].display == false) {
- return GIF_OK;
- }
-
- /* Ensure the frame is in range to decode */
- if (frame > gif->frame_count_partial) {
- return GIF_INSUFFICIENT_DATA;
- }
-
- /* done if frame is already decoded */
- if ((!clear_image) &&
- ((int)frame == gif->decoded_frame)) {
- return GIF_OK;
- }
-
- /* Get the start of our frame data and the end of the GIF data */
- gif_data = gif->gif_data + gif->frames[frame].frame_pointer;
- gif_end = gif->gif_data + gif->buffer_size;
- gif_bytes = (gif_end - gif_data);
-
- /*
- * Ensure there is a minimal amount of data to proceed. The shortest
- * block of data is a 10-byte image descriptor + 1-byte gif trailer
- */
- if (gif_bytes < 12) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Save the buffer position */
- save_buffer_position = gif->buffer_position;
- gif->buffer_position = gif_data - gif->gif_data;
-
- /* Skip any extensions because they have allready been processed */
- if ((return_value = gif_skip_frame_extensions(gif)) != GIF_OK) {
- goto gif_decode_frame_exit;
- }
- gif_data = (gif->gif_data + gif->buffer_position);
- gif_bytes = (gif_end - gif_data);
-
- /* Ensure we have enough data for the 10-byte image descriptor + 1-byte
- * gif trailer
- */
- if (gif_bytes < 12) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
-
- /* 10-byte Image Descriptor 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
- */
- if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
- return_value = GIF_DATA_ERROR;
- goto gif_decode_frame_exit;
- }
- offset_x = gif_data[1] | (gif_data[2] << 8);
- offset_y = gif_data[3] | (gif_data[4] << 8);
- width = gif_data[5] | (gif_data[6] << 8);
- height = gif_data[7] | (gif_data[8] << 8);
-
- /* Boundary checking - shouldn't ever happen except unless the data has
- * been modified since initialisation.
- */
- if ((offset_x + width > gif->width) ||
- (offset_y + height > gif->height)) {
- return_value = GIF_DATA_ERROR;
- goto gif_decode_frame_exit;
- }
-
- /* Make sure we have a buffer to decode to.
- */
- if (gif_initialise_sprite(gif, gif->width, gif->height)) {
- return GIF_INSUFFICIENT_MEMORY;
- }
-
- /* Decode the flags */
- flags = gif_data[9];
- colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
- interlace = flags & GIF_INTERLACE_MASK;
-
- /* Advance data pointer to next block either colour table or image
- * data.
- */
- gif_data += 10;
- gif_bytes = (gif_end - gif_data);
-
- /* Set up the colour table */
- if (flags & GIF_COLOUR_TABLE_MASK) {
- if (gif_bytes < (int)(3 * colour_table_size)) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
- colour_table = gif->local_colour_table;
- if (!clear_image) {
- for (index = 0; index < colour_table_size; index++) {
- /* 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.
- */
- unsigned char *entry =
- (unsigned char *) &colour_table[index];
-
- entry[0] = gif_data[0]; /* r */
- entry[1] = gif_data[1]; /* g */
- entry[2] = gif_data[2]; /* b */
- entry[3] = 0xff; /* a */
-
- gif_data += 3;
- }
- } else {
- gif_data += 3 * colour_table_size;
- }
- gif_bytes = (gif_end - gif_data);
- } else {
- colour_table = gif->global_colour_table;
- }
-
- /* Ensure sufficient data remains */
- if (gif_bytes < 1) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
-
- /* check for an end marker */
- if (gif_data[0] == GIF_TRAILER) {
- return_value = GIF_OK;
- goto gif_decode_frame_exit;
- }
-
- /* Get the frame data */
- assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- return GIF_INSUFFICIENT_MEMORY;
- }
-
- /* If we are clearing the image we just clear, if not decode */
- if (!clear_image) {
- /* Ensure we have enough data for a 1-byte LZW code size +
- * 1-byte gif trailer
- */
- if (gif_bytes < 2) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
-
- /* If we only have a 1-byte LZW code size + 1-byte gif trailer,
- * we're finished
- */
- if ((gif_bytes == 2) && (gif_data[1] == GIF_TRAILER)) {
- return_value = GIF_OK;
- goto gif_decode_frame_exit;
- }
-
- /* If the previous frame's disposal method requires we restore
- * the background colour or this is the first frame, clear
- * the frame data
- */
- if ((frame == 0) || (gif->decoded_frame == GIF_INVALID_FRAME)) {
- memset((char*)frame_data,
- GIF_TRANSPARENT_COLOUR,
- gif->width * gif->height * sizeof(int));
- gif->decoded_frame = frame;
- /* The line below would fill the image with its
- * background color, but because GIFs support
- * transparency we likely wouldn't want to do that. */
- /* memset((char*)frame_data, colour_table[gif->background_index], gif->width * gif->height * sizeof(int)); */
- } else if ((frame != 0) &&
- (gif->frames[frame - 1].disposal_method == GIF_FRAME_CLEAR)) {
- return_value = gif_internal_decode_frame(gif,
- (frame - 1),
- true);
- if (return_value != GIF_OK) {
- goto gif_decode_frame_exit;
- }
-
- } else if ((frame != 0) &&
- (gif->frames[frame - 1].disposal_method == GIF_FRAME_RESTORE)) {
- /*
- * If the previous frame's disposal method requires we
- * restore the previous image, restore our saved image.
- */
- err = gif__recover_previous_frame(gif);
- if (err != GIF_OK) {
- /* see notes above on transparency
- * vs. background color
- */
- memset((char*)frame_data,
- GIF_TRANSPARENT_COLOUR,
- gif->width * gif->height * sizeof(int));
- }
- }
-
- if (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE) {
- /* Store the previous frame for later restoration */
- gif__record_previous_frame(gif);
- }
-
- gif->decoded_frame = frame;
- gif->buffer_position = (gif_data - gif->gif_data) + 1;
-
- return_value = gif__decode(gif, frame, width, height,
- offset_x, offset_y, interlace, gif_data[0],
- frame_data, colour_table);
- } else {
- /* Clear our frame */
- if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) {
- unsigned int y;
- for (y = 0; y < height; y++) {
- unsigned int *frame_scanline;
- frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width);
- if (gif->frames[frame].transparency) {
- memset(frame_scanline,
- GIF_TRANSPARENT_COLOUR,
- width * 4);
- } else {
- memset(frame_scanline,
- colour_table[gif->background_index],
- width * 4);
- }
- }
- }
- }
+ gif_result err;
+ unsigned int index = 0;
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int width, height, offset_x, offset_y;
+ unsigned int flags, colour_table_size, interlace;
+ unsigned int *colour_table;
+ unsigned int *frame_data = 0; // Set to 0 for no warnings
+ unsigned int save_buffer_position;
+ unsigned int return_value = 0;
+
+ /* Ensure this frame is supposed to be decoded */
+ if (gif->frames[frame].display == false) {
+ return GIF_OK;
+ }
+
+ /* Ensure the frame is in range to decode */
+ if (frame > gif->frame_count_partial) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+
+ /* done if frame is already decoded */
+ if ((!clear_image) &&
+ ((int)frame == gif->decoded_frame)) {
+ return GIF_OK;
+ }
+
+ /* Get the start of our frame data and the end of the GIF data */
+ gif_data = gif->gif_data + gif->frames[frame].frame_pointer;
+ gif_end = gif->gif_data + gif->buffer_size;
+ gif_bytes = (gif_end - gif_data);
+
+ /*
+ * Ensure there is a minimal amount of data to proceed. The shortest
+ * block of data is a 10-byte image descriptor + 1-byte gif trailer
+ */
+ if (gif_bytes < 12) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Save the buffer position */
+ save_buffer_position = gif->buffer_position;
+ gif->buffer_position = gif_data - gif->gif_data;
+
+ /* Skip any extensions because they have already been processed */
+ if ((return_value = gif_skip_frame_extensions(gif)) != GIF_OK) {
+ goto gif_decode_frame_exit;
+ }
+ gif_data = (gif->gif_data + gif->buffer_position);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Ensure we have enough data for the 10-byte image descriptor + 1-byte
+ * gif trailer
+ */
+ if (gif_bytes < 12) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+
+ /* 10-byte Image Descriptor 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
+ */
+ if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
+ return_value = GIF_DATA_ERROR;
+ goto gif_decode_frame_exit;
+ }
+ offset_x = gif_data[1] | (gif_data[2] << 8);
+ offset_y = gif_data[3] | (gif_data[4] << 8);
+ width = gif_data[5] | (gif_data[6] << 8);
+ height = gif_data[7] | (gif_data[8] << 8);
+
+ /* Boundary checking - shouldn't ever happen except unless the data has
+ * been modified since initialisation.
+ */
+ if ((offset_x + width > gif->width) ||
+ (offset_y + height > gif->height)) {
+ return_value = GIF_DATA_ERROR;
+ goto gif_decode_frame_exit;
+ }
+
+ /* Make sure we have a buffer to decode to.
+ */
+ if (gif_initialise_sprite(gif, gif->width, gif->height)) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ /* Decode the flags */
+ flags = gif_data[9];
+ colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
+ interlace = flags & GIF_INTERLACE_MASK;
+
+ /* Advance data pointer to next block either colour table or image
+ * data.
+ */
+ gif_data += 10;
+ gif_bytes = (gif_end - gif_data);
+
+ /* Set up the colour table */
+ if (flags & GIF_COLOUR_TABLE_MASK) {
+ if (gif_bytes < (int)(3 * colour_table_size)) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+ colour_table = gif->local_colour_table;
+ if (!clear_image) {
+ for (index = 0; index < colour_table_size; index++) {
+ /* 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.
+ */
+ unsigned char *entry =
+ (unsigned char *) &colour_table[index];
+
+ entry[0] = gif_data[0]; /* r */
+ entry[1] = gif_data[1]; /* g */
+ entry[2] = gif_data[2]; /* b */
+ entry[3] = 0xff; /* a */
+
+ gif_data += 3;
+ }
+ } else {
+ gif_data += 3 * colour_table_size;
+ }
+ gif_bytes = (gif_end - gif_data);
+ } else {
+ colour_table = gif->global_colour_table;
+ }
+
+ /* Ensure sufficient data remains */
+ if (gif_bytes < 1) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+
+ /* check for an end marker */
+ if (gif_data[0] == GIF_TRAILER) {
+ return_value = GIF_OK;
+ goto gif_decode_frame_exit;
+ }
+
+ /* Get the frame data */
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ /* If we are clearing the image we just clear, if not decode */
+ if (!clear_image) {
+ /* Ensure we have enough data for a 1-byte LZW code size +
+ * 1-byte gif trailer
+ */
+ if (gif_bytes < 2) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+
+ /* If we only have a 1-byte LZW code size + 1-byte gif trailer,
+ * we're finished
+ */
+ if ((gif_bytes == 2) && (gif_data[1] == GIF_TRAILER)) {
+ return_value = GIF_OK;
+ goto gif_decode_frame_exit;
+ }
+
+ /* If the previous frame's disposal method requires we restore
+ * the background colour or this is the first frame, clear
+ * the frame data
+ */
+ if ((frame == 0) || (gif->decoded_frame == GIF_INVALID_FRAME)) {
+ memset((char*)frame_data,
+ GIF_TRANSPARENT_COLOUR,
+ gif->width * gif->height * sizeof(int));
+ gif->decoded_frame = frame;
+ /* The line below would fill the image with its
+ * background color, but because GIFs support
+ * transparency we likely wouldn't want to do that. */
+ /* memset((char*)frame_data, colour_table[gif->background_index], gif->width * gif->height * sizeof(int)); */
+ } else if ((frame != 0) &&
+ (gif->frames[frame - 1].disposal_method == GIF_FRAME_CLEAR)) {
+ return_value = gif_internal_decode_frame(gif,
+ (frame - 1),
+ true);
+ if (return_value != GIF_OK) {
+ goto gif_decode_frame_exit;
+ }
+
+ } else if ((frame != 0) &&
+ (gif->frames[frame - 1].disposal_method == GIF_FRAME_RESTORE)) {
+ /*
+ * If the previous frame's disposal method requires we
+ * restore the previous image, restore our saved image.
+ */
+ err = gif__recover_previous_frame(gif);
+ if (err != GIF_OK) {
+ /* see notes above on transparency
+ * vs. background color
+ */
+ memset((char*)frame_data,
+ GIF_TRANSPARENT_COLOUR,
+ gif->width * gif->height * sizeof(int));
+ }
+ }
+
+ if (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE) {
+ /* Store the previous frame for later restoration */
+ gif__record_previous_frame(gif);
+ }
+
+ gif->decoded_frame = frame;
+ gif->buffer_position = (gif_data - gif->gif_data) + 1;
+
+ return_value = gif__decode(gif, frame, width, height,
+ offset_x, offset_y, interlace, gif_data[0],
+ frame_data, colour_table);
+ } else {
+ /* Clear our frame */
+ if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) {
+ unsigned int y;
+ for (y = 0; y < height; y++) {
+ unsigned int *frame_scanline;
+ frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width);
+ if (gif->frames[frame].transparency) {
+ memset(frame_scanline,
+ GIF_TRANSPARENT_COLOUR,
+ width * 4);
+ } else {
+ memset(frame_scanline,
+ colour_table[gif->background_index],
+ width * 4);
+ }
+ }
+ }
+ }
gif_decode_frame_exit:
- /* Check if we should test for optimisation */
- if (gif->frames[frame].virgin) {
- if (gif->bitmap_callbacks.bitmap_test_opaque) {
- gif->frames[frame].opaque = gif->bitmap_callbacks.bitmap_test_opaque(gif->frame_image);
- } else {
- gif->frames[frame].opaque = false;
- }
- gif->frames[frame].virgin = false;
- }
+ /* Check if we should test for optimisation */
+ if (gif->frames[frame].virgin) {
+ if (gif->bitmap_callbacks.bitmap_test_opaque) {
+ gif->frames[frame].opaque = gif->bitmap_callbacks.bitmap_test_opaque(gif->frame_image);
+ } else {
+ gif->frames[frame].opaque = false;
+ }
+ gif->frames[frame].virgin = false;
+ }
- if (gif->bitmap_callbacks.bitmap_set_opaque) {
- gif->bitmap_callbacks.bitmap_set_opaque(gif->frame_image, gif->frames[frame].opaque);
- }
+ if (gif->bitmap_callbacks.bitmap_set_opaque) {
+ gif->bitmap_callbacks.bitmap_set_opaque(gif->frame_image, gif->frames[frame].opaque);
+ }
- if (gif->bitmap_callbacks.bitmap_modified) {
- gif->bitmap_callbacks.bitmap_modified(gif->frame_image);
- }
+ if (gif->bitmap_callbacks.bitmap_modified) {
+ gif->bitmap_callbacks.bitmap_modified(gif->frame_image);
+ }
- /* Restore the buffer position */
- gif->buffer_position = save_buffer_position;
+ /* Restore the buffer position */
+ gif->buffer_position = save_buffer_position;
- return return_value;
+ return return_value;
}
/* exported function documented in libnsgif.h */
void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks)
{
- 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(gif_animation));
+ gif->bitmap_callbacks = *bitmap_callbacks;
+ gif->decoded_frame = GIF_INVALID_FRAME;
+ gif->prev_index = GIF_INVALID_FRAME;
}
/* exported function documented in libnsgif.h */
gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data)
{
- unsigned char *gif_data;
- unsigned int index;
- gif_result return_value;
-
- /* Initialize values */
- gif->buffer_size = size;
- gif->gif_data = data;
-
- if (gif->lzw_ctx == NULL) {
- lzw_result res = lzw_context_create(
- (struct lzw_ctx **)&gif->lzw_ctx);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
- }
-
- /* Check for sufficient data to be a GIF (6-byte header + 7-byte
- * logical screen descriptor)
- */
- if (gif->buffer_size < GIF_STANDARD_HEADER_SIZE) {
- return GIF_INSUFFICIENT_DATA;
- }
-
- /* Get our current processing position */
- gif_data = gif->gif_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->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 = GIF_INVALID_FRAME;
-
- /* 6-byte GIF file header is:
- *
- * +0 3CHARS Signature ('GIF')
- * +3 3CHARS Version ('87a' or '89a')
- */
- if (strncmp((const char *) gif_data, "GIF", 3) != 0) {
- return GIF_DATA_ERROR;
- }
- gif_data += 3;
-
- /* Ensure GIF reports version 87a or 89a */
- /*
- if ((strncmp(gif_data, "87a", 3) != 0) &&
- (strncmp(gif_data, "89a", 3) != 0))
- LOG(("Unknown GIF format - proceeding anyway"));
- */
- gif_data += 3;
-
- /* 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
- */
- gif->width = gif_data[0] | (gif_data[1] << 8);
- gif->height = gif_data[2] | (gif_data[3] << 8);
- gif->global_colours = (gif_data[4] & GIF_COLOUR_TABLE_MASK);
- gif->colour_table_size = (2 << (gif_data[4] & GIF_COLOUR_TABLE_SIZE_MASK));
- gif->background_index = gif_data[5];
- gif->aspect_ratio = gif_data[6];
- gif->loop_count = 1;
- gif_data += 7;
-
- /* 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(GIF_MAX_COLOURS, sizeof(unsigned int));
- gif->local_colour_table = calloc(GIF_MAX_COLOURS, sizeof(unsigned int));
- if ((gif->global_colour_table == NULL) ||
- (gif->local_colour_table == NULL)) {
- gif_finalise(gif);
- return GIF_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;
-
- /* 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_STANDARD_HEADER_SIZE + 1)) {
- if (gif_data[0] == GIF_TRAILER) {
- return GIF_OK;
- } else {
- return GIF_INSUFFICIENT_DATA;
- }
- }
-
- /* Initialise enough workspace for a frame */
- if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) {
- gif_finalise(gif);
- return GIF_INSUFFICIENT_MEMORY;
- }
- gif->frame_holders = 1;
-
- /* Remember we've done this now */
- gif->buffer_position = gif_data - gif->gif_data;
- }
-
- /* 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] == GIF_PROCESS_COLOURS) {
- /* Check for a global colour map signified by bit 7 */
- if (gif->global_colours) {
- if (gif->buffer_size < (gif->colour_table_size * 3 + GIF_STANDARD_HEADER_SIZE)) {
- return GIF_INSUFFICIENT_DATA;
- }
- for (index = 0; index < gif->colour_table_size; index++) {
- /* 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.
- */
- unsigned char *entry = (unsigned char *) &gif->
- global_colour_table[index];
-
- entry[0] = gif_data[0]; /* r */
- entry[1] = gif_data[1]; /* g */
- entry[2] = gif_data[2]; /* b */
- entry[3] = 0xff; /* a */
-
- gif_data += 3;
- }
- gif->buffer_position = (gif_data - gif->gif_data);
- } else {
- /* Create a default colour table with the first two
- * colours as black and white
- */
- unsigned int *entry = gif->global_colour_table;
-
- entry[0] = 0x00000000;
- /* Force Alpha channel to opaque */
- ((unsigned char *) entry)[3] = 0xff;
-
- entry[1] = 0xffffffff;
- }
- }
-
- /* Repeatedly try to initialise frames */
- while ((return_value = gif_initialise_frame(gif)) == GIF_WORKING);
-
- /* If there was a memory error tell the caller */
- if ((return_value == GIF_INSUFFICIENT_MEMORY) ||
- (return_value == GIF_DATA_ERROR)) {
- return return_value;
- }
-
- /* If we didn't have some frames then a GIF_INSUFFICIENT_DATA becomes a
- * GIF_INSUFFICIENT_FRAME_DATA
- */
- if ((return_value == GIF_INSUFFICIENT_DATA) &&
- (gif->frame_count_partial > 0)) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Return how many we got */
- return return_value;
+ unsigned char *gif_data;
+ unsigned int index;
+ gif_result return_value;
+
+ /* Initialize values */
+ gif->buffer_size = size;
+ gif->gif_data = data;
+
+ if (gif->lzw_ctx == NULL) {
+ lzw_result res = lzw_context_create(
+ (struct lzw_ctx **)&gif->lzw_ctx);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+ }
+
+ /* Check for sufficient data to be a GIF (6-byte header + 7-byte
+ * logical screen descriptor)
+ */
+ if (gif->buffer_size < GIF_STANDARD_HEADER_SIZE) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+
+ /* Get our current processing position */
+ gif_data = gif->gif_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->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 = GIF_INVALID_FRAME;
+
+ /* 6-byte GIF file header is:
+ *
+ * +0 3CHARS Signature ('GIF')
+ * +3 3CHARS Version ('87a' or '89a')
+ */
+ if (strncmp((const char *) gif_data, "GIF", 3) != 0) {
+ return GIF_DATA_ERROR;
+ }
+ gif_data += 3;
+
+ /* Ensure GIF reports version 87a or 89a */
+ /*
+ if ((strncmp(gif_data, "87a", 3) != 0) &&
+ (strncmp(gif_data, "89a", 3) != 0))
+ LOG(("Unknown GIF format - proceeding anyway"));
+ */
+ gif_data += 3;
+
+ /* 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
+ */
+ gif->width = gif_data[0] | (gif_data[1] << 8);
+ gif->height = gif_data[2] | (gif_data[3] << 8);
+ gif->global_colours = (gif_data[4] & GIF_COLOUR_TABLE_MASK);
+ gif->colour_table_size = (2 << (gif_data[4] & GIF_COLOUR_TABLE_SIZE_MASK));
+ gif->background_index = gif_data[5];
+ gif->aspect_ratio = gif_data[6];
+ gif->loop_count = 1;
+ gif_data += 7;
+
+ /* 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(GIF_MAX_COLOURS, sizeof(unsigned int));
+ gif->local_colour_table = calloc(GIF_MAX_COLOURS, sizeof(unsigned int));
+ if ((gif->global_colour_table == NULL) ||
+ (gif->local_colour_table == NULL)) {
+ gif_finalise(gif);
+ return GIF_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;
+
+ /* 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_STANDARD_HEADER_SIZE + 1)) {
+ if (gif_data[0] == GIF_TRAILER) {
+ return GIF_OK;
+ } else {
+ return GIF_INSUFFICIENT_DATA;
+ }
+ }
+
+ /* Initialise enough workspace for a frame */
+ if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) {
+ gif_finalise(gif);
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+ gif->frame_holders = 1;
+
+ /* Remember we've done this now */
+ gif->buffer_position = gif_data - gif->gif_data;
+ }
+
+ /* 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] == GIF_PROCESS_COLOURS) {
+ /* Check for a global colour map signified by bit 7 */
+ if (gif->global_colours) {
+ if (gif->buffer_size < (gif->colour_table_size * 3 + GIF_STANDARD_HEADER_SIZE)) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+ for (index = 0; index < gif->colour_table_size; index++) {
+ /* 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.
+ */
+ unsigned char *entry = (unsigned char *) &gif->
+ global_colour_table[index];
+
+ entry[0] = gif_data[0]; /* r */
+ entry[1] = gif_data[1]; /* g */
+ entry[2] = gif_data[2]; /* b */
+ entry[3] = 0xff; /* a */
+
+ gif_data += 3;
+ }
+ gif->buffer_position = (gif_data - gif->gif_data);
+ } else {
+ /* Create a default colour table with the first two
+ * colours as black and white
+ */
+ unsigned int *entry = gif->global_colour_table;
+
+ entry[0] = 0x00000000;
+ /* Force Alpha channel to opaque */
+ ((unsigned char *) entry)[3] = 0xff;
+
+ entry[1] = 0xffffffff;
+ }
+ }
+
+ /* Repeatedly try to initialise frames */
+ while ((return_value = gif_initialise_frame(gif)) == GIF_WORKING);
+
+ /* If there was a memory error tell the caller */
+ if ((return_value == GIF_INSUFFICIENT_MEMORY) ||
+ (return_value == GIF_DATA_ERROR)) {
+ return return_value;
+ }
+
+ /* If we didn't have some frames then a GIF_INSUFFICIENT_DATA becomes a
+ * GIF_INSUFFICIENT_FRAME_DATA
+ */
+ if ((return_value == GIF_INSUFFICIENT_DATA) &&
+ (gif->frame_count_partial > 0)) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Return how many we got */
+ return return_value;
}
/* exported function documented in libnsgif.h */
gif_result gif_decode_frame(gif_animation *gif, unsigned int frame)
{
- return gif_internal_decode_frame(gif, frame, false);
+ return gif_internal_decode_frame(gif, frame, false);
}
/* exported function documented in libnsgif.h */
void gif_finalise(gif_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);
- }
-
- 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;
+ /* Release all our memory blocks */
+ if (gif->frame_image) {
+ assert(gif->bitmap_callbacks.bitmap_destroy);
+ gif->bitmap_callbacks.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;
}
-----------------------------------------------------------------------
Summary of changes:
src/libnsgif.c | 2219 ++++++++++++++++++++++++++++----------------------------
1 file changed, 1109 insertions(+), 1110 deletions(-)
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 6d78dc2..5fa9cb6 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -79,21 +79,21 @@
*/
static gif_result
gif_initialise_sprite(gif_animation *gif,
- unsigned int width,
- unsigned int height)
+ unsigned int width,
+ unsigned int height)
{
- /* Already allocated? */
- if (gif->frame_image) {
- return GIF_OK;
- }
-
- assert(gif->bitmap_callbacks.bitmap_create);
- gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
- if (gif->frame_image == NULL) {
- return GIF_INSUFFICIENT_MEMORY;
- }
-
- return GIF_OK;
+ /* Already allocated? */
+ if (gif->frame_image) {
+ return GIF_OK;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_create);
+ gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
+ if (gif->frame_image == NULL) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ return GIF_OK;
}
@@ -108,117 +108,117 @@ gif_initialise_sprite(gif_animation *gif,
static gif_result
gif_initialise_frame_extensions(gif_animation *gif, const int frame)
{
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int block_size;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
-
- /* Initialise the extensions */
- while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
- ++gif_data;
- if ((gif_bytes = (gif_end - gif_data)) < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Switch on extension label */
- switch (gif_data[0]) {
- case GIF_EXTENSION_GRAPHIC_CONTROL:
- /* 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 (gif_bytes < 6) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4] << 8);
- if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
- gif->frames[frame].transparency = true;
- gif->frames[frame].transparency_index = gif_data[5];
- }
- gif->frames[frame].disposal_method = ((gif_data[2] & GIF_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 (gif->frames[frame].disposal_method == GIF_FRAME_QUIRKS_RESTORE) {
- gif->frames[frame].disposal_method = GIF_FRAME_RESTORE;
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_APPLICATION:
- /* 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 (gif_bytes < 17) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if ((gif_data[1] == 0x0b) &&
- (strncmp((const char *) gif_data + 2,
- "NETSCAPE2.0", 11) == 0) &&
- (gif_data[13] == 0x03) &&
- (gif_data[14] == 0x01)) {
- gif->loop_count = gif_data[15] | (gif_data[16] << 8);
- }
- gif_data += (2 + gif_data[1]);
- break;
-
- case GIF_EXTENSION_COMMENT:
- /* Move the pointer to the first data sub-block Skip 1
- * byte for the extension label
- */
- ++gif_data;
- break;
-
- default:
- /* 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 (gif_bytes < 2) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += (2 + gif_data[1]);
- }
-
- /* Repeatedly skip blocks until we get a zero block or run out
- * of data This data is ignored by this gif decoder
- */
- gif_bytes = (gif_end - gif_data);
- block_size = 0;
- while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
- block_size = gif_data[0] + 1;
- if ((gif_bytes -= block_size) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += block_size;
- }
- ++gif_data;
- }
-
- /* Set buffer position and return */
- gif->buffer_position = (gif_data - gif->gif_data);
- return GIF_OK;
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int block_size;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+
+ /* Initialise the extensions */
+ while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
+ ++gif_data;
+ if ((gif_bytes = (gif_end - gif_data)) < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Switch on extension label */
+ switch (gif_data[0]) {
+ case GIF_EXTENSION_GRAPHIC_CONTROL:
+ /* 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 (gif_bytes < 6) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ gif->frames[frame].frame_delay = gif_data[3] | (gif_data[4] << 8);
+ if (gif_data[2] & GIF_TRANSPARENCY_MASK) {
+ gif->frames[frame].transparency = true;
+ gif->frames[frame].transparency_index = gif_data[5];
+ }
+ gif->frames[frame].disposal_method = ((gif_data[2] & GIF_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 (gif->frames[frame].disposal_method == GIF_FRAME_QUIRKS_RESTORE) {
+ gif->frames[frame].disposal_method = GIF_FRAME_RESTORE;
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_APPLICATION:
+ /* 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 (gif_bytes < 17) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ if ((gif_data[1] == 0x0b) &&
+ (strncmp((const char *) gif_data + 2,
+ "NETSCAPE2.0", 11) == 0) &&
+ (gif_data[13] == 0x03) &&
+ (gif_data[14] == 0x01)) {
+ gif->loop_count = gif_data[15] | (gif_data[16] << 8);
+ }
+ gif_data += (2 + gif_data[1]);
+ break;
+
+ case GIF_EXTENSION_COMMENT:
+ /* Move the pointer to the first data sub-block Skip 1
+ * byte for the extension label
+ */
+ ++gif_data;
+ break;
+
+ default:
+ /* 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 (gif_bytes < 2) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += (2 + gif_data[1]);
+ }
+
+ /* Repeatedly skip blocks until we get a zero block or run out
+ * of data This data is ignored by this gif decoder
+ */
+ gif_bytes = (gif_end - gif_data);
+ block_size = 0;
+ while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
+ block_size = gif_data[0] + 1;
+ if ((gif_bytes -= block_size) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += block_size;
+ }
+ ++gif_data;
+ }
+
+ /* Set buffer position and return */
+ gif->buffer_position = (gif_data - gif->gif_data);
+ return GIF_OK;
}
@@ -237,231 +237,230 @@ gif_initialise_frame_extensions(gif_animation *gif, const int frame)
*/
static gif_result gif_initialise_frame(gif_animation *gif)
{
- int frame;
- gif_frame *temp_buf;
-
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int flags = 0;
- unsigned int width, height, offset_x, offset_y;
- unsigned int block_size, colour_table_size;
- bool first_image = true;
- gif_result return_value;
-
- /* Get the frame to decode and our data position */
- frame = gif->frame_count;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
- gif_bytes = (gif_end - gif_data);
-
- /* Check if we've finished */
- if ((gif_bytes > 0) && (gif_data[0] == GIF_TRAILER)) {
- return GIF_OK;
- }
-
- /* Check if there is enough data remaining. The shortest block of data
- * is a 4-byte comment extension + 1-byte block terminator + 1-byte gif
- * trailer
- */
- if (gif_bytes < 6) {
- return GIF_INSUFFICIENT_DATA;
- }
-
- /* 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 > 4096) {
- return GIF_FRAME_DATA_ERROR;
- }
-
- /* Get some memory to store our pointers in etc. */
- if ((int)gif->frame_holders <= frame) {
- /* Allocate more memory */
- temp_buf = (gif_frame *)realloc(gif->frames, (frame + 1) * sizeof(gif_frame));
- if (temp_buf == NULL) {
- return GIF_INSUFFICIENT_MEMORY;
- }
- gif->frames = temp_buf;
- gif->frame_holders = frame + 1;
- }
-
- /* Store our frame pointer. We would do it when allocating except we
- * start off with one frame allocated so we can always use realloc.
- */
- gif->frames[frame].frame_pointer = gif->buffer_position;
- gif->frames[frame].display = false;
- gif->frames[frame].virgin = true;
- gif->frames[frame].disposal_method = 0;
- gif->frames[frame].transparency = false;
- gif->frames[frame].frame_delay = 100;
- gif->frames[frame].redraw_required = false;
-
- /* Invalidate any previous decoding we have of this frame */
- if (gif->decoded_frame == frame) {
- gif->decoded_frame = GIF_INVALID_FRAME;
- }
-
- /* We pretend to initialise the frames, but really we just skip over
- * all the data contained within. This is all basically a cut down
- * version of gif_decode_frame that doesn't have any of the LZW bits in
- * it.
- */
-
- /* Initialise any extensions */
- gif->buffer_position = gif_data - gif->gif_data;
- return_value = gif_initialise_frame_extensions(gif, frame);
- if (return_value != GIF_OK) {
- return return_value;
- }
- gif_data = (gif->gif_data + gif->buffer_position);
- gif_bytes = (gif_end - gif_data);
-
- /* Check if we've finished */
- if ((gif_bytes = (gif_end - gif_data)) < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- if (gif_data[0] == GIF_TRAILER) {
- gif->buffer_position = (gif_data - gif->gif_data);
- gif->frame_count = frame + 1;
- return GIF_OK;
- }
-
- /* If we're not done, there should be an image descriptor */
- if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
- return GIF_FRAME_DATA_ERROR;
- }
-
- /* Do some simple boundary checking */
- if (gif_bytes < 10) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- offset_x = gif_data[1] | (gif_data[2] << 8);
- offset_y = gif_data[3] | (gif_data[4] << 8);
- width = gif_data[5] | (gif_data[6] << 8);
- height = gif_data[7] | (gif_data[8] << 8);
-
- /* Set up the redraw characteristics. We have to check for extending
- * the area due to multi-image frames.
- */
- if (!first_image) {
- if (gif->frames[frame].redraw_x > offset_x) {
- gif->frames[frame].redraw_width += (gif->frames[frame].redraw_x - offset_x);
- gif->frames[frame].redraw_x = offset_x;
- }
-
- if (gif->frames[frame].redraw_y > offset_y) {
- gif->frames[frame].redraw_height += (gif->frames[frame].redraw_y - offset_y);
- gif->frames[frame].redraw_y = offset_y;
- }
-
- if ((offset_x + width) > (gif->frames[frame].redraw_x + gif->frames[frame].redraw_width)) {
- gif->frames[frame].redraw_width = (offset_x + width) - gif->frames[frame].redraw_x;
- }
-
- if ((offset_y + height) > (gif->frames[frame].redraw_y + gif->frames[frame].redraw_height)) {
- gif->frames[frame].redraw_height = (offset_y + height) - gif->frames[frame].redraw_y;
- }
- } else {
- first_image = false;
- gif->frames[frame].redraw_x = offset_x;
- gif->frames[frame].redraw_y = offset_y;
- gif->frames[frame].redraw_width = width;
- gif->frames[frame].redraw_height = height;
- }
-
- /* if we are clearing the background then we need to redraw enough to
- * cover the previous frame too
- */
- gif->frames[frame].redraw_required = ((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
- (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
-
- /* Frame size may have grown.
- */
- gif->width = (offset_x + width > gif->width) ?
- offset_x + width : gif->width;
- gif->height = (offset_y + height > gif->height) ?
- offset_y + height : gif->height;
-
- /* Decode the flags */
- flags = gif_data[9];
- colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
-
- /* Move our data onwards and remember we've got a bit of this frame */
- gif_data += 10;
- gif_bytes = (gif_end - gif_data);
- gif->frame_count_partial = frame + 1;
-
- /* Skip the local colour table */
- if (flags & GIF_COLOUR_TABLE_MASK) {
- gif_data += 3 * colour_table_size;
- if ((gif_bytes = (gif_end - gif_data)) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- }
-
- /* Ensure we have a correct code size */
- if (gif_bytes < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- if (gif_data[0] >= LZW_CODE_MAX) {
- return GIF_DATA_ERROR;
- }
-
- /* Move our pointer to the actual image data */
- gif_data++;
- --gif_bytes;
-
- /* Repeatedly skip blocks until we get a zero block or run out of data
- * These blocks of image data are processed later by gif_decode_frame()
- */
- block_size = 0;
- while (block_size != 1) {
- if (gif_bytes < 1) return GIF_INSUFFICIENT_FRAME_DATA;
- block_size = gif_data[0] + 1;
- /* Check if the frame data runs off the end of the file */
- if ((int)(gif_bytes - block_size) < 0) {
- /* Try to recover by signaling the end of the gif.
- * Once we get garbage data, there is no logical way to
- * determine where the next frame is. It's probably
- * better to partially load the gif than not at all.
- */
- if (gif_bytes >= 2) {
- gif_data[0] = 0;
- gif_data[1] = GIF_TRAILER;
- gif_bytes = 1;
- ++gif_data;
- break;
- } else {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- } else {
- gif_bytes -= block_size;
- gif_data += block_size;
- }
- }
-
- /* Add the frame and set the display flag */
- gif->buffer_position = gif_data - gif->gif_data;
- gif->frame_count = frame + 1;
- gif->frames[frame].display = true;
-
- /* Check if we've finished */
- if (gif_bytes < 1) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- } else {
- if (gif_data[0] == GIF_TRAILER) {
- return GIF_OK;
- }
- }
- return GIF_WORKING;
+ int frame;
+ gif_frame *temp_buf;
+
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int flags = 0;
+ unsigned int width, height, offset_x, offset_y;
+ unsigned int block_size, colour_table_size;
+ bool first_image = true;
+ gif_result return_value;
+
+ /* Get the frame to decode and our data position */
+ frame = gif->frame_count;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Check if we've finished */
+ if ((gif_bytes > 0) && (gif_data[0] == GIF_TRAILER)) {
+ return GIF_OK;
+ }
+
+ /* Check if there is enough data remaining. The shortest block of data
+ * is a 4-byte comment extension + 1-byte block terminator + 1-byte gif
+ * trailer
+ */
+ if (gif_bytes < 6) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+
+ /* 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 > 4096) {
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ /* Get some memory to store our pointers in etc. */
+ if ((int)gif->frame_holders <= frame) {
+ /* Allocate more memory */
+ temp_buf = (gif_frame *)realloc(gif->frames, (frame + 1) * sizeof(gif_frame));
+ if (temp_buf == NULL) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+ gif->frames = temp_buf;
+ gif->frame_holders = frame + 1;
+ }
+
+ /* Store our frame pointer. We would do it when allocating except we
+ * start off with one frame allocated so we can always use realloc.
+ */
+ gif->frames[frame].frame_pointer = gif->buffer_position;
+ gif->frames[frame].display = false;
+ gif->frames[frame].virgin = true;
+ gif->frames[frame].disposal_method = 0;
+ gif->frames[frame].transparency = false;
+ gif->frames[frame].frame_delay = 100;
+ gif->frames[frame].redraw_required = false;
+
+ /* Invalidate any previous decoding we have of this frame */
+ if (gif->decoded_frame == frame) {
+ gif->decoded_frame = GIF_INVALID_FRAME;
+ }
+
+ /* We pretend to initialise the frames, but really we just skip over
+ * all the data contained within. This is all basically a cut down
+ * version of gif_decode_frame that doesn't have any of the LZW bits in
+ * it.
+ */
+
+ /* Initialise any extensions */
+ gif->buffer_position = gif_data - gif->gif_data;
+ return_value = gif_initialise_frame_extensions(gif, frame);
+ if (return_value != GIF_OK) {
+ return return_value;
+ }
+ gif_data = (gif->gif_data + gif->buffer_position);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Check if we've finished */
+ if ((gif_bytes = (gif_end - gif_data)) < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ if (gif_data[0] == GIF_TRAILER) {
+ gif->buffer_position = (gif_data - gif->gif_data);
+ gif->frame_count = frame + 1;
+ return GIF_OK;
+ }
+
+ /* If we're not done, there should be an image descriptor */
+ if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ /* Do some simple boundary checking */
+ if (gif_bytes < 10) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ offset_x = gif_data[1] | (gif_data[2] << 8);
+ offset_y = gif_data[3] | (gif_data[4] << 8);
+ width = gif_data[5] | (gif_data[6] << 8);
+ height = gif_data[7] | (gif_data[8] << 8);
+
+ /* Set up the redraw characteristics. We have to check for extending
+ * the area due to multi-image frames.
+ */
+ if (!first_image) {
+ if (gif->frames[frame].redraw_x > offset_x) {
+ gif->frames[frame].redraw_width += (gif->frames[frame].redraw_x - offset_x);
+ gif->frames[frame].redraw_x = offset_x;
+ }
+
+ if (gif->frames[frame].redraw_y > offset_y) {
+ gif->frames[frame].redraw_height += (gif->frames[frame].redraw_y - offset_y);
+ gif->frames[frame].redraw_y = offset_y;
+ }
+
+ if ((offset_x + width) > (gif->frames[frame].redraw_x + gif->frames[frame].redraw_width)) {
+ gif->frames[frame].redraw_width = (offset_x + width) - gif->frames[frame].redraw_x;
+ }
+
+ if ((offset_y + height) > (gif->frames[frame].redraw_y + gif->frames[frame].redraw_height)) {
+ gif->frames[frame].redraw_height = (offset_y + height) - gif->frames[frame].redraw_y;
+ }
+ } else {
+ first_image = false;
+ gif->frames[frame].redraw_x = offset_x;
+ gif->frames[frame].redraw_y = offset_y;
+ gif->frames[frame].redraw_width = width;
+ gif->frames[frame].redraw_height = height;
+ }
+
+ /* if we are clearing the background then we need to redraw enough to
+ * cover the previous frame too
+ */
+ gif->frames[frame].redraw_required =
+ ((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
+ (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
+
+ /* Frame size may have grown.
+ */
+ gif->width = (offset_x + width > gif->width) ?
+ offset_x + width : gif->width;
+ gif->height = (offset_y + height > gif->height) ?
+ offset_y + height : gif->height;
+
+ /* Decode the flags */
+ flags = gif_data[9];
+ colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
+
+ /* Move our data onwards and remember we've got a bit of this frame */
+ gif_data += 10;
+ gif_bytes = (gif_end - gif_data);
+ gif->frame_count_partial = frame + 1;
+
+ /* Skip the local colour table */
+ if (flags & GIF_COLOUR_TABLE_MASK) {
+ gif_data += 3 * colour_table_size;
+ if ((gif_bytes = (gif_end - gif_data)) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ }
+
+ /* Ensure we have a correct code size */
+ if (gif_bytes < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ if (gif_data[0] >= LZW_CODE_MAX) {
+ return GIF_DATA_ERROR;
+ }
+
+ /* Move our pointer to the actual image data */
+ gif_data++;
+ --gif_bytes;
+
+ /* Repeatedly skip blocks until we get a zero block or run out of data
+ * These blocks of image data are processed later by gif_decode_frame()
+ */
+ block_size = 0;
+ while (block_size != 1) {
+ if (gif_bytes < 1) return GIF_INSUFFICIENT_FRAME_DATA;
+ block_size = gif_data[0] + 1;
+ /* Check if the frame data runs off the end of the file */
+ if ((int)(gif_bytes - block_size) < 0) {
+ /* Try to recover by signaling the end of the gif.
+ * Once we get garbage data, there is no logical way to
+ * determine where the next frame is. It's probably
+ * better to partially load the gif than not at all.
+ */
+ if (gif_bytes >= 2) {
+ gif_data[0] = 0;
+ gif_data[1] = GIF_TRAILER;
+ gif_bytes = 1;
+ ++gif_data;
+ break;
+ } else {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ } else {
+ gif_bytes -= block_size;
+ gif_data += block_size;
+ }
+ }
+
+ /* Add the frame and set the display flag */
+ gif->buffer_position = gif_data - gif->gif_data;
+ gif->frame_count = frame + 1;
+ gif->frames[frame].display = true;
+
+ /* Check if we've finished */
+ if (gif_bytes < 1) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ } else {
+ if (gif_data[0] == GIF_TRAILER) {
+ return GIF_OK;
+ }
+ }
+ return GIF_WORKING;
}
-
-
/**
* Skips the frame's extensions (which have been previously initialised)
*
@@ -471,313 +470,313 @@ static gif_result gif_initialise_frame(gif_animation *gif)
*/
static gif_result gif_skip_frame_extensions(gif_animation *gif)
{
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int block_size;
-
- /* Get our buffer position etc. */
- gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
- gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
- gif_bytes = (gif_end - gif_data);
-
- /* Skip the extensions */
- while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
- ++gif_data;
- if (gif_data >= gif_end) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Switch on extension label */
- switch(gif_data[0]) {
- case GIF_EXTENSION_COMMENT:
- /* Move the pointer to the first data sub-block
- * 1 byte for the extension label
- */
- ++gif_data;
- break;
-
- default:
- /* Move the pointer to the first data sub-block 2 bytes
- * for the extension label and size fields Skip the
- * extension size itself
- */
- if (gif_data + 1 >= gif_end) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += (2 + gif_data[1]);
- }
-
- /* Repeatedly skip blocks until we get a zero block or run out
- * of data This data is ignored by this gif decoder
- */
- gif_bytes = (gif_end - gif_data);
- block_size = 0;
- while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
- block_size = gif_data[0] + 1;
- if ((gif_bytes -= block_size) < 0) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
- gif_data += block_size;
- }
- ++gif_data;
- }
-
- /* Set buffer position and return */
- gif->buffer_position = (gif_data - gif->gif_data);
- return GIF_OK;
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int block_size;
+
+ /* Get our buffer position etc. */
+ gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position);
+ gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Skip the extensions */
+ while (gif_data < gif_end && gif_data[0] == GIF_EXTENSION_INTRODUCER) {
+ ++gif_data;
+ if (gif_data >= gif_end) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Switch on extension label */
+ switch(gif_data[0]) {
+ case GIF_EXTENSION_COMMENT:
+ /* Move the pointer to the first data sub-block
+ * 1 byte for the extension label
+ */
+ ++gif_data;
+ break;
+
+ default:
+ /* Move the pointer to the first data sub-block 2 bytes
+ * for the extension label and size fields Skip the
+ * extension size itself
+ */
+ if (gif_data + 1 >= gif_end) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += (2 + gif_data[1]);
+ }
+
+ /* Repeatedly skip blocks until we get a zero block or run out
+ * of data This data is ignored by this gif decoder
+ */
+ gif_bytes = (gif_end - gif_data);
+ block_size = 0;
+ while (gif_data < gif_end && gif_data[0] != GIF_BLOCK_TERMINATOR) {
+ block_size = gif_data[0] + 1;
+ if ((gif_bytes -= block_size) < 0) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+ gif_data += block_size;
+ }
+ ++gif_data;
+ }
+
+ /* Set buffer position and return */
+ gif->buffer_position = (gif_data - gif->gif_data);
+ return GIF_OK;
}
static unsigned int gif_interlaced_line(int height, int y) {
- if ((y << 3) < height) {
- return (y << 3);
- }
- y -= ((height + 7) >> 3);
- if ((y << 3) < (height - 4)) {
- return (y << 3) + 4;
- }
- y -= ((height + 3) >> 3);
- if ((y << 2) < (height - 2)) {
- return (y << 2) + 2;
- }
- y -= ((height + 1) >> 2);
- return (y << 1) + 1;
+ if ((y << 3) < height) {
+ return (y << 3);
+ }
+ y -= ((height + 7) >> 3);
+ if ((y << 3) < (height - 4)) {
+ return (y << 3) + 4;
+ }
+ y -= ((height + 3) >> 3);
+ if ((y << 2) < (height - 2)) {
+ return (y << 2) + 2;
+ }
+ y -= ((height + 1) >> 2);
+ return (y << 1) + 1;
}
static gif_result gif_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_FRAME_DATA,
- [LZW_EOI_CODE] = GIF_FRAME_DATA_ERROR,
- [LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
- [LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
- };
- return g_res[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_FRAME_DATA,
+ [LZW_EOI_CODE] = GIF_FRAME_DATA_ERROR,
+ [LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
+ [LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
+ };
+ return g_res[l_res];
}
static void gif__record_previous_frame(gif_animation *gif)
{
- bool need_alloc = gif->prev_frame == NULL;
- const uint32_t *frame_data;
- uint32_t *prev_frame;
-
- if (gif->decoded_frame == GIF_INVALID_FRAME ||
- gif->decoded_frame == gif->prev_index) {
- /* No frame to copy, or already have this frame recorded. */
- return;
- }
-
- assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- 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, frame_data, 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;
+ bool need_alloc = gif->prev_frame == NULL;
+ const uint32_t *frame_data;
+ uint32_t *prev_frame;
+
+ if (gif->decoded_frame == GIF_INVALID_FRAME ||
+ gif->decoded_frame == gif->prev_index) {
+ /* No frame to copy, or already have this frame recorded. */
+ return;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ 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, frame_data, 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 gif_result gif__recover_previous_frame(const gif_animation *gif)
{
- 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;
- uint32_t *frame_data;
+ 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;
+ uint32_t *frame_data;
- if (prev_frame == NULL) {
- return GIF_FRAME_DATA_ERROR;
- }
+ if (prev_frame == NULL) {
+ return GIF_FRAME_DATA_ERROR;
+ }
- assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- return GIF_INSUFFICIENT_MEMORY;
- }
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
- for (unsigned y = 0; y < height; y++) {
- memcpy(frame_data, prev_frame, width * 4);
+ for (unsigned y = 0; y < height; y++) {
+ memcpy(frame_data, prev_frame, width * 4);
- frame_data += gif->width;
- prev_frame += gif->prev_width;
- }
+ frame_data += gif->width;
+ prev_frame += gif->prev_width;
+ }
- return GIF_OK;
+ return GIF_OK;
}
static gif_result
gif__decode_complex(gif_animation *gif,
- unsigned int frame,
- unsigned int width,
- unsigned int height,
- unsigned int offset_x,
- unsigned int offset_y,
- unsigned int interlace,
- uint8_t minimum_code_size,
- unsigned int *restrict frame_data,
- unsigned int *restrict colour_table)
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
{
- unsigned int transparency_index;
- uint32_t available = 0;
- gif_result ret = GIF_OK;
- lzw_result res;
-
- /* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
-
- transparency_index = gif->frames[frame].transparency ?
- gif->frames[frame].transparency_index :
- GIF_NO_TRANSPARENCY;
-
- for (unsigned int y = 0; y < height; y++) {
- unsigned int x;
- unsigned int decode_y;
- unsigned int *frame_scanline;
-
- if (interlace) {
- decode_y = gif_interlaced_line(height, y) + offset_y;
- } else {
- decode_y = y + offset_y;
- }
- frame_scanline = frame_data + offset_x + (decode_y * gif->width);
-
- 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 = GIF_OK;
- } else {
- ret = gif_error_from_lzw(res);
- }
- break;
- }
- res = lzw_decode_continuous(gif->lzw_ctx,
- &uncompressed, &available);
- }
-
- row_available = x < available ? x : available;
- x -= row_available;
- available -= row_available;
- while (row_available-- > 0) {
- register unsigned int colour;
- colour = *uncompressed++;
- if (colour != transparency_index) {
- *frame_scanline = colour_table[colour];
- }
- frame_scanline++;
- }
- }
- }
- return ret;
+ unsigned int transparency_index;
+ uint32_t available = 0;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
+ for (unsigned int y = 0; y < height; y++) {
+ unsigned int x;
+ unsigned int decode_y;
+ unsigned int *frame_scanline;
+
+ if (interlace) {
+ decode_y = gif_interlaced_line(height, y) + offset_y;
+ } else {
+ decode_y = y + offset_y;
+ }
+ frame_scanline = frame_data + offset_x + (decode_y * gif->width);
+
+ 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 = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ res = lzw_decode_continuous(gif->lzw_ctx,
+ &uncompressed, &available);
+ }
+
+ row_available = x < available ? x : available;
+ x -= row_available;
+ available -= row_available;
+ while (row_available-- > 0) {
+ register unsigned int colour;
+ colour = *uncompressed++;
+ if (colour != transparency_index) {
+ *frame_scanline = colour_table[colour];
+ }
+ frame_scanline++;
+ }
+ }
+ }
+ return ret;
}
static gif_result
gif__decode_simple(gif_animation *gif,
- unsigned int frame,
- unsigned int height,
- unsigned int offset_y,
- uint8_t minimum_code_size,
- unsigned int *restrict frame_data,
- unsigned int *restrict colour_table)
+ unsigned int frame,
+ unsigned int height,
+ unsigned int offset_y,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
{
- unsigned int transparency_index;
- uint32_t pixels = gif->width * height;
- uint32_t written = 0;
- gif_result ret = GIF_OK;
- lzw_result res;
-
- /* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- minimum_code_size);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
-
- transparency_index = gif->frames[frame].transparency ?
- gif->frames[frame].transparency_index :
- GIF_NO_TRANSPARENCY;
-
- frame_data += (offset_y * gif->width);
-
- while (pixels > 0) {
- res = lzw_decode_map_continuous(gif->lzw_ctx,
- transparency_index, colour_table,
- frame_data, pixels, &written);
- pixels -= written;
- frame_data += written;
- if (res != LZW_OK) {
- /* Unexpected end of frame, try to recover */
- if (res == LZW_OK_EOD) {
- ret = GIF_OK;
- } else {
- ret = gif_error_from_lzw(res);
- }
- break;
- }
- }
-
- if (pixels == 0) {
- ret = GIF_OK;
- }
-
- return ret;
+ unsigned int transparency_index;
+ uint32_t pixels = gif->width * height;
+ uint32_t written = 0;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
+ frame_data += (offset_y * gif->width);
+
+ while (pixels > 0) {
+ res = lzw_decode_map_continuous(gif->lzw_ctx,
+ transparency_index, colour_table,
+ frame_data, pixels, &written);
+ pixels -= written;
+ frame_data += written;
+ if (res != LZW_OK) {
+ /* Unexpected end of frame, try to recover */
+ if (res == LZW_OK_EOD) {
+ ret = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ }
+
+ if (pixels == 0) {
+ ret = GIF_OK;
+ }
+
+ return ret;
}
static inline gif_result
gif__decode(gif_animation *gif,
- unsigned int frame,
- unsigned int width,
- unsigned int height,
- unsigned int offset_x,
- unsigned int offset_y,
- unsigned int interlace,
- uint8_t minimum_code_size,
- unsigned int *restrict frame_data,
- unsigned int *restrict colour_table)
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
{
- gif_result ret;
-
- if (interlace == false && width == gif->width && offset_x == 0) {
- ret = gif__decode_simple(gif, frame, height, offset_y,
- minimum_code_size, frame_data, colour_table);
- } else {
- ret = gif__decode_complex(gif, frame, width, height,
- offset_x, offset_y, interlace,
- minimum_code_size, frame_data, colour_table);
- }
-
- return ret;
+ gif_result ret;
+
+ if (interlace == false && width == gif->width && offset_x == 0) {
+ ret = gif__decode_simple(gif, frame, height, offset_y,
+ minimum_code_size, frame_data, colour_table);
+ } else {
+ ret = gif__decode_complex(gif, frame, width, height,
+ offset_x, offset_y, interlace,
+ minimum_code_size, frame_data, colour_table);
+ }
+
+ return ret;
}
/**
@@ -789,527 +788,527 @@ gif__decode(gif_animation *gif,
*/
static gif_result
gif_internal_decode_frame(gif_animation *gif,
- unsigned int frame,
- bool clear_image)
+ unsigned int frame,
+ bool clear_image)
{
- gif_result err;
- unsigned int index = 0;
- unsigned char *gif_data, *gif_end;
- int gif_bytes;
- unsigned int width, height, offset_x, offset_y;
- unsigned int flags, colour_table_size, interlace;
- unsigned int *colour_table;
- unsigned int *frame_data = 0; // Set to 0 for no warnings
- unsigned int save_buffer_position;
- unsigned int return_value = 0;
-
- /* Ensure this frame is supposed to be decoded */
- if (gif->frames[frame].display == false) {
- return GIF_OK;
- }
-
- /* Ensure the frame is in range to decode */
- if (frame > gif->frame_count_partial) {
- return GIF_INSUFFICIENT_DATA;
- }
-
- /* done if frame is already decoded */
- if ((!clear_image) &&
- ((int)frame == gif->decoded_frame)) {
- return GIF_OK;
- }
-
- /* Get the start of our frame data and the end of the GIF data */
- gif_data = gif->gif_data + gif->frames[frame].frame_pointer;
- gif_end = gif->gif_data + gif->buffer_size;
- gif_bytes = (gif_end - gif_data);
-
- /*
- * Ensure there is a minimal amount of data to proceed. The shortest
- * block of data is a 10-byte image descriptor + 1-byte gif trailer
- */
- if (gif_bytes < 12) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Save the buffer position */
- save_buffer_position = gif->buffer_position;
- gif->buffer_position = gif_data - gif->gif_data;
-
- /* Skip any extensions because they have allready been processed */
- if ((return_value = gif_skip_frame_extensions(gif)) != GIF_OK) {
- goto gif_decode_frame_exit;
- }
- gif_data = (gif->gif_data + gif->buffer_position);
- gif_bytes = (gif_end - gif_data);
-
- /* Ensure we have enough data for the 10-byte image descriptor + 1-byte
- * gif trailer
- */
- if (gif_bytes < 12) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
-
- /* 10-byte Image Descriptor 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
- */
- if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
- return_value = GIF_DATA_ERROR;
- goto gif_decode_frame_exit;
- }
- offset_x = gif_data[1] | (gif_data[2] << 8);
- offset_y = gif_data[3] | (gif_data[4] << 8);
- width = gif_data[5] | (gif_data[6] << 8);
- height = gif_data[7] | (gif_data[8] << 8);
-
- /* Boundary checking - shouldn't ever happen except unless the data has
- * been modified since initialisation.
- */
- if ((offset_x + width > gif->width) ||
- (offset_y + height > gif->height)) {
- return_value = GIF_DATA_ERROR;
- goto gif_decode_frame_exit;
- }
-
- /* Make sure we have a buffer to decode to.
- */
- if (gif_initialise_sprite(gif, gif->width, gif->height)) {
- return GIF_INSUFFICIENT_MEMORY;
- }
-
- /* Decode the flags */
- flags = gif_data[9];
- colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
- interlace = flags & GIF_INTERLACE_MASK;
-
- /* Advance data pointer to next block either colour table or image
- * data.
- */
- gif_data += 10;
- gif_bytes = (gif_end - gif_data);
-
- /* Set up the colour table */
- if (flags & GIF_COLOUR_TABLE_MASK) {
- if (gif_bytes < (int)(3 * colour_table_size)) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
- colour_table = gif->local_colour_table;
- if (!clear_image) {
- for (index = 0; index < colour_table_size; index++) {
- /* 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.
- */
- unsigned char *entry =
- (unsigned char *) &colour_table[index];
-
- entry[0] = gif_data[0]; /* r */
- entry[1] = gif_data[1]; /* g */
- entry[2] = gif_data[2]; /* b */
- entry[3] = 0xff; /* a */
-
- gif_data += 3;
- }
- } else {
- gif_data += 3 * colour_table_size;
- }
- gif_bytes = (gif_end - gif_data);
- } else {
- colour_table = gif->global_colour_table;
- }
-
- /* Ensure sufficient data remains */
- if (gif_bytes < 1) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
-
- /* check for an end marker */
- if (gif_data[0] == GIF_TRAILER) {
- return_value = GIF_OK;
- goto gif_decode_frame_exit;
- }
-
- /* Get the frame data */
- assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- return GIF_INSUFFICIENT_MEMORY;
- }
-
- /* If we are clearing the image we just clear, if not decode */
- if (!clear_image) {
- /* Ensure we have enough data for a 1-byte LZW code size +
- * 1-byte gif trailer
- */
- if (gif_bytes < 2) {
- return_value = GIF_INSUFFICIENT_FRAME_DATA;
- goto gif_decode_frame_exit;
- }
-
- /* If we only have a 1-byte LZW code size + 1-byte gif trailer,
- * we're finished
- */
- if ((gif_bytes == 2) && (gif_data[1] == GIF_TRAILER)) {
- return_value = GIF_OK;
- goto gif_decode_frame_exit;
- }
-
- /* If the previous frame's disposal method requires we restore
- * the background colour or this is the first frame, clear
- * the frame data
- */
- if ((frame == 0) || (gif->decoded_frame == GIF_INVALID_FRAME)) {
- memset((char*)frame_data,
- GIF_TRANSPARENT_COLOUR,
- gif->width * gif->height * sizeof(int));
- gif->decoded_frame = frame;
- /* The line below would fill the image with its
- * background color, but because GIFs support
- * transparency we likely wouldn't want to do that. */
- /* memset((char*)frame_data, colour_table[gif->background_index], gif->width * gif->height * sizeof(int)); */
- } else if ((frame != 0) &&
- (gif->frames[frame - 1].disposal_method == GIF_FRAME_CLEAR)) {
- return_value = gif_internal_decode_frame(gif,
- (frame - 1),
- true);
- if (return_value != GIF_OK) {
- goto gif_decode_frame_exit;
- }
-
- } else if ((frame != 0) &&
- (gif->frames[frame - 1].disposal_method == GIF_FRAME_RESTORE)) {
- /*
- * If the previous frame's disposal method requires we
- * restore the previous image, restore our saved image.
- */
- err = gif__recover_previous_frame(gif);
- if (err != GIF_OK) {
- /* see notes above on transparency
- * vs. background color
- */
- memset((char*)frame_data,
- GIF_TRANSPARENT_COLOUR,
- gif->width * gif->height * sizeof(int));
- }
- }
-
- if (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE) {
- /* Store the previous frame for later restoration */
- gif__record_previous_frame(gif);
- }
-
- gif->decoded_frame = frame;
- gif->buffer_position = (gif_data - gif->gif_data) + 1;
-
- return_value = gif__decode(gif, frame, width, height,
- offset_x, offset_y, interlace, gif_data[0],
- frame_data, colour_table);
- } else {
- /* Clear our frame */
- if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) {
- unsigned int y;
- for (y = 0; y < height; y++) {
- unsigned int *frame_scanline;
- frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width);
- if (gif->frames[frame].transparency) {
- memset(frame_scanline,
- GIF_TRANSPARENT_COLOUR,
- width * 4);
- } else {
- memset(frame_scanline,
- colour_table[gif->background_index],
- width * 4);
- }
- }
- }
- }
+ gif_result err;
+ unsigned int index = 0;
+ unsigned char *gif_data, *gif_end;
+ int gif_bytes;
+ unsigned int width, height, offset_x, offset_y;
+ unsigned int flags, colour_table_size, interlace;
+ unsigned int *colour_table;
+ unsigned int *frame_data = 0; // Set to 0 for no warnings
+ unsigned int save_buffer_position;
+ unsigned int return_value = 0;
+
+ /* Ensure this frame is supposed to be decoded */
+ if (gif->frames[frame].display == false) {
+ return GIF_OK;
+ }
+
+ /* Ensure the frame is in range to decode */
+ if (frame > gif->frame_count_partial) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+
+ /* done if frame is already decoded */
+ if ((!clear_image) &&
+ ((int)frame == gif->decoded_frame)) {
+ return GIF_OK;
+ }
+
+ /* Get the start of our frame data and the end of the GIF data */
+ gif_data = gif->gif_data + gif->frames[frame].frame_pointer;
+ gif_end = gif->gif_data + gif->buffer_size;
+ gif_bytes = (gif_end - gif_data);
+
+ /*
+ * Ensure there is a minimal amount of data to proceed. The shortest
+ * block of data is a 10-byte image descriptor + 1-byte gif trailer
+ */
+ if (gif_bytes < 12) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Save the buffer position */
+ save_buffer_position = gif->buffer_position;
+ gif->buffer_position = gif_data - gif->gif_data;
+
+ /* Skip any extensions because they have already been processed */
+ if ((return_value = gif_skip_frame_extensions(gif)) != GIF_OK) {
+ goto gif_decode_frame_exit;
+ }
+ gif_data = (gif->gif_data + gif->buffer_position);
+ gif_bytes = (gif_end - gif_data);
+
+ /* Ensure we have enough data for the 10-byte image descriptor + 1-byte
+ * gif trailer
+ */
+ if (gif_bytes < 12) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+
+ /* 10-byte Image Descriptor 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
+ */
+ if (gif_data[0] != GIF_IMAGE_SEPARATOR) {
+ return_value = GIF_DATA_ERROR;
+ goto gif_decode_frame_exit;
+ }
+ offset_x = gif_data[1] | (gif_data[2] << 8);
+ offset_y = gif_data[3] | (gif_data[4] << 8);
+ width = gif_data[5] | (gif_data[6] << 8);
+ height = gif_data[7] | (gif_data[8] << 8);
+
+ /* Boundary checking - shouldn't ever happen except unless the data has
+ * been modified since initialisation.
+ */
+ if ((offset_x + width > gif->width) ||
+ (offset_y + height > gif->height)) {
+ return_value = GIF_DATA_ERROR;
+ goto gif_decode_frame_exit;
+ }
+
+ /* Make sure we have a buffer to decode to.
+ */
+ if (gif_initialise_sprite(gif, gif->width, gif->height)) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ /* Decode the flags */
+ flags = gif_data[9];
+ colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
+ interlace = flags & GIF_INTERLACE_MASK;
+
+ /* Advance data pointer to next block either colour table or image
+ * data.
+ */
+ gif_data += 10;
+ gif_bytes = (gif_end - gif_data);
+
+ /* Set up the colour table */
+ if (flags & GIF_COLOUR_TABLE_MASK) {
+ if (gif_bytes < (int)(3 * colour_table_size)) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+ colour_table = gif->local_colour_table;
+ if (!clear_image) {
+ for (index = 0; index < colour_table_size; index++) {
+ /* 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.
+ */
+ unsigned char *entry =
+ (unsigned char *) &colour_table[index];
+
+ entry[0] = gif_data[0]; /* r */
+ entry[1] = gif_data[1]; /* g */
+ entry[2] = gif_data[2]; /* b */
+ entry[3] = 0xff; /* a */
+
+ gif_data += 3;
+ }
+ } else {
+ gif_data += 3 * colour_table_size;
+ }
+ gif_bytes = (gif_end - gif_data);
+ } else {
+ colour_table = gif->global_colour_table;
+ }
+
+ /* Ensure sufficient data remains */
+ if (gif_bytes < 1) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+
+ /* check for an end marker */
+ if (gif_data[0] == GIF_TRAILER) {
+ return_value = GIF_OK;
+ goto gif_decode_frame_exit;
+ }
+
+ /* Get the frame data */
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ /* If we are clearing the image we just clear, if not decode */
+ if (!clear_image) {
+ /* Ensure we have enough data for a 1-byte LZW code size +
+ * 1-byte gif trailer
+ */
+ if (gif_bytes < 2) {
+ return_value = GIF_INSUFFICIENT_FRAME_DATA;
+ goto gif_decode_frame_exit;
+ }
+
+ /* If we only have a 1-byte LZW code size + 1-byte gif trailer,
+ * we're finished
+ */
+ if ((gif_bytes == 2) && (gif_data[1] == GIF_TRAILER)) {
+ return_value = GIF_OK;
+ goto gif_decode_frame_exit;
+ }
+
+ /* If the previous frame's disposal method requires we restore
+ * the background colour or this is the first frame, clear
+ * the frame data
+ */
+ if ((frame == 0) || (gif->decoded_frame == GIF_INVALID_FRAME)) {
+ memset((char*)frame_data,
+ GIF_TRANSPARENT_COLOUR,
+ gif->width * gif->height * sizeof(int));
+ gif->decoded_frame = frame;
+ /* The line below would fill the image with its
+ * background color, but because GIFs support
+ * transparency we likely wouldn't want to do that. */
+ /* memset((char*)frame_data, colour_table[gif->background_index], gif->width * gif->height * sizeof(int)); */
+ } else if ((frame != 0) &&
+ (gif->frames[frame - 1].disposal_method == GIF_FRAME_CLEAR)) {
+ return_value = gif_internal_decode_frame(gif,
+ (frame - 1),
+ true);
+ if (return_value != GIF_OK) {
+ goto gif_decode_frame_exit;
+ }
+
+ } else if ((frame != 0) &&
+ (gif->frames[frame - 1].disposal_method == GIF_FRAME_RESTORE)) {
+ /*
+ * If the previous frame's disposal method requires we
+ * restore the previous image, restore our saved image.
+ */
+ err = gif__recover_previous_frame(gif);
+ if (err != GIF_OK) {
+ /* see notes above on transparency
+ * vs. background color
+ */
+ memset((char*)frame_data,
+ GIF_TRANSPARENT_COLOUR,
+ gif->width * gif->height * sizeof(int));
+ }
+ }
+
+ if (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE) {
+ /* Store the previous frame for later restoration */
+ gif__record_previous_frame(gif);
+ }
+
+ gif->decoded_frame = frame;
+ gif->buffer_position = (gif_data - gif->gif_data) + 1;
+
+ return_value = gif__decode(gif, frame, width, height,
+ offset_x, offset_y, interlace, gif_data[0],
+ frame_data, colour_table);
+ } else {
+ /* Clear our frame */
+ if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) {
+ unsigned int y;
+ for (y = 0; y < height; y++) {
+ unsigned int *frame_scanline;
+ frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width);
+ if (gif->frames[frame].transparency) {
+ memset(frame_scanline,
+ GIF_TRANSPARENT_COLOUR,
+ width * 4);
+ } else {
+ memset(frame_scanline,
+ colour_table[gif->background_index],
+ width * 4);
+ }
+ }
+ }
+ }
gif_decode_frame_exit:
- /* Check if we should test for optimisation */
- if (gif->frames[frame].virgin) {
- if (gif->bitmap_callbacks.bitmap_test_opaque) {
- gif->frames[frame].opaque = gif->bitmap_callbacks.bitmap_test_opaque(gif->frame_image);
- } else {
- gif->frames[frame].opaque = false;
- }
- gif->frames[frame].virgin = false;
- }
+ /* Check if we should test for optimisation */
+ if (gif->frames[frame].virgin) {
+ if (gif->bitmap_callbacks.bitmap_test_opaque) {
+ gif->frames[frame].opaque = gif->bitmap_callbacks.bitmap_test_opaque(gif->frame_image);
+ } else {
+ gif->frames[frame].opaque = false;
+ }
+ gif->frames[frame].virgin = false;
+ }
- if (gif->bitmap_callbacks.bitmap_set_opaque) {
- gif->bitmap_callbacks.bitmap_set_opaque(gif->frame_image, gif->frames[frame].opaque);
- }
+ if (gif->bitmap_callbacks.bitmap_set_opaque) {
+ gif->bitmap_callbacks.bitmap_set_opaque(gif->frame_image, gif->frames[frame].opaque);
+ }
- if (gif->bitmap_callbacks.bitmap_modified) {
- gif->bitmap_callbacks.bitmap_modified(gif->frame_image);
- }
+ if (gif->bitmap_callbacks.bitmap_modified) {
+ gif->bitmap_callbacks.bitmap_modified(gif->frame_image);
+ }
- /* Restore the buffer position */
- gif->buffer_position = save_buffer_position;
+ /* Restore the buffer position */
+ gif->buffer_position = save_buffer_position;
- return return_value;
+ return return_value;
}
/* exported function documented in libnsgif.h */
void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks)
{
- 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(gif_animation));
+ gif->bitmap_callbacks = *bitmap_callbacks;
+ gif->decoded_frame = GIF_INVALID_FRAME;
+ gif->prev_index = GIF_INVALID_FRAME;
}
/* exported function documented in libnsgif.h */
gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data)
{
- unsigned char *gif_data;
- unsigned int index;
- gif_result return_value;
-
- /* Initialize values */
- gif->buffer_size = size;
- gif->gif_data = data;
-
- if (gif->lzw_ctx == NULL) {
- lzw_result res = lzw_context_create(
- (struct lzw_ctx **)&gif->lzw_ctx);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
- }
-
- /* Check for sufficient data to be a GIF (6-byte header + 7-byte
- * logical screen descriptor)
- */
- if (gif->buffer_size < GIF_STANDARD_HEADER_SIZE) {
- return GIF_INSUFFICIENT_DATA;
- }
-
- /* Get our current processing position */
- gif_data = gif->gif_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->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 = GIF_INVALID_FRAME;
-
- /* 6-byte GIF file header is:
- *
- * +0 3CHARS Signature ('GIF')
- * +3 3CHARS Version ('87a' or '89a')
- */
- if (strncmp((const char *) gif_data, "GIF", 3) != 0) {
- return GIF_DATA_ERROR;
- }
- gif_data += 3;
-
- /* Ensure GIF reports version 87a or 89a */
- /*
- if ((strncmp(gif_data, "87a", 3) != 0) &&
- (strncmp(gif_data, "89a", 3) != 0))
- LOG(("Unknown GIF format - proceeding anyway"));
- */
- gif_data += 3;
-
- /* 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
- */
- gif->width = gif_data[0] | (gif_data[1] << 8);
- gif->height = gif_data[2] | (gif_data[3] << 8);
- gif->global_colours = (gif_data[4] & GIF_COLOUR_TABLE_MASK);
- gif->colour_table_size = (2 << (gif_data[4] & GIF_COLOUR_TABLE_SIZE_MASK));
- gif->background_index = gif_data[5];
- gif->aspect_ratio = gif_data[6];
- gif->loop_count = 1;
- gif_data += 7;
-
- /* 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(GIF_MAX_COLOURS, sizeof(unsigned int));
- gif->local_colour_table = calloc(GIF_MAX_COLOURS, sizeof(unsigned int));
- if ((gif->global_colour_table == NULL) ||
- (gif->local_colour_table == NULL)) {
- gif_finalise(gif);
- return GIF_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;
-
- /* 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_STANDARD_HEADER_SIZE + 1)) {
- if (gif_data[0] == GIF_TRAILER) {
- return GIF_OK;
- } else {
- return GIF_INSUFFICIENT_DATA;
- }
- }
-
- /* Initialise enough workspace for a frame */
- if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) {
- gif_finalise(gif);
- return GIF_INSUFFICIENT_MEMORY;
- }
- gif->frame_holders = 1;
-
- /* Remember we've done this now */
- gif->buffer_position = gif_data - gif->gif_data;
- }
-
- /* 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] == GIF_PROCESS_COLOURS) {
- /* Check for a global colour map signified by bit 7 */
- if (gif->global_colours) {
- if (gif->buffer_size < (gif->colour_table_size * 3 + GIF_STANDARD_HEADER_SIZE)) {
- return GIF_INSUFFICIENT_DATA;
- }
- for (index = 0; index < gif->colour_table_size; index++) {
- /* 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.
- */
- unsigned char *entry = (unsigned char *) &gif->
- global_colour_table[index];
-
- entry[0] = gif_data[0]; /* r */
- entry[1] = gif_data[1]; /* g */
- entry[2] = gif_data[2]; /* b */
- entry[3] = 0xff; /* a */
-
- gif_data += 3;
- }
- gif->buffer_position = (gif_data - gif->gif_data);
- } else {
- /* Create a default colour table with the first two
- * colours as black and white
- */
- unsigned int *entry = gif->global_colour_table;
-
- entry[0] = 0x00000000;
- /* Force Alpha channel to opaque */
- ((unsigned char *) entry)[3] = 0xff;
-
- entry[1] = 0xffffffff;
- }
- }
-
- /* Repeatedly try to initialise frames */
- while ((return_value = gif_initialise_frame(gif)) == GIF_WORKING);
-
- /* If there was a memory error tell the caller */
- if ((return_value == GIF_INSUFFICIENT_MEMORY) ||
- (return_value == GIF_DATA_ERROR)) {
- return return_value;
- }
-
- /* If we didn't have some frames then a GIF_INSUFFICIENT_DATA becomes a
- * GIF_INSUFFICIENT_FRAME_DATA
- */
- if ((return_value == GIF_INSUFFICIENT_DATA) &&
- (gif->frame_count_partial > 0)) {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
-
- /* Return how many we got */
- return return_value;
+ unsigned char *gif_data;
+ unsigned int index;
+ gif_result return_value;
+
+ /* Initialize values */
+ gif->buffer_size = size;
+ gif->gif_data = data;
+
+ if (gif->lzw_ctx == NULL) {
+ lzw_result res = lzw_context_create(
+ (struct lzw_ctx **)&gif->lzw_ctx);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+ }
+
+ /* Check for sufficient data to be a GIF (6-byte header + 7-byte
+ * logical screen descriptor)
+ */
+ if (gif->buffer_size < GIF_STANDARD_HEADER_SIZE) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+
+ /* Get our current processing position */
+ gif_data = gif->gif_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->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 = GIF_INVALID_FRAME;
+
+ /* 6-byte GIF file header is:
+ *
+ * +0 3CHARS Signature ('GIF')
+ * +3 3CHARS Version ('87a' or '89a')
+ */
+ if (strncmp((const char *) gif_data, "GIF", 3) != 0) {
+ return GIF_DATA_ERROR;
+ }
+ gif_data += 3;
+
+ /* Ensure GIF reports version 87a or 89a */
+ /*
+ if ((strncmp(gif_data, "87a", 3) != 0) &&
+ (strncmp(gif_data, "89a", 3) != 0))
+ LOG(("Unknown GIF format - proceeding anyway"));
+ */
+ gif_data += 3;
+
+ /* 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
+ */
+ gif->width = gif_data[0] | (gif_data[1] << 8);
+ gif->height = gif_data[2] | (gif_data[3] << 8);
+ gif->global_colours = (gif_data[4] & GIF_COLOUR_TABLE_MASK);
+ gif->colour_table_size = (2 << (gif_data[4] & GIF_COLOUR_TABLE_SIZE_MASK));
+ gif->background_index = gif_data[5];
+ gif->aspect_ratio = gif_data[6];
+ gif->loop_count = 1;
+ gif_data += 7;
+
+ /* 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(GIF_MAX_COLOURS, sizeof(unsigned int));
+ gif->local_colour_table = calloc(GIF_MAX_COLOURS, sizeof(unsigned int));
+ if ((gif->global_colour_table == NULL) ||
+ (gif->local_colour_table == NULL)) {
+ gif_finalise(gif);
+ return GIF_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;
+
+ /* 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_STANDARD_HEADER_SIZE + 1)) {
+ if (gif_data[0] == GIF_TRAILER) {
+ return GIF_OK;
+ } else {
+ return GIF_INSUFFICIENT_DATA;
+ }
+ }
+
+ /* Initialise enough workspace for a frame */
+ if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) {
+ gif_finalise(gif);
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+ gif->frame_holders = 1;
+
+ /* Remember we've done this now */
+ gif->buffer_position = gif_data - gif->gif_data;
+ }
+
+ /* 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] == GIF_PROCESS_COLOURS) {
+ /* Check for a global colour map signified by bit 7 */
+ if (gif->global_colours) {
+ if (gif->buffer_size < (gif->colour_table_size * 3 + GIF_STANDARD_HEADER_SIZE)) {
+ return GIF_INSUFFICIENT_DATA;
+ }
+ for (index = 0; index < gif->colour_table_size; index++) {
+ /* 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.
+ */
+ unsigned char *entry = (unsigned char *) &gif->
+ global_colour_table[index];
+
+ entry[0] = gif_data[0]; /* r */
+ entry[1] = gif_data[1]; /* g */
+ entry[2] = gif_data[2]; /* b */
+ entry[3] = 0xff; /* a */
+
+ gif_data += 3;
+ }
+ gif->buffer_position = (gif_data - gif->gif_data);
+ } else {
+ /* Create a default colour table with the first two
+ * colours as black and white
+ */
+ unsigned int *entry = gif->global_colour_table;
+
+ entry[0] = 0x00000000;
+ /* Force Alpha channel to opaque */
+ ((unsigned char *) entry)[3] = 0xff;
+
+ entry[1] = 0xffffffff;
+ }
+ }
+
+ /* Repeatedly try to initialise frames */
+ while ((return_value = gif_initialise_frame(gif)) == GIF_WORKING);
+
+ /* If there was a memory error tell the caller */
+ if ((return_value == GIF_INSUFFICIENT_MEMORY) ||
+ (return_value == GIF_DATA_ERROR)) {
+ return return_value;
+ }
+
+ /* If we didn't have some frames then a GIF_INSUFFICIENT_DATA becomes a
+ * GIF_INSUFFICIENT_FRAME_DATA
+ */
+ if ((return_value == GIF_INSUFFICIENT_DATA) &&
+ (gif->frame_count_partial > 0)) {
+ return GIF_INSUFFICIENT_FRAME_DATA;
+ }
+
+ /* Return how many we got */
+ return return_value;
}
/* exported function documented in libnsgif.h */
gif_result gif_decode_frame(gif_animation *gif, unsigned int frame)
{
- return gif_internal_decode_frame(gif, frame, false);
+ return gif_internal_decode_frame(gif, frame, false);
}
/* exported function documented in libnsgif.h */
void gif_finalise(gif_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);
- }
-
- 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;
+ /* Release all our memory blocks */
+ if (gif->frame_image) {
+ assert(gif->bitmap_callbacks.bitmap_destroy);
+ gif->bitmap_callbacks.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;
}
--
NetSurf GIF Decoder
2 years, 5 months
libnsgif: branch master updated. release/0.2.1-35-g7253a5b
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/7253a5b36f0f07757b99...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/7253a5b36f0f07757b9989...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/7253a5b36f0f07757b998955...
The branch, master has been updated
via 7253a5b36f0f07757b99895572ceac0c95022a4e (commit)
via 1e61fac24f2adcd0c716c2946f7ab1998ab17adf (commit)
from f9b8f113aa8a51ef4a704c129a7e939800efdbc5 (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/libnsgif.git/commit/?id=7253a5b36f0f07757b...
commit 7253a5b36f0f07757b99895572ceac0c95022a4e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Remove unused one-code-at-a-time API.
diff --git a/src/lzw.c b/src/lzw.c
index 3a4bd7b..c865b8d 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -463,19 +463,8 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
}
/* Exported function, documented in lzw.h */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
- const uint8_t *restrict* const restrict data,
- uint32_t *restrict used)
-{
- *used = 0;
- *data = ctx->stack_base;
- return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
- lzw__write_pixels, used);
-}
-
-/* Exported function, documented in lzw.h */
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t ** const data,
+ const uint8_t *restrict *const restrict data,
uint32_t *restrict used)
{
*used = 0;
diff --git a/src/lzw.h b/src/lzw.h
index c442cff..a227163 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -77,21 +77,6 @@ lzw_result lzw_decode_init(
uint8_t minimum_code_size);
/**
- * Read a single LZW code and write into lzw context owned output buffer.
- *
- * Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
- *
- * \param[in] ctx LZW reading context, updated.
- * \param[out] data Returns pointer to array of output values.
- * \param[out] used Returns the number of values written to data.
- * \return LZW_OK on success, or appropriate error code otherwise.
- */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
- const uint8_t *restrict *const restrict data,
- uint32_t *restrict used);
-
-/**
* Read input codes until end of lzw context owned output buffer.
*
* Ensure anything in output is used before calling this, as anything
@@ -103,7 +88,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t ** const data,
+ const uint8_t *restrict *const restrict data,
uint32_t *restrict used);
/**
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=1e61fac24f2adcd0c7...
commit 1e61fac24f2adcd0c716c2946f7ab1998ab17adf
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Reduce overhead for clear code handling.
diff --git a/src/lzw.c b/src/lzw.c
index dd30d01..3a4bd7b 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -224,18 +224,39 @@ static inline lzw_result lzw__read_code(
/**
- * Clear LZW code table.
+ * Handle clear code.
*
- * \param[in] ctx LZW reading context, updated.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] code_out Returns next code after a clear code.
* \return LZW_OK or error code.
*/
-static inline void lzw__clear_table(
- struct lzw_ctx *ctx)
+static inline lzw_result lzw__handle_clear(
+ struct lzw_ctx *ctx,
+ uint32_t *code_out)
{
+ uint32_t code;
+
/* Reset table building context */
ctx->code_size = ctx->initial_code_size;
ctx->code_max = (1 << ctx->initial_code_size) - 1;
ctx->table_size = ctx->eoi_code + 1;
+
+ /* There might be a sequence of clear codes, so process them all */
+ do {
+ lzw_result res = lzw__read_code(&ctx->input,
+ ctx->code_size, &code);
+ if (res != LZW_OK) {
+ return res;
+ }
+ } while (code == ctx->clear_code);
+
+ /* The initial code must be from the initial table. */
+ if (code > ctx->clear_code) {
+ return LZW_BAD_ICODE;
+ }
+
+ *code_out = code;
+ return LZW_OK;
}
@@ -248,6 +269,8 @@ lzw_result lzw_decode_init(
uint8_t minimum_code_size)
{
struct lzw_table_entry *table = ctx->table;
+ lzw_result res;
+ uint32_t code;
if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
@@ -276,8 +299,19 @@ lzw_result lzw_decode_init(
table[i].count = 1;
}
- lzw__clear_table(ctx);
- ctx->prev_code = ctx->clear_code;
+ res = lzw__handle_clear(ctx, &code);
+ if (res != LZW_OK) {
+ return res;
+ }
+
+ /* Store details of this code as "previous code" to the context. */
+ ctx->prev_code_first = ctx->table[code].first;
+ ctx->prev_code_count = ctx->table[code].count;
+ ctx->prev_code = code;
+
+ /* Add code to context for immediate output. */
+ ctx->output_code = code;
+ ctx->output_left = 1;
return LZW_OK;
}
@@ -345,31 +379,27 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
return LZW_BAD_CODE;
} else if (code == ctx->clear_code) {
- lzw__clear_table(ctx);
- } else {
- if (ctx->prev_code == ctx->clear_code) {
- if (code > ctx->clear_code) {
- return LZW_BAD_ICODE;
- }
-
- } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
- uint32_t size = ctx->table_size;
- lzw__table_add_entry(ctx, (code < size) ?
- ctx->table[code].first :
- ctx->prev_code_first);
-
- /* Ensure code size is increased, if needed. */
- if (size == ctx->code_max &&
- ctx->code_size < LZW_CODE_MAX) {
- ctx->code_size++;
- ctx->code_max = (1 << ctx->code_size) - 1;
- }
+ res = lzw__handle_clear(ctx, &code);
+ if (res != LZW_OK) {
+ return res;
}
- *used += write_pixels(ctx, output, length, *used, code,
- ctx->table[code].count);
+ } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
+ uint32_t size = ctx->table_size;
+ lzw__table_add_entry(ctx, (code < size) ?
+ ctx->table[code].first :
+ ctx->prev_code_first);
+
+ /* Ensure code size is increased, if needed. */
+ if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
+ ctx->code_size++;
+ ctx->code_max = (1 << ctx->code_size) - 1;
+ }
}
+ *used += write_pixels(ctx, output, length, *used, code,
+ ctx->table[code].count);
+
/* Store details of this code as "previous code" to the context. */
ctx->prev_code_first = ctx->table[code].first;
ctx->prev_code_count = ctx->table[code].count;
-----------------------------------------------------------------------
Summary of changes:
src/lzw.c | 97 ++++++++++++++++++++++++++++++++++++-------------------------
src/lzw.h | 17 +----------
2 files changed, 59 insertions(+), 55 deletions(-)
diff --git a/src/lzw.c b/src/lzw.c
index dd30d01..c865b8d 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -224,18 +224,39 @@ static inline lzw_result lzw__read_code(
/**
- * Clear LZW code table.
+ * Handle clear code.
*
- * \param[in] ctx LZW reading context, updated.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] code_out Returns next code after a clear code.
* \return LZW_OK or error code.
*/
-static inline void lzw__clear_table(
- struct lzw_ctx *ctx)
+static inline lzw_result lzw__handle_clear(
+ struct lzw_ctx *ctx,
+ uint32_t *code_out)
{
+ uint32_t code;
+
/* Reset table building context */
ctx->code_size = ctx->initial_code_size;
ctx->code_max = (1 << ctx->initial_code_size) - 1;
ctx->table_size = ctx->eoi_code + 1;
+
+ /* There might be a sequence of clear codes, so process them all */
+ do {
+ lzw_result res = lzw__read_code(&ctx->input,
+ ctx->code_size, &code);
+ if (res != LZW_OK) {
+ return res;
+ }
+ } while (code == ctx->clear_code);
+
+ /* The initial code must be from the initial table. */
+ if (code > ctx->clear_code) {
+ return LZW_BAD_ICODE;
+ }
+
+ *code_out = code;
+ return LZW_OK;
}
@@ -248,6 +269,8 @@ lzw_result lzw_decode_init(
uint8_t minimum_code_size)
{
struct lzw_table_entry *table = ctx->table;
+ lzw_result res;
+ uint32_t code;
if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
@@ -276,8 +299,19 @@ lzw_result lzw_decode_init(
table[i].count = 1;
}
- lzw__clear_table(ctx);
- ctx->prev_code = ctx->clear_code;
+ res = lzw__handle_clear(ctx, &code);
+ if (res != LZW_OK) {
+ return res;
+ }
+
+ /* Store details of this code as "previous code" to the context. */
+ ctx->prev_code_first = ctx->table[code].first;
+ ctx->prev_code_count = ctx->table[code].count;
+ ctx->prev_code = code;
+
+ /* Add code to context for immediate output. */
+ ctx->output_code = code;
+ ctx->output_left = 1;
return LZW_OK;
}
@@ -345,31 +379,27 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
return LZW_BAD_CODE;
} else if (code == ctx->clear_code) {
- lzw__clear_table(ctx);
- } else {
- if (ctx->prev_code == ctx->clear_code) {
- if (code > ctx->clear_code) {
- return LZW_BAD_ICODE;
- }
-
- } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
- uint32_t size = ctx->table_size;
- lzw__table_add_entry(ctx, (code < size) ?
- ctx->table[code].first :
- ctx->prev_code_first);
-
- /* Ensure code size is increased, if needed. */
- if (size == ctx->code_max &&
- ctx->code_size < LZW_CODE_MAX) {
- ctx->code_size++;
- ctx->code_max = (1 << ctx->code_size) - 1;
- }
+ res = lzw__handle_clear(ctx, &code);
+ if (res != LZW_OK) {
+ return res;
}
- *used += write_pixels(ctx, output, length, *used, code,
- ctx->table[code].count);
+ } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
+ uint32_t size = ctx->table_size;
+ lzw__table_add_entry(ctx, (code < size) ?
+ ctx->table[code].first :
+ ctx->prev_code_first);
+
+ /* Ensure code size is increased, if needed. */
+ if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
+ ctx->code_size++;
+ ctx->code_max = (1 << ctx->code_size) - 1;
+ }
}
+ *used += write_pixels(ctx, output, length, *used, code,
+ ctx->table[code].count);
+
/* Store details of this code as "previous code" to the context. */
ctx->prev_code_first = ctx->table[code].first;
ctx->prev_code_count = ctx->table[code].count;
@@ -433,19 +463,8 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
}
/* Exported function, documented in lzw.h */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
- const uint8_t *restrict* const restrict data,
- uint32_t *restrict used)
-{
- *used = 0;
- *data = ctx->stack_base;
- return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
- lzw__write_pixels, used);
-}
-
-/* Exported function, documented in lzw.h */
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t ** const data,
+ const uint8_t *restrict *const restrict data,
uint32_t *restrict used)
{
*used = 0;
diff --git a/src/lzw.h b/src/lzw.h
index c442cff..a227163 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -77,21 +77,6 @@ lzw_result lzw_decode_init(
uint8_t minimum_code_size);
/**
- * Read a single LZW code and write into lzw context owned output buffer.
- *
- * Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
- *
- * \param[in] ctx LZW reading context, updated.
- * \param[out] data Returns pointer to array of output values.
- * \param[out] used Returns the number of values written to data.
- * \return LZW_OK on success, or appropriate error code otherwise.
- */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
- const uint8_t *restrict *const restrict data,
- uint32_t *restrict used);
-
-/**
* Read input codes until end of lzw context owned output buffer.
*
* Ensure anything in output is used before calling this, as anything
@@ -103,7 +88,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
- const uint8_t ** const data,
+ const uint8_t *restrict *const restrict data,
uint32_t *restrict used);
/**
--
NetSurf GIF Decoder
2 years, 5 months
libnsgif: branch master updated. release/0.2.1-33-gf9b8f11
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/f9b8f113aa8a51ef4a70...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/f9b8f113aa8a51ef4a704c...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/f9b8f113aa8a51ef4a704c12...
The branch, master has been updated
via f9b8f113aa8a51ef4a704c129a7e939800efdbc5 (commit)
from 0aeb0afe342d035ab32bac1d89b185f25d7acf32 (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/libnsgif.git/commit/?id=f9b8f113aa8a51ef4a...
commit f9b8f113aa8a51ef4a704c129a7e939800efdbc5
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Detect invalid code after clear code.
diff --git a/src/lzw.c b/src/lzw.c
index 4b521b6..dd30d01 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -347,8 +347,12 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
} else if (code == ctx->clear_code) {
lzw__clear_table(ctx);
} else {
- if (ctx->prev_code != ctx->clear_code &&
- ctx->table_size < LZW_TABLE_ENTRY_MAX) {
+ if (ctx->prev_code == ctx->clear_code) {
+ if (code > ctx->clear_code) {
+ return LZW_BAD_ICODE;
+ }
+
+ } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
uint32_t size = ctx->table_size;
lzw__table_add_entry(ctx, (code < size) ?
ctx->table[code].first :
-----------------------------------------------------------------------
Summary of changes:
src/lzw.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/lzw.c b/src/lzw.c
index 4b521b6..dd30d01 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -347,8 +347,12 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
} else if (code == ctx->clear_code) {
lzw__clear_table(ctx);
} else {
- if (ctx->prev_code != ctx->clear_code &&
- ctx->table_size < LZW_TABLE_ENTRY_MAX) {
+ if (ctx->prev_code == ctx->clear_code) {
+ if (code > ctx->clear_code) {
+ return LZW_BAD_ICODE;
+ }
+
+ } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
uint32_t size = ctx->table_size;
lzw__table_add_entry(ctx, (code < size) ?
ctx->table[code].first :
--
NetSurf GIF Decoder
2 years, 5 months
libnsgif: branch master updated. release/0.2.1-32-g0aeb0af
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libnsgif.git/shortlog/0aeb0afe342d035ab32b...
...commit http://git.netsurf-browser.org/libnsgif.git/commit/0aeb0afe342d035ab32bac...
...tree http://git.netsurf-browser.org/libnsgif.git/tree/0aeb0afe342d035ab32bac1d...
The branch, master has been updated
via 0aeb0afe342d035ab32bac1d89b185f25d7acf32 (commit)
via 2cff6fc0dc2f57816a73a37501e017cd252457f8 (commit)
via 6dc2f20b0a836750b98b0abba9dad6e54571ecad (commit)
via e2c52950885bf50271a990511ba7954736080735 (commit)
via decfeceb211697b18b2525ec533a95ed03418e1d (commit)
via db49e5b61beb1759469f3e6bd53850c6bc0a38ac (commit)
via 9dd7f040b1dffbe94b833aeede412054544709e8 (commit)
via 1abac9abe5a3f4a0f1b892b9aa2e036f5871b37d (commit)
via 39519291052243d5ab678be3da5ae12787941016 (commit)
via 45c0d2812d13d110b151e4b60787275572c65e69 (commit)
via c2074de22a8d77ff8e688a3f22132f6d0ee44c20 (commit)
via 602dcec85a1fc6f932bd32b49008354016c29bec (commit)
via f434088537e3c8a4bde836fcea3c159b44fe8983 (commit)
via 3ab1f9e45455ea4406168da9a5837bd0ce176542 (commit)
via 79d5d80a4dbe33d9e446aa637d7b905fac072f88 (commit)
via 270155287a0f2e7788253a38178efefb608ffdd5 (commit)
via def4cda3550f2f3e661fecf897447e0409e3ca15 (commit)
via b5b9d0524b2159278be8ebb18812b82872704c5d (commit)
via bf63b51e89777cccbc3e94e3c4ca082f5f82def2 (commit)
via c06164add4d44baad937ee9abcd110a46b7944ba (commit)
via f1e0c5c5bbb01ab9747b9bd0113e6598bcc5025a (commit)
via 87f9e081593d4ca373997f4a19578f13066e1941 (commit)
via 29f3d0fb22f9cdbd603e9561c9c8e000a2d6d5ef (commit)
via d8e8d3cceef907f798276014ebdfed7c370fb866 (commit)
from bba28df0cc0c75338a63645c6a55aebfebe91c74 (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/libnsgif.git/commit/?id=0aeb0afe342d035ab3...
commit 0aeb0afe342d035ab32bac1d89b185f25d7acf32
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Always read three bytes on fast path to avoid swtich.
diff --git a/src/lzw.c b/src/lzw.c
index a3034f8..4b521b6 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -41,7 +41,7 @@ struct lzw_read_ctx {
uint32_t data_sb_next; /**< Offset to sub-block size */
const uint8_t *sb_data; /**< Pointer to current sub-block in data */
- uint32_t sb_bit; /**< Current bit offset in sub-block */
+ size_t sb_bit; /**< Current bit offset in sub-block */
uint32_t sb_bit_count; /**< Bit count in sub-block */
};
@@ -165,29 +165,25 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
*/
static inline lzw_result lzw__read_code(
struct lzw_read_ctx *restrict ctx,
- uint8_t code_size,
+ uint32_t code_size,
uint32_t *restrict code_out)
{
uint32_t code = 0;
- uint8_t current_bit = ctx->sb_bit & 0x7;
- uint8_t byte_advance = (current_bit + code_size) >> 3;
+ uint32_t current_bit = ctx->sb_bit & 0x7;
- assert(byte_advance <= 2);
-
- if (ctx->sb_bit + code_size <= ctx->sb_bit_count) {
- /* Fast path: code fully inside this sub-block */
+ if (ctx->sb_bit + 24 <= ctx->sb_bit_count) {
+ /* Fast path: read three bytes from this sub-block */
const uint8_t *data = ctx->sb_data + (ctx->sb_bit >> 3);
- switch (byte_advance) {
- case 2: code |= data[2] << 16; /* Fall through */
- case 1: code |= data[1] << 8; /* Fall through */
- case 0: code |= data[0] << 0;
- }
+ code |= *data++ << 0;
+ code |= *data++ << 8;
+ code |= *data << 16;
ctx->sb_bit += code_size;
} else {
/* Slow path: code spans sub-blocks */
+ uint8_t byte_advance = (current_bit + code_size) >> 3;
uint8_t byte = 0;
- uint8_t bits_remaining_0 = (code_size < (8 - current_bit)) ?
- code_size : (8 - current_bit);
+ uint8_t bits_remaining_0 = (code_size < (8u - current_bit)) ?
+ code_size : (8u - current_bit);
uint8_t bits_remaining_1 = code_size - bits_remaining_0;
uint8_t bits_used[3] = {
[0] = bits_remaining_0,
@@ -195,6 +191,8 @@ static inline lzw_result lzw__read_code(
[2] = bits_remaining_1 - 8,
};
+ assert(byte_advance <= 2);
+
while (true) {
const uint8_t *data = ctx->sb_data;
lzw_result res;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=2cff6fc0dc2f57816a...
commit 2cff6fc0dc2f57816a73a37501e017cd252457f8
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Restrict pointers through code reader.
diff --git a/src/lzw.c b/src/lzw.c
index 4c4e09c..a3034f8 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -36,7 +36,7 @@
* Note that an individual LZW code can be split over up to three sub-blocks.
*/
struct lzw_read_ctx {
- const uint8_t *data; /**< Pointer to start of input data */
+ const uint8_t *restrict data; /**< Pointer to start of input data */
uint32_t data_len; /**< Input data length */
uint32_t data_sb_next; /**< Offset to sub-block size */
@@ -122,7 +122,7 @@ void lzw_context_destroy(struct lzw_ctx *ctx)
* \param[in] ctx LZW reading context, updated on success.
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
*/
-static lzw_result lzw__block_advance(struct lzw_read_ctx *ctx)
+static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
{
uint32_t block_size;
uint32_t next_block_pos = ctx->data_sb_next;
@@ -164,9 +164,9 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx *ctx)
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
*/
static inline lzw_result lzw__read_code(
- struct lzw_read_ctx *ctx,
+ struct lzw_read_ctx *restrict ctx,
uint8_t code_size,
- uint32_t *code_out)
+ uint32_t *restrict code_out)
{
uint32_t code = 0;
uint8_t current_bit = ctx->sb_bit & 0x7;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=6dc2f20b0a836750b9...
commit 6dc2f20b0a836750b98b0abba9dad6e54571ecad
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Constify table pointers in writer functions.
diff --git a/src/lzw.c b/src/lzw.c
index ece06e7..4c4e09c 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -400,7 +400,7 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
uint32_t left)
{
uint8_t *restrict output_pos = (uint8_t *)output + used;
- struct lzw_table_entry * const table = ctx->table;
+ const struct lzw_table_entry * const table = ctx->table;
uint32_t space = length - used;
uint32_t count = left;
@@ -416,13 +416,13 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
/* Skip over any values we don't have space for. */
for (unsigned i = left; i != 0; i--) {
- struct lzw_table_entry *entry = table + code;
+ const struct lzw_table_entry *entry = table + code;
code = entry->extends;
}
output_pos += count;
for (unsigned i = count; i != 0; i--) {
- struct lzw_table_entry *entry = table + code;
+ const struct lzw_table_entry *entry = table + code;
*--output_pos = entry->value;
code = entry->extends;
}
@@ -491,7 +491,7 @@ static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
uint32_t left)
{
uint32_t *restrict stack_pos = (uint32_t *)buffer + used;
- struct lzw_table_entry * const table = ctx->table;
+ const struct lzw_table_entry * const table = ctx->table;
uint32_t space = length - used;
uint32_t count = left;
@@ -506,13 +506,13 @@ static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
ctx->output_left = left;
for (unsigned i = left; i != 0; i--) {
- struct lzw_table_entry *entry = table + code;
+ const struct lzw_table_entry *entry = table + code;
code = entry->extends;
}
stack_pos += count;
for (unsigned i = count; i != 0; i--) {
- struct lzw_table_entry *entry = table + code;
+ const struct lzw_table_entry *entry = table + code;
--stack_pos;
if (entry->value != ctx->transparency_idx) {
*stack_pos = ctx->colour_map[entry->value];
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=e2c52950885bf50271...
commit e2c52950885bf50271a990511ba7954736080735
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
gif: Switch complex decoder over to continuous lzw API.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 3c49218..6d78dc2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -681,7 +681,7 @@ gif__decode_complex(gif_animation *gif,
}
break;
}
- res = lzw_decode(gif->lzw_ctx,
+ res = lzw_decode_continuous(gif->lzw_ctx,
&uncompressed, &available);
}
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=decfeceb211697b18b...
commit decfeceb211697b18b2525ec533a95ed03418e1d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Direct output into frame data, avoiding stack.
If the frame is non-interlaced, and has the same rowstride as the
full image, then we can decode lzw directly into the output image.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 752f8c2..3c49218 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -626,8 +626,8 @@ static gif_result gif__recover_previous_frame(const gif_animation *gif)
return GIF_OK;
}
-static inline gif_result
-gif__decode(gif_animation *gif,
+static gif_result
+gif__decode_complex(gif_animation *gif,
unsigned int frame,
unsigned int width,
unsigned int height,
@@ -701,6 +701,85 @@ gif__decode(gif_animation *gif,
return ret;
}
+static gif_result
+gif__decode_simple(gif_animation *gif,
+ unsigned int frame,
+ unsigned int height,
+ unsigned int offset_y,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
+{
+ unsigned int transparency_index;
+ uint32_t pixels = gif->width * height;
+ uint32_t written = 0;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
+ frame_data += (offset_y * gif->width);
+
+ while (pixels > 0) {
+ res = lzw_decode_map_continuous(gif->lzw_ctx,
+ transparency_index, colour_table,
+ frame_data, pixels, &written);
+ pixels -= written;
+ frame_data += written;
+ if (res != LZW_OK) {
+ /* Unexpected end of frame, try to recover */
+ if (res == LZW_OK_EOD) {
+ ret = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ }
+
+ if (pixels == 0) {
+ ret = GIF_OK;
+ }
+
+ return ret;
+}
+
+static inline gif_result
+gif__decode(gif_animation *gif,
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
+{
+ gif_result ret;
+
+ if (interlace == false && width == gif->width && offset_x == 0) {
+ ret = gif__decode_simple(gif, frame, height, offset_y,
+ minimum_code_size, frame_data, colour_table);
+ } else {
+ ret = gif__decode_complex(gif, frame, width, height,
+ offset_x, offset_y, interlace,
+ minimum_code_size, frame_data, colour_table);
+ }
+
+ return ret;
+}
+
/**
* decode a gif frame
*
diff --git a/src/lzw.c b/src/lzw.c
index 88ee060..ece06e7 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -85,6 +85,9 @@ struct lzw_ctx {
uint32_t output_code; /**< Code that has been partially output. */
uint32_t output_left; /**< Number of values left for output_code. */
+ uint32_t transparency_idx; /**< Index representing transparency. */
+ uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
+
/** Output value stack. */
uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
@@ -320,7 +323,7 @@ typedef uint32_t (*lzw_writer_fn)(
* \return LZW_OK on success, or appropriate error code otherwise.
*/
static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
- uint8_t *restrict output,
+ void *restrict output,
uint32_t length,
lzw_writer_fn write_pixels,
uint32_t *restrict used)
@@ -463,3 +466,88 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
return LZW_OK;
}
+
+/**
+ * Write colour mapped values for this code to the output stack.
+ *
+ * If there isn't enough space in the output stack, this function will write
+ * the as many as it can into the output. If `ctx->output_left > 0` after
+ * this call, then there is more data for this code left to output. The code
+ * is stored to the context as `ctx->output_code`.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this value.
+ * \return Number of pixel values written.
+ */
+static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
+ void *restrict buffer,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left)
+{
+ uint32_t *restrict stack_pos = (uint32_t *)buffer + used;
+ struct lzw_table_entry * const table = ctx->table;
+ uint32_t space = length - used;
+ uint32_t count = left;
+
+ if (count > space) {
+ left = count - space;
+ count = space;
+ } else {
+ left = 0;
+ }
+
+ ctx->output_code = code;
+ ctx->output_left = left;
+
+ for (unsigned i = left; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ code = entry->extends;
+ }
+
+ stack_pos += count;
+ for (unsigned i = count; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ --stack_pos;
+ if (entry->value != ctx->transparency_idx) {
+ *stack_pos = ctx->colour_map[entry->value];
+ }
+ code = entry->extends;
+ }
+
+ return count;
+}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+ uint32_t transparency_idx,
+ uint32_t *restrict colour_map,
+ uint32_t *restrict data,
+ uint32_t length,
+ uint32_t *restrict used)
+{
+ *used = 0;
+
+ ctx->transparency_idx = transparency_idx;
+ ctx->colour_map = colour_map;
+
+ if (ctx->output_left != 0) {
+ *used += lzw__write_pixels_map(ctx, data, length, *used,
+ ctx->output_code, ctx->output_left);
+ }
+
+ while (*used != sizeof(ctx->stack_base)) {
+ lzw_result res = lzw__decode(ctx, data, length,
+ lzw__write_pixels_map, used);
+ if (res != LZW_OK) {
+ return res;
+ }
+ }
+
+ return LZW_OK;
+}
diff --git a/src/lzw.h b/src/lzw.h
index 9f8f979..c442cff 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -106,4 +106,29 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
const uint8_t ** const data,
uint32_t *restrict used);
+/**
+ * Read LZW codes into client buffer, mapping output to colours.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
+ *
+ * For transparency to work correctly, the given client buffer must have
+ * the values from the previous frame. The transparency_idx should be a value
+ * of 256 or above, if the frame does not have transparency.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] transparency_idx Index representing transparency.
+ * \param[in] colour_map Index to pixel colour mapping
+ * \param[in] data Client buffer to fill with colour mapped values.
+ * \param[in] length Size of output array.
+ * \param[out] used Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+ uint32_t transparency_idx,
+ uint32_t *restrict colour_table,
+ uint32_t *restrict data,
+ uint32_t length,
+ uint32_t *restrict used);
+
#endif
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=db49e5b61beb175946...
commit db49e5b61beb1759469f3e6bd53850c6bc0a38ac
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
gif: Handle any uncompressed output before exiting due to error.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index e0d97c0..752f8c2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -672,8 +672,6 @@ gif__decode(gif_animation *gif,
const uint8_t *uncompressed;
unsigned row_available;
if (available == 0) {
- res = lzw_decode(gif->lzw_ctx,
- &uncompressed, &available);
if (res != LZW_OK) {
/* Unexpected end of frame, try to recover */
if (res == LZW_OK_EOD) {
@@ -683,6 +681,8 @@ gif__decode(gif_animation *gif,
}
break;
}
+ res = lzw_decode(gif->lzw_ctx,
+ &uncompressed, &available);
}
row_available = x < available ? x : available;
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=9dd7f040b1dffbe94b...
commit 9dd7f040b1dffbe94b833aeede412054544709e8
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Add function for decoding multiple LZW codes at a time.
diff --git a/src/lzw.c b/src/lzw.c
index 5308ff4..88ee060 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -437,3 +437,29 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
lzw__write_pixels, used);
}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *restrict used)
+{
+ *used = 0;
+ *data = ctx->stack_base;
+
+ if (ctx->output_left != 0) {
+ *used += lzw__write_pixels(ctx,
+ ctx->stack_base, sizeof(ctx->stack_base), *used,
+ ctx->output_code, ctx->output_left);
+ }
+
+ while (*used != sizeof(ctx->stack_base)) {
+ lzw_result res = lzw__decode(ctx,
+ ctx->stack_base, sizeof(ctx->stack_base),
+ lzw__write_pixels, used);
+ if (res != LZW_OK) {
+ return res;
+ }
+ }
+
+ return LZW_OK;
+}
diff --git a/src/lzw.h b/src/lzw.h
index dd0191e..9f8f979 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -91,4 +91,19 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict *const restrict data,
uint32_t *restrict used);
+/**
+ * Read input codes until end of lzw context owned output buffer.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] data Returns pointer to array of output values.
+ * \param[out] used Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *restrict used);
+
#endif
commitdiff http://git.netsurf-browser.org/libnsgif.git/commit/?id=1abac9abe5a3f4a0f1...
commit 1abac9abe5a3f4a0f1b892b9aa2e036f5871b37d
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
lzw: Add support for resumable output of a single code.
This allows handling of insufficient output buffer space.
diff --git a/src/lzw.c b/src/lzw.c
index 035882d..5308ff4 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -82,6 +82,9 @@ struct lzw_ctx {
uint32_t table_size; /**< Next position in table to fill. */
+ uint32_t output_code; /**< Code that has been partially output. */
+ uint32_t output_left; /**< Number of values left for output_code. */
+
/** Output value stack. */
uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
@@ -263,6 +266,8 @@ lzw_result lzw_decode_init(
ctx->clear_code = (1 << minimum_code_size) + 0;
ctx->eoi_code = (1 << minimum_code_size) + 1;
+ ctx->output_left = 0;
+
/* Initialise the standard table entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
table[i].first = i;
@@ -296,47 +301,28 @@ static inline void lzw__table_add_entry(
ctx->table_size++;
}
-/**
- * Write values for this code to the output stack.
- *
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[in] code LZW code to output values for.
- * \return Number of pixel values written.
- */
-static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
+typedef uint32_t (*lzw_writer_fn)(
+ struct lzw_ctx *ctx,
void *restrict output,
- uint32_t code)
-{
- uint8_t *restrict output_pos = (uint8_t *)output;
- struct lzw_table_entry * const table = ctx->table;
- uint32_t count = table[code].count;
-
- output_pos += count;
- for (unsigned i = count; i != 0; i--) {
- struct lzw_table_entry *entry = table + code;
- *--output_pos = entry->value;
- code = entry->extends;
- }
-
- return count;
-}
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left);
/**
- * Fill the LZW stack with decompressed data
+ * Get the next LZW code and write its value(s) to output buffer.
*
- * Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
- *
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[out] used Returns the number of values written.
- * Use with `stack_base_out` value from previous
- * lzw_decode_init() call.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] write_pixels Function for writing pixels to output.
+ * \param[in,out] used Number of values written. Updated on exit.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
uint8_t *restrict output,
+ uint32_t length,
+ lzw_writer_fn write_pixels,
uint32_t *restrict used)
{
lzw_result res;
@@ -375,7 +361,8 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
}
}
- *used += lzw__write_pixels(ctx, output, code);
+ *used += write_pixels(ctx, output, length, *used, code,
+ ctx->table[code].count);
}
/* Store details of this code as "previous code" to the context. */
@@ -386,6 +373,60 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
return LZW_OK;
}
+/**
+ * Write values for this code to the output stack.
+ *
+ * If there isn't enough space in the output stack, this function will write
+ * the as many as it can into the output. If `ctx->output_left > 0` after
+ * this call, then there is more data for this code left to output. The code
+ * is stored to the context as `ctx->output_code`.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this value.
+ * \return Number of pixel values written.
+ */
+static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
+ void *restrict output,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left)
+{
+ uint8_t *restrict output_pos = (uint8_t *)output + used;
+ struct lzw_table_entry * const table = ctx->table;
+ uint32_t space = length - used;
+ uint32_t count = left;
+
+ if (count > space) {
+ left = count - space;
+ count = space;
+ } else {
+ left = 0;
+ }
+
+ ctx->output_code = code;
+ ctx->output_left = left;
+
+ /* Skip over any values we don't have space for. */
+ for (unsigned i = left; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ code = entry->extends;
+ }
+
+ output_pos += count;
+ for (unsigned i = count; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ *--output_pos = entry->value;
+ code = entry->extends;
+ }
+
+ return count;
+}
+
/* Exported function, documented in lzw.h */
lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict* const restrict data,
@@ -393,5 +434,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
{
*used = 0;
*data = ctx->stack_base;
- return lzw__decode(ctx, ctx->stack_base, used);
+ return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
+ lzw__write_pixels, used);
}
-----------------------------------------------------------------------
Summary of changes:
src/libnsgif.c | 221 +++++++++++++++++++--------
src/lzw.c | 456 ++++++++++++++++++++++++++++++++++++++------------------
src/lzw.h | 69 ++++++---
3 files changed, 524 insertions(+), 222 deletions(-)
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 512ebfe..6d78dc2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -42,6 +42,9 @@
/** Transparent colour */
#define GIF_TRANSPARENT_COLOUR 0x00
+/** No transparency */
+#define GIF_NO_TRANSPARENCY (0xFFFFFFFFu)
+
/* GIF Flags */
#define GIF_FRAME_COMBINE 1
#define GIF_FRAME_CLEAR 2
@@ -623,6 +626,160 @@ static gif_result gif__recover_previous_frame(const gif_animation *gif)
return GIF_OK;
}
+static gif_result
+gif__decode_complex(gif_animation *gif,
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
+{
+ unsigned int transparency_index;
+ uint32_t available = 0;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
+ for (unsigned int y = 0; y < height; y++) {
+ unsigned int x;
+ unsigned int decode_y;
+ unsigned int *frame_scanline;
+
+ if (interlace) {
+ decode_y = gif_interlaced_line(height, y) + offset_y;
+ } else {
+ decode_y = y + offset_y;
+ }
+ frame_scanline = frame_data + offset_x + (decode_y * gif->width);
+
+ 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 = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ res = lzw_decode_continuous(gif->lzw_ctx,
+ &uncompressed, &available);
+ }
+
+ row_available = x < available ? x : available;
+ x -= row_available;
+ available -= row_available;
+ while (row_available-- > 0) {
+ register unsigned int colour;
+ colour = *uncompressed++;
+ if (colour != transparency_index) {
+ *frame_scanline = colour_table[colour];
+ }
+ frame_scanline++;
+ }
+ }
+ }
+ return ret;
+}
+
+static gif_result
+gif__decode_simple(gif_animation *gif,
+ unsigned int frame,
+ unsigned int height,
+ unsigned int offset_y,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
+{
+ unsigned int transparency_index;
+ uint32_t pixels = gif->width * height;
+ uint32_t written = 0;
+ gif_result ret = GIF_OK;
+ lzw_result res;
+
+ /* Initialise the LZW decoding */
+ res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
+ gif->buffer_size, gif->buffer_position,
+ minimum_code_size);
+ if (res != LZW_OK) {
+ return gif_error_from_lzw(res);
+ }
+
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
+ frame_data += (offset_y * gif->width);
+
+ while (pixels > 0) {
+ res = lzw_decode_map_continuous(gif->lzw_ctx,
+ transparency_index, colour_table,
+ frame_data, pixels, &written);
+ pixels -= written;
+ frame_data += written;
+ if (res != LZW_OK) {
+ /* Unexpected end of frame, try to recover */
+ if (res == LZW_OK_EOD) {
+ ret = GIF_OK;
+ } else {
+ ret = gif_error_from_lzw(res);
+ }
+ break;
+ }
+ }
+
+ if (pixels == 0) {
+ ret = GIF_OK;
+ }
+
+ return ret;
+}
+
+static inline gif_result
+gif__decode(gif_animation *gif,
+ unsigned int frame,
+ unsigned int width,
+ unsigned int height,
+ unsigned int offset_x,
+ unsigned int offset_y,
+ unsigned int interlace,
+ uint8_t minimum_code_size,
+ unsigned int *restrict frame_data,
+ unsigned int *restrict colour_table)
+{
+ gif_result ret;
+
+ if (interlace == false && width == gif->width && offset_x == 0) {
+ ret = gif__decode_simple(gif, frame, height, offset_y,
+ minimum_code_size, frame_data, colour_table);
+ } else {
+ ret = gif__decode_complex(gif, frame, width, height,
+ offset_x, offset_y, interlace,
+ minimum_code_size, frame_data, colour_table);
+ }
+
+ return ret;
+}
+
/**
* decode a gif frame
*
@@ -643,11 +800,8 @@ gif_internal_decode_frame(gif_animation *gif,
unsigned int flags, colour_table_size, interlace;
unsigned int *colour_table;
unsigned int *frame_data = 0; // Set to 0 for no warnings
- unsigned int *frame_scanline;
unsigned int save_buffer_position;
unsigned int return_value = 0;
- unsigned int x, y, decode_y, burst_bytes;
- register unsigned char colour;
/* Ensure this frame is supposed to be decoded */
if (gif->frames[frame].display == false) {
@@ -801,10 +955,6 @@ gif_internal_decode_frame(gif_animation *gif,
/* If we are clearing the image we just clear, if not decode */
if (!clear_image) {
- lzw_result res;
- const uint8_t *stack_base;
- const uint8_t *stack_pos;
-
/* Ensure we have enough data for a 1-byte LZW code size +
* 1-byte gif trailer
*/
@@ -868,62 +1018,15 @@ gif_internal_decode_frame(gif_animation *gif,
gif->decoded_frame = frame;
gif->buffer_position = (gif_data - gif->gif_data) + 1;
- /* Initialise the LZW decoding */
- res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
- gif->buffer_size, gif->buffer_position,
- gif_data[0], &stack_base, &stack_pos);
- if (res != LZW_OK) {
- return gif_error_from_lzw(res);
- }
-
- /* Decompress the data */
- for (y = 0; y < height; y++) {
- if (interlace) {
- decode_y = gif_interlaced_line(height, y) + offset_y;
- } else {
- decode_y = y + offset_y;
- }
- frame_scanline = frame_data + offset_x + (decode_y * gif->width);
-
- /* Rather than decoding pixel by pixel, we try to burst
- * out streams of data to remove the need for end-of
- * data checks every pixel.
- */
- x = width;
- while (x > 0) {
- burst_bytes = (stack_pos - stack_base);
- if (burst_bytes > 0) {
- if (burst_bytes > x) {
- burst_bytes = x;
- }
- x -= burst_bytes;
- while (burst_bytes-- > 0) {
- colour = *--stack_pos;
- if (((gif->frames[frame].transparency) &&
- (colour != gif->frames[frame].transparency_index)) ||
- (!gif->frames[frame].transparency)) {
- *frame_scanline = colour_table[colour];
- }
- frame_scanline++;
- }
- } else {
- res = lzw_decode(gif->lzw_ctx, &stack_pos);
- if (res != LZW_OK) {
- /* Unexpected end of frame, try to recover */
- if (res == LZW_OK_EOD) {
- return_value = GIF_OK;
- } else {
- return_value = gif_error_from_lzw(res);
- }
- goto gif_decode_frame_exit;
- }
- }
- }
- }
+ return_value = gif__decode(gif, frame, width, height,
+ offset_x, offset_y, interlace, gif_data[0],
+ frame_data, colour_table);
} else {
/* Clear our frame */
if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) {
+ unsigned int y;
for (y = 0; y < height; y++) {
+ unsigned int *frame_scanline;
frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width);
if (gif->frames[frame].transparency) {
memset(frame_scanline,
diff --git a/src/lzw.c b/src/lzw.c
index 1f85496..4b521b6 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -4,6 +4,7 @@
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2017 Michael Drake <michael.drake(a)codethink.co.uk>
+ * Copyright 2021 Michael Drake <tlsa(a)netsurf-browser.org>
*/
#include <assert.h>
@@ -20,6 +21,8 @@
* Decoder for GIF LZW data.
*/
+/** Maximum number of lzw table entries. */
+#define LZW_TABLE_ENTRY_MAX (1u << LZW_CODE_MAX)
/**
* Context for reading LZW data.
@@ -33,55 +36,63 @@
* Note that an individual LZW code can be split over up to three sub-blocks.
*/
struct lzw_read_ctx {
- const uint8_t *data; /**< Pointer to start of input data */
+ const uint8_t *restrict data; /**< Pointer to start of input data */
uint32_t data_len; /**< Input data length */
uint32_t data_sb_next; /**< Offset to sub-block size */
const uint8_t *sb_data; /**< Pointer to current sub-block in data */
- uint32_t sb_bit; /**< Current bit offset in sub-block */
+ size_t sb_bit; /**< Current bit offset in sub-block */
uint32_t sb_bit_count; /**< Bit count in sub-block */
};
/**
- * LZW dictionary entry.
+ * LZW table entry.
*
- * Records in the dictionary are composed of 1 or more entries.
- * Entries point to previous entries which can be followed to compose
+ * Records in the table are composed of 1 or more entries.
+ * Entries refer to the entry they extend which can be followed to compose
* the complete record. To compose the record in reverse order, take
- * the `last_value` from each entry, and move to the previous entry.
- * If the previous_entry's index is < the current clear_code, then it
+ * the `value` from each entry, and move to the entry it extends.
+ * If the extended entries index is < the current clear_code, then it
* is the last entry in the record.
*/
-struct lzw_dictionary_entry {
- uint8_t last_value; /**< Last value for record ending at entry. */
- uint8_t first_value; /**< First value for entry's record. */
- uint16_t previous_entry; /**< Offset in dictionary to previous entry. */
+struct lzw_table_entry {
+ uint8_t value; /**< Last value for record ending at entry. */
+ uint8_t first; /**< First value in entry's entire record. */
+ uint16_t count; /**< Count of values in this entry's record. */
+ uint16_t extends; /**< Offset in table to previous entry. */
};
/**
* LZW decompression context.
*/
struct lzw_ctx {
- /** Input reading context */
- struct lzw_read_ctx input;
+ struct lzw_read_ctx input; /**< Input reading context */
- uint32_t previous_code; /**< Code read from input previously. */
- uint32_t previous_code_first; /**< First value of previous code. */
+ uint32_t prev_code; /**< Code read from input previously. */
+ uint32_t prev_code_first; /**< First value of previous code. */
+ uint32_t prev_code_count; /**< Total values for previous code. */
- uint32_t initial_code_size; /**< Starting LZW code size. */
- uint32_t current_code_size; /**< Current LZW code size. */
- uint32_t current_code_size_max; /**< Max code value for current size. */
+ uint32_t initial_code_size; /**< Starting LZW code size. */
+
+ uint32_t code_size; /**< Current LZW code size. */
+ uint32_t code_max; /**< Max code value for current code size. */
uint32_t clear_code; /**< Special Clear code value */
uint32_t eoi_code; /**< Special End of Information code value */
- uint32_t current_entry; /**< Next position in table to fill. */
+ uint32_t table_size; /**< Next position in table to fill. */
+
+ uint32_t output_code; /**< Code that has been partially output. */
+ uint32_t output_left; /**< Number of values left for output_code. */
+
+ uint32_t transparency_idx; /**< Index representing transparency. */
+ uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
/** Output value stack. */
- uint8_t stack_base[1 << LZW_CODE_MAX];
+ uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
- /** LZW decode dictionary. Generated during decode. */
- struct lzw_dictionary_entry table[1 << LZW_CODE_MAX];
+ /** LZW code table. Generated during decode. */
+ struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX];
};
@@ -111,7 +122,7 @@ void lzw_context_destroy(struct lzw_ctx *ctx)
* \param[in] ctx LZW reading context, updated on success.
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
*/
-static lzw_result lzw__block_advance(struct lzw_read_ctx *ctx)
+static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
{
uint32_t block_size;
uint32_t next_block_pos = ctx->data_sb_next;
@@ -152,31 +163,27 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx *ctx)
* \param[out] code_out Returns an LZW code on success.
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
*/
-static inline lzw_result lzw__next_code(
- struct lzw_read_ctx *ctx,
- uint8_t code_size,
- uint32_t *code_out)
+static inline lzw_result lzw__read_code(
+ struct lzw_read_ctx *restrict ctx,
+ uint32_t code_size,
+ uint32_t *restrict code_out)
{
uint32_t code = 0;
- uint8_t current_bit = ctx->sb_bit & 0x7;
- uint8_t byte_advance = (current_bit + code_size) >> 3;
-
- assert(byte_advance <= 2);
+ uint32_t current_bit = ctx->sb_bit & 0x7;
- if (ctx->sb_bit + code_size <= ctx->sb_bit_count) {
- /* Fast path: code fully inside this sub-block */
+ if (ctx->sb_bit + 24 <= ctx->sb_bit_count) {
+ /* Fast path: read three bytes from this sub-block */
const uint8_t *data = ctx->sb_data + (ctx->sb_bit >> 3);
- switch (byte_advance) {
- case 2: code |= data[2] << 16; /* Fall through */
- case 1: code |= data[1] << 8; /* Fall through */
- case 0: code |= data[0] << 0;
- }
+ code |= *data++ << 0;
+ code |= *data++ << 8;
+ code |= *data << 16;
ctx->sb_bit += code_size;
} else {
/* Slow path: code spans sub-blocks */
+ uint8_t byte_advance = (current_bit + code_size) >> 3;
uint8_t byte = 0;
- uint8_t bits_remaining_0 = (code_size < (8 - current_bit)) ?
- code_size : (8 - current_bit);
+ uint8_t bits_remaining_0 = (code_size < (8u - current_bit)) ?
+ code_size : (8u - current_bit);
uint8_t bits_remaining_1 = code_size - bits_remaining_0;
uint8_t bits_used[3] = {
[0] = bits_remaining_0,
@@ -184,6 +191,8 @@ static inline lzw_result lzw__next_code(
[2] = bits_remaining_1 - 8,
};
+ assert(byte_advance <= 2);
+
while (true) {
const uint8_t *data = ctx->sb_data;
lzw_result res;
@@ -215,48 +224,18 @@ static inline lzw_result lzw__next_code(
/**
- * Clear LZW code dictionary.
+ * Clear LZW code table.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[out] stack_pos_out Returns current stack position.
+ * \param[in] ctx LZW reading context, updated.
* \return LZW_OK or error code.
*/
-static lzw_result lzw__clear_codes(
- struct lzw_ctx *ctx,
- const uint8_t ** const stack_pos_out)
+static inline void lzw__clear_table(
+ struct lzw_ctx *ctx)
{
- uint32_t code;
- uint8_t *stack_pos;
-
- /* Reset dictionary building context */
- ctx->current_code_size = ctx->initial_code_size + 1;
- ctx->current_code_size_max = (1 << ctx->current_code_size) - 1;
- ctx->current_entry = (1 << ctx->initial_code_size) + 2;
-
- /* There might be a sequence of clear codes, so process them all */
- do {
- lzw_result res = lzw__next_code(&ctx->input,
- ctx->current_code_size, &code);
- if (res != LZW_OK) {
- return res;
- }
- } while (code == ctx->clear_code);
-
- /* The initial code must be from the initial dictionary. */
- if (code > ctx->clear_code) {
- return LZW_BAD_ICODE;
- }
-
- /* Record this initial code as "previous" code, needed during decode. */
- ctx->previous_code = code;
- ctx->previous_code_first = code;
-
- /* Reset the stack, and add first non-clear code added as first item. */
- stack_pos = ctx->stack_base;
- *stack_pos++ = code;
-
- *stack_pos_out = stack_pos;
- return LZW_OK;
+ /* Reset table building context */
+ ctx->code_size = ctx->initial_code_size;
+ ctx->code_max = (1 << ctx->initial_code_size) - 1;
+ ctx->table_size = ctx->eoi_code + 1;
}
@@ -266,13 +245,11 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t code_size,
- const uint8_t ** const stack_base_out,
- const uint8_t ** const stack_pos_out)
+ uint8_t minimum_code_size)
{
- struct lzw_dictionary_entry *table = ctx->table;
+ struct lzw_table_entry *table = ctx->table;
- if (code_size >= LZW_CODE_MAX) {
+ if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
}
@@ -284,98 +261,291 @@ lzw_result lzw_decode_init(
ctx->input.sb_bit = 0;
ctx->input.sb_bit_count = 0;
- /* Initialise the dictionary building context */
- ctx->initial_code_size = code_size;
+ /* Initialise the table building context */
+ ctx->initial_code_size = minimum_code_size + 1;
- ctx->clear_code = (1 << code_size) + 0;
- ctx->eoi_code = (1 << code_size) + 1;
+ ctx->clear_code = (1 << minimum_code_size) + 0;
+ ctx->eoi_code = (1 << minimum_code_size) + 1;
- /* Initialise the standard dictionary entries */
+ ctx->output_left = 0;
+
+ /* Initialise the standard table entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
- table[i].first_value = i;
- table[i].last_value = i;
+ table[i].first = i;
+ table[i].value = i;
+ table[i].count = 1;
}
- *stack_base_out = ctx->stack_base;
- return lzw__clear_codes(ctx, stack_pos_out);
+ lzw__clear_table(ctx);
+ ctx->prev_code = ctx->clear_code;
+
+ return LZW_OK;
}
+/**
+ * Create new table entry.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] code Last value code for new table entry.
+ */
+static inline void lzw__table_add_entry(
+ struct lzw_ctx *ctx,
+ uint32_t code)
+{
+ struct lzw_table_entry *entry = &ctx->table[ctx->table_size];
-/* Exported function, documented in lzw.h */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
- const uint8_t ** const stack_pos_out)
+ entry->value = code;
+ entry->first = ctx->prev_code_first;
+ entry->count = ctx->prev_code_count + 1;
+ entry->extends = ctx->prev_code;
+
+ ctx->table_size++;
+}
+
+typedef uint32_t (*lzw_writer_fn)(
+ struct lzw_ctx *ctx,
+ void *restrict output,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left);
+
+/**
+ * Get the next LZW code and write its value(s) to output buffer.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] write_pixels Function for writing pixels to output.
+ * \param[in,out] used Number of values written. Updated on exit.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
+ void *restrict output,
+ uint32_t length,
+ lzw_writer_fn write_pixels,
+ uint32_t *restrict used)
{
lzw_result res;
- uint32_t code_new;
- uint32_t code_out;
- uint8_t last_value;
- uint8_t *stack_pos = ctx->stack_base;
- uint32_t clear_code = ctx->clear_code;
- uint32_t current_entry = ctx->current_entry;
- struct lzw_dictionary_entry * const table = ctx->table;
+ uint32_t code;
/* Get a new code from the input */
- res = lzw__next_code(&ctx->input, ctx->current_code_size, &code_new);
+ res = lzw__read_code(&ctx->input, ctx->code_size, &code);
if (res != LZW_OK) {
return res;
}
/* Handle the new code */
- if (code_new == clear_code) {
- /* Got Clear code */
- return lzw__clear_codes(ctx, stack_pos_out);
-
- } else if (code_new == ctx->eoi_code) {
+ if (code == ctx->eoi_code) {
/* Got End of Information code */
return LZW_EOI_CODE;
- } else if (code_new > current_entry) {
+ } else if (code > ctx->table_size) {
/* Code is invalid */
return LZW_BAD_CODE;
- } else if (code_new < current_entry) {
- /* Code is in table */
- code_out = code_new;
- last_value = table[code_new].first_value;
+ } else if (code == ctx->clear_code) {
+ lzw__clear_table(ctx);
+ } else {
+ if (ctx->prev_code != ctx->clear_code &&
+ ctx->table_size < LZW_TABLE_ENTRY_MAX) {
+ uint32_t size = ctx->table_size;
+ lzw__table_add_entry(ctx, (code < size) ?
+ ctx->table[code].first :
+ ctx->prev_code_first);
+
+ /* Ensure code size is increased, if needed. */
+ if (size == ctx->code_max &&
+ ctx->code_size < LZW_CODE_MAX) {
+ ctx->code_size++;
+ ctx->code_max = (1 << ctx->code_size) - 1;
+ }
+ }
+
+ *used += write_pixels(ctx, output, length, *used, code,
+ ctx->table[code].count);
+ }
+
+ /* Store details of this code as "previous code" to the context. */
+ ctx->prev_code_first = ctx->table[code].first;
+ ctx->prev_code_count = ctx->table[code].count;
+ ctx->prev_code = code;
+
+ return LZW_OK;
+}
+
+/**
+ * Write values for this code to the output stack.
+ *
+ * If there isn't enough space in the output stack, this function will write
+ * the as many as it can into the output. If `ctx->output_left > 0` after
+ * this call, then there is more data for this code left to output. The code
+ * is stored to the context as `ctx->output_code`.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this value.
+ * \return Number of pixel values written.
+ */
+static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
+ void *restrict output,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left)
+{
+ uint8_t *restrict output_pos = (uint8_t *)output + used;
+ const struct lzw_table_entry * const table = ctx->table;
+ uint32_t space = length - used;
+ uint32_t count = left;
+
+ if (count > space) {
+ left = count - space;
+ count = space;
} else {
- /* Code not in table */
- *stack_pos++ = ctx->previous_code_first;
- code_out = ctx->previous_code;
- last_value = ctx->previous_code_first;
+ left = 0;
}
- /* Add to the dictionary, only if there's space */
- if (current_entry < (1 << LZW_CODE_MAX)) {
- struct lzw_dictionary_entry *entry = table + current_entry;
- entry->last_value = last_value;
- entry->first_value = ctx->previous_code_first;
- entry->previous_entry = ctx->previous_code;
- ctx->current_entry++;
+ ctx->output_code = code;
+ ctx->output_left = left;
+
+ /* Skip over any values we don't have space for. */
+ for (unsigned i = left; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ code = entry->extends;
+ }
+
+ output_pos += count;
+ for (unsigned i = count; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ *--output_pos = entry->value;
+ code = entry->extends;
+ }
+
+ return count;
+}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict* const restrict data,
+ uint32_t *restrict used)
+{
+ *used = 0;
+ *data = ctx->stack_base;
+ return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
+ lzw__write_pixels, used);
+}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *restrict used)
+{
+ *used = 0;
+ *data = ctx->stack_base;
+
+ if (ctx->output_left != 0) {
+ *used += lzw__write_pixels(ctx,
+ ctx->stack_base, sizeof(ctx->stack_base), *used,
+ ctx->output_code, ctx->output_left);
}
- /* Ensure code size is increased, if needed. */
- if (current_entry == ctx->current_code_size_max) {
- if (ctx->current_code_size < LZW_CODE_MAX) {
- ctx->current_code_size++;
- ctx->current_code_size_max =
- (1 << ctx->current_code_size) - 1;
+ while (*used != sizeof(ctx->stack_base)) {
+ lzw_result res = lzw__decode(ctx,
+ ctx->stack_base, sizeof(ctx->stack_base),
+ lzw__write_pixels, used);
+ if (res != LZW_OK) {
+ return res;
}
}
- /* Store details of this code as "previous code" to the context. */
- ctx->previous_code_first = table[code_new].first_value;
- ctx->previous_code = code_new;
-
- /* Put rest of data for this code on output stack.
- * Note, in the case of "code not in table", the last entry of the
- * current code has already been placed on the stack above. */
- while (code_out > clear_code) {
- struct lzw_dictionary_entry *entry = table + code_out;
- *stack_pos++ = entry->last_value;
- code_out = entry->previous_entry;
+ return LZW_OK;
+}
+
+/**
+ * Write colour mapped values for this code to the output stack.
+ *
+ * If there isn't enough space in the output stack, this function will write
+ * the as many as it can into the output. If `ctx->output_left > 0` after
+ * this call, then there is more data for this code left to output. The code
+ * is stored to the context as `ctx->output_code`.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this value.
+ * \return Number of pixel values written.
+ */
+static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
+ void *restrict buffer,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left)
+{
+ uint32_t *restrict stack_pos = (uint32_t *)buffer + used;
+ const struct lzw_table_entry * const table = ctx->table;
+ uint32_t space = length - used;
+ uint32_t count = left;
+
+ if (count > space) {
+ left = count - space;
+ count = space;
+ } else {
+ left = 0;
+ }
+
+ ctx->output_code = code;
+ ctx->output_left = left;
+
+ for (unsigned i = left; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ code = entry->extends;
+ }
+
+ stack_pos += count;
+ for (unsigned i = count; i != 0; i--) {
+ const struct lzw_table_entry *entry = table + code;
+ --stack_pos;
+ if (entry->value != ctx->transparency_idx) {
+ *stack_pos = ctx->colour_map[entry->value];
+ }
+ code = entry->extends;
+ }
+
+ return count;
+}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+ uint32_t transparency_idx,
+ uint32_t *restrict colour_map,
+ uint32_t *restrict data,
+ uint32_t length,
+ uint32_t *restrict used)
+{
+ *used = 0;
+
+ ctx->transparency_idx = transparency_idx;
+ ctx->colour_map = colour_map;
+
+ if (ctx->output_left != 0) {
+ *used += lzw__write_pixels_map(ctx, data, length, *used,
+ ctx->output_code, ctx->output_left);
+ }
+
+ while (*used != sizeof(ctx->stack_base)) {
+ lzw_result res = lzw__decode(ctx, data, length,
+ lzw__write_pixels_map, used);
+ if (res != LZW_OK) {
+ return res;
+ }
}
- *stack_pos++ = table[code_out].last_value;
- *stack_pos_out = stack_pos;
return LZW_OK;
}
diff --git a/src/lzw.h b/src/lzw.h
index 385b425..c442cff 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -65,11 +65,8 @@ void lzw_context_destroy(
* \param[in] compressed_data_len Byte length of compressed data.
* \param[in] compressed_data_pos Start position in data. Must be position
* of a size byte at sub-block start.
- * \param[in] code_size The initial LZW code size to use.
+ * \param[in] minimum_code_size The LZW Minimum Code Size.
* \param[out] stack_base_out Returns base of decompressed data stack.
- * \param[out] stack_pos_out Returns current stack position.
- * There are `stack_pos_out - stack_base_out`
- * current stack entries.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_init(
@@ -77,29 +74,61 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t code_size,
- const uint8_t ** const stack_base_out,
- const uint8_t ** const stack_pos_out);
+ uint8_t minimum_code_size);
/**
- * Fill the LZW stack with decompressed data
+ * Read a single LZW code and write into lzw context owned output buffer.
*
- * Ensure anything on the stack is used before calling this, as anything
- * on the stack before this call will be trampled.
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
*
- * Caller does not own `stack_pos_out`.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] data Returns pointer to array of output values.
+ * \param[out] used Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict *const restrict data,
+ uint32_t *restrict used);
+
+/**
+ * Read input codes until end of lzw context owned output buffer.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[out] stack_pos_out Returns current stack position.
- * Use with `stack_base_out` value from previous
- * lzw_decode_init() call.
- * There are `stack_pos_out - stack_base_out`
- * current stack entries.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] data Returns pointer to array of output values.
+ * \param[out] used Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-lzw_result lzw_decode(
- struct lzw_ctx *ctx,
- const uint8_t ** const stack_pos_out);
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *restrict used);
+/**
+ * Read LZW codes into client buffer, mapping output to colours.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
+ *
+ * For transparency to work correctly, the given client buffer must have
+ * the values from the previous frame. The transparency_idx should be a value
+ * of 256 or above, if the frame does not have transparency.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] transparency_idx Index representing transparency.
+ * \param[in] colour_map Index to pixel colour mapping
+ * \param[in] data Client buffer to fill with colour mapped values.
+ * \param[in] length Size of output array.
+ * \param[out] used Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+ uint32_t transparency_idx,
+ uint32_t *restrict colour_table,
+ uint32_t *restrict data,
+ uint32_t length,
+ uint32_t *restrict used);
#endif
--
NetSurf GIF Decoder
2 years, 5 months
netsurf: branch master updated. release/3.10-130-g81c40ab
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/81c40ab7c29e6bc59f4c1...
...commit http://git.netsurf-browser.org/netsurf.git/commit/81c40ab7c29e6bc59f4c10f...
...tree http://git.netsurf-browser.org/netsurf.git/tree/81c40ab7c29e6bc59f4c10fa1...
The branch, master has been updated
via 81c40ab7c29e6bc59f4c10fa1655fd7e4a47a1ec (commit)
from 99a3d04d5587e7908e0f2b41c71c297999a4e267 (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=81c40ab7c29e6bc59f4...
commit 81c40ab7c29e6bc59f4c10fa1655fd7e4a47a1ec
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Amiga: Fix codesets.library conversion when string specified as zero length
diff --git a/frontends/amiga/utf8.c b/frontends/amiga/utf8.c
index 2a4643b..fabb1e2 100755
--- a/frontends/amiga/utf8.c
+++ b/frontends/amiga/utf8.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2020 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008-2021 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -35,7 +35,7 @@
static nserror ami_utf8_codesets(const char *string, size_t len, char **result, bool to_local)
{
char *out;
- ULONG utf8_tag, local_tag;
+ ULONG utf8_tag = CSA_SourceCodeset, local_tag = CSA_DestCodeset, len_tag = CSA_SourceLen;
static struct codeset *utf8_cs = NULL;
static struct codeset *local_cs = NULL;
@@ -54,13 +54,12 @@ static nserror ami_utf8_codesets(const char *string, size_t len, char **result,
if(to_local == false) {
local_tag = CSA_SourceCodeset;
utf8_tag = CSA_DestCodeset;
- } else {
- utf8_tag = CSA_SourceCodeset;
- local_tag = CSA_DestCodeset;
}
+ if(len == 0) len_tag = TAG_IGNORE;
+
out = CodesetsConvertStr(CSA_Source, string,
- CSA_SourceLen, len,
+ len_tag, len,
#ifdef __amigaos4__
local_tag, local_cs,
#endif
-----------------------------------------------------------------------
Summary of changes:
frontends/amiga/utf8.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/frontends/amiga/utf8.c b/frontends/amiga/utf8.c
index 2a4643b..fabb1e2 100755
--- a/frontends/amiga/utf8.c
+++ b/frontends/amiga/utf8.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2020 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008-2021 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -35,7 +35,7 @@
static nserror ami_utf8_codesets(const char *string, size_t len, char **result, bool to_local)
{
char *out;
- ULONG utf8_tag, local_tag;
+ ULONG utf8_tag = CSA_SourceCodeset, local_tag = CSA_DestCodeset, len_tag = CSA_SourceLen;
static struct codeset *utf8_cs = NULL;
static struct codeset *local_cs = NULL;
@@ -54,13 +54,12 @@ static nserror ami_utf8_codesets(const char *string, size_t len, char **result,
if(to_local == false) {
local_tag = CSA_SourceCodeset;
utf8_tag = CSA_DestCodeset;
- } else {
- utf8_tag = CSA_SourceCodeset;
- local_tag = CSA_DestCodeset;
}
+ if(len == 0) len_tag = TAG_IGNORE;
+
out = CodesetsConvertStr(CSA_Source, string,
- CSA_SourceLen, len,
+ len_tag, len,
#ifdef __amigaos4__
local_tag, local_cs,
#endif
--
NetSurf Browser
2 years, 5 months