From e71691bae890040b83cfd54a2d9a1097d5026866 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Fri, 6 May 2011 20:40:09 +0000 Subject: Merge branches/jmb/content-factory to trunk svn path=/trunk/netsurf/; revision=12283 --- image/bmp.c | 225 ++++++++++++++++++++++++----- image/bmp.h | 26 +--- image/gif.c | 322 ++++++++++++++++++++++++++++++----------- image/gif.h | 28 +--- image/ico.c | 222 ++++++++++++++++++++++------ image/ico.h | 31 ++-- image/image.c | 100 +++++++++++++ image/image.h | 31 ++++ image/jpeg.c | 142 +++++++++++++++++- image/jpeg.h | 27 ++-- image/mng.c | 430 ++++++++++++++++++++++++++++++++++++++++--------------- image/mng.h | 33 +---- image/nssprite.c | 149 +++++++++++++++++-- image/nssprite.h | 20 +-- image/png.c | 287 ++++++++++++++++++++++++++++--------- image/png.h | 40 ++---- image/rsvg.c | 189 +++++++++++++++++++++--- image/rsvg.h | 34 ++--- image/svg.c | 188 +++++++++++++++++++++--- image/svg.h | 33 ++--- image/webp.c | 136 +++++++++++++++++- image/webp.h | 22 ++- 22 files changed, 2099 insertions(+), 616 deletions(-) create mode 100644 image/image.c create mode 100644 image/image.h (limited to 'image') diff --git a/image/bmp.c b/image/bmp.c index 1e8ec5be9..dbb4d9796 100644 --- a/image/bmp.c +++ b/image/bmp.c @@ -31,13 +31,40 @@ #include #include "utils/config.h" #include "content/content_protected.h" +#include "content/hlcache.h" #include "desktop/plotters.h" #include "image/bitmap.h" #include "image/bmp.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/utils.h" +typedef struct nsbmp_content { + struct content base; + + bmp_image *bmp; /** BMP image data */ +} nsbmp_content; + +static nserror nsbmp_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static nserror nsbmp_create_bmp_data(nsbmp_content *bmp); +static bool nsbmp_convert(struct content *c); +static void nsbmp_destroy(struct content *c); +static bool nsbmp_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static bool nsbmp_redraw_tiled(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour, + bool repeat_x, bool repeat_y); +static nserror nsbmp_clone(const struct content *old, struct content **newc); +static content_type nsbmp_content_type(lwc_string *mime_type); + +static void *nsbmp_bitmap_create(int width, int height, unsigned int bmp_state); + /* The Bitmap callbacks function table; * necessary for interaction with nsbmplib. */ @@ -49,25 +76,131 @@ bmp_bitmap_callback_vt bmp_bitmap_callbacks = { .bitmap_get_bpp = bitmap_get_bpp }; -bool nsbmp_create(struct content *c, const struct http_parameter *params) +static const content_handler nsbmp_content_handler = { + nsbmp_create, + NULL, + nsbmp_convert, + NULL, + nsbmp_destroy, + NULL, + NULL, + NULL, + nsbmp_redraw, + nsbmp_redraw_tiled, + NULL, + NULL, + nsbmp_clone, + NULL, + nsbmp_content_type, + false +}; + +static const char *nsbmp_types[] = { + "application/bmp", + "application/preview", + "application/x-bmp", + "application/x-win-bitmap", + "image/bmp", + "image/ms-bmp", + "image/x-bitmap", + "image/x-bmp", + "image/x-ms-bmp", + "image/x-win-bitmap", + "image/x-windows-bmp", + "image/x-xbitmap" +}; + +static lwc_string *nsbmp_mime_types[NOF_ELEMENTS(nsbmp_types)]; + +nserror nsbmp_init(void) { + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(nsbmp_mime_types); i++) { + lerror = lwc_intern_string(nsbmp_types[i], + strlen(nsbmp_types[i]), + &nsbmp_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(nsbmp_mime_types[i], + &nsbmp_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + nsbmp_fini(); + + return error; +} + +void nsbmp_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(nsbmp_mime_types); i++) { + if (nsbmp_mime_types[i] != NULL) + lwc_string_unref(nsbmp_mime_types[i]); + } +} + +nserror nsbmp_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + nsbmp_content *bmp; + nserror error; + + bmp = talloc_zero(0, nsbmp_content); + if (bmp == NULL) + return NSERROR_NOMEM; + + error = content__init(&bmp->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(bmp); + return error; + } + + error = nsbmp_create_bmp_data(bmp); + if (error != NSERROR_OK) { + talloc_free(bmp); + return error; + } + + *c = (struct content *) bmp; + + return NSERROR_OK; +} + +nserror nsbmp_create_bmp_data(nsbmp_content *bmp) +{ union content_msg_data msg_data; - c->data.bmp.bmp = calloc(sizeof(struct bmp_image), 1); - if (!c->data.bmp.bmp) { + bmp->bmp = calloc(sizeof(struct bmp_image), 1); + if (bmp->bmp == NULL) { msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&bmp->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } - bmp_create(c->data.bmp.bmp, &bmp_bitmap_callbacks); - return true; -} + bmp_create(bmp->bmp, &bmp_bitmap_callbacks); + + return NSERROR_OK; +} bool nsbmp_convert(struct content *c) { + nsbmp_content *bmp = (nsbmp_content *) c; bmp_result res; - bmp_image *bmp; union content_msg_data msg_data; uint32_t swidth; const char *data; @@ -75,12 +208,10 @@ bool nsbmp_convert(struct content *c) char title[100]; /* set the bmp data */ - bmp = c->data.bmp.bmp; - data = content__get_source_data(c, &size); /* analyse the BMP */ - res = bmp_analyse(bmp, size, (unsigned char *) data); + res = bmp_analyse(bmp->bmp, size, (unsigned char *) data); switch (res) { case BMP_OK: break; @@ -96,17 +227,18 @@ bool nsbmp_convert(struct content *c) } /* Store our content width and description */ - c->width = bmp->width; - c->height = bmp->height; + c->width = bmp->bmp->width; + c->height = bmp->bmp->height; LOG(("BMP width %u height %u", c->width, c->height)); snprintf(title, sizeof(title), messages_get("BMPTitle"), c->width, c->height, size); content__set_title(c, title); - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - c->size += (swidth * bmp->height) + 16 + 44; + swidth = bmp->bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bmp->bitmap) * + bmp->bmp->width; + c->size += (swidth * bmp->bmp->height) + 16 + 44; /* exit as a success */ - c->bitmap = bmp->bitmap; + c->bitmap = bmp->bmp->bitmap; bitmap_modified(c->bitmap); content_set_ready(c); @@ -122,11 +254,14 @@ bool nsbmp_redraw(struct content *c, int x, int y, int width, int height, const struct rect *clip, float scale, colour background_colour) { + nsbmp_content *bmp = (nsbmp_content *) c; - if (!c->data.bmp.bmp->decoded) - if (bmp_decode(c->data.bmp.bmp) != BMP_OK) + if (bmp->bmp->decoded == false) + if (bmp_decode(bmp->bmp) != BMP_OK) return false; - c->bitmap = c->data.bmp.bmp->bitmap; + + c->bitmap = bmp->bmp->bitmap; + return plot.bitmap(x, y, width, height, c->bitmap, background_colour, BITMAPF_NONE); } @@ -137,13 +272,14 @@ bool nsbmp_redraw_tiled(struct content *c, int x, int y, float scale, colour background_colour, bool repeat_x, bool repeat_y) { + nsbmp_content *bmp = (nsbmp_content *) c; bitmap_flags_t flags = BITMAPF_NONE; - if (!c->data.bmp.bmp->decoded) - if (bmp_decode(c->data.bmp.bmp) != BMP_OK) + if (bmp->bmp->decoded == false) + if (bmp_decode(bmp->bmp) != BMP_OK) return false; - c->bitmap = c->data.bmp.bmp->bitmap; + c->bitmap = bmp->bmp->bitmap; if (repeat_x) flags |= BITMAPF_REPEAT_X; @@ -157,27 +293,52 @@ bool nsbmp_redraw_tiled(struct content *c, int x, int y, void nsbmp_destroy(struct content *c) { - bmp_finalise(c->data.bmp.bmp); - free(c->data.bmp.bmp); -} + nsbmp_content *bmp = (nsbmp_content *) c; + bmp_finalise(bmp->bmp); + free(bmp->bmp); +} -bool nsbmp_clone(const struct content *old, struct content *new_content) +nserror nsbmp_clone(const struct content *old, struct content **newc) { + nsbmp_content *new_bmp; + nserror error; + + new_bmp = talloc_zero(0, nsbmp_content); + if (new_bmp == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &new_bmp->base); + if (error != NSERROR_OK) { + content_destroy(&new_bmp->base); + return error; + } + /* We "clone" the old content by replaying creation and conversion */ - if (nsbmp_create(new_content, NULL) == false) - return false; + error = nsbmp_create_bmp_data(new_bmp); + if (error != NSERROR_OK) { + content_destroy(&new_bmp->base); + return error; + } if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (nsbmp_convert(new_content) == false) - return false; + if (nsbmp_convert(&new_bmp->base) == false) { + content_destroy(&new_bmp->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) new_bmp; + + return NSERROR_OK; } +content_type nsbmp_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; +} /** * Callback for libnsbmp; forwards the call to bitmap_create() diff --git a/image/bmp.h b/image/bmp.h index cb386f6d1..885b94344 100644 --- a/image/bmp.h +++ b/image/bmp.h @@ -31,29 +31,15 @@ #include #include "image/bitmap.h" -struct content; -struct bitmap; -struct http_parameter; -struct rect; +extern bmp_bitmap_callback_vt bmp_bitmap_callbacks; /** Only to be used by ICO code. */ -struct content_bmp_data { - bmp_image *bmp; /** BMP image data */ -}; +nserror nsbmp_init(void); +void nsbmp_fini(void); -extern bmp_bitmap_callback_vt bmp_bitmap_callbacks; /** Only to be used by ICO code. */ +#else -bool nsbmp_create(struct content *c, const struct http_parameter *params); -bool nsbmp_convert(struct content *c); -void nsbmp_destroy(struct content *c); -bool nsbmp_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool nsbmp_redraw_tiled(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour, - bool repeat_x, bool repeat_y); -bool nsbmp_clone(const struct content *old, struct content *new_content); -void *nsbmp_bitmap_create(int width, int height, unsigned int bmp_state); +#define nsbmp_init() NSERROR_OK +#define nsbmp_fini() ((void) 0) #endif /* WITH_BMP */ diff --git a/image/gif.c b/image/gif.c index e449db345..20a67424e 100644 --- a/image/gif.c +++ b/image/gif.c @@ -38,6 +38,7 @@ #include #include "utils/config.h" #include "content/content_protected.h" +#include "content/hlcache.h" #include "desktop/options.h" #include "desktop/plotters.h" #include "image/bitmap.h" @@ -45,8 +46,34 @@ #include "utils/log.h" #include "utils/messages.h" #include "utils/schedule.h" +#include "utils/talloc.h" #include "utils/utils.h" +typedef struct nsgif_content { + struct content base; + + struct gif_animation *gif; /**< GIF animation data */ + int current_frame; /**< current frame to display [0...(max-1)] */ +} nsgif_content; + +static nserror nsgif_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static nserror nsgif_create_gif_data(nsgif_content *c); +static bool nsgif_convert(struct content *c); +static void nsgif_destroy(struct content *c); +static bool nsgif_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static bool nsgif_redraw_tiled(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour, + bool repeat_x, bool repeat_y); +static nserror nsgif_clone(const struct content *old, struct content **newc); +static content_type nsgif_content_type(lwc_string *mime_type); + +static void *nsgif_bitmap_create(int width, int height); static void nsgif_invalidate(void *bitmap, void *private_word); static void nsgif_animate(void *p); static gif_result nsgif_get_frame(struct content *c); @@ -63,39 +90,131 @@ gif_bitmap_callback_vt gif_bitmap_callbacks = { .bitmap_modified = bitmap_modified }; +static const content_handler nsgif_content_handler = { + nsgif_create, + NULL, + nsgif_convert, + NULL, + nsgif_destroy, + NULL, + NULL, + NULL, + nsgif_redraw, + nsgif_redraw_tiled, + NULL, + NULL, + nsgif_clone, + NULL, + nsgif_content_type, + false +}; + +static const char *nsgif_types[] = { + "image/gif" +}; -bool nsgif_create(struct content *c, const struct http_parameter *params) +static lwc_string *nsgif_mime_types[NOF_ELEMENTS(nsgif_types)]; + +nserror nsgif_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(nsgif_mime_types); i++) { + lerror = lwc_intern_string(nsgif_types[i], + strlen(nsgif_types[i]), + &nsgif_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(nsgif_mime_types[i], + &nsgif_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + nsgif_fini(); + + return error; +} + +void nsgif_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(nsgif_mime_types); i++) { + if (nsgif_mime_types[i] != NULL) + lwc_string_unref(nsgif_mime_types[i]); + } +} + +nserror nsgif_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + nsgif_content *result; + nserror error; + + result = talloc_zero(0, nsgif_content); + if (result == NULL) + return NSERROR_NOMEM; + + error = content__init(&result->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(result); + return error; + } + + error = nsgif_create_gif_data(result); + if (error != NSERROR_OK) { + talloc_free(result); + return error; + } + + *c = (struct content *) result; + + return NSERROR_OK; +} + +nserror nsgif_create_gif_data(nsgif_content *c) { union content_msg_data msg_data; + /* Initialise our data structure */ - c->data.gif.gif = calloc(sizeof(gif_animation), 1); - if (!c->data.gif.gif) { + c->gif = calloc(sizeof(gif_animation), 1); + if (c->gif == NULL) { msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } - gif_create(c->data.gif.gif, &gif_bitmap_callbacks); - return true; + gif_create(c->gif, &gif_bitmap_callbacks); + return NSERROR_OK; } bool nsgif_convert(struct content *c) { + nsgif_content *gif = (nsgif_content *) c; int res; - struct gif_animation *gif; union content_msg_data msg_data; const char *data; unsigned long size; char title[100]; /* Get the animation */ - gif = c->data.gif.gif; - data = content__get_source_data(c, &size); /* Initialise the GIF */ do { - res = gif_initialise(gif, size, (unsigned char *) data); + res = gif_initialise(gif->gif, size, (unsigned char *) data); if (res != GIF_OK && res != GIF_WORKING && res != GIF_INSUFFICIENT_FRAME_DATA) { switch (res) { @@ -114,30 +233,31 @@ bool nsgif_convert(struct content *c) } while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA); /* Abort on bad GIFs */ - if ((gif->frame_count_partial == 0) || (gif->width == 0) || - (gif->height == 0)) { + if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) || + (gif->gif->height == 0)) { msg_data.error = messages_get("BadGIF"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } /* Store our content width and description */ - c->width = gif->width; - c->height = gif->height; + c->width = gif->gif->width; + c->height = gif->gif->height; snprintf(title, sizeof(title), messages_get("GIFTitle"), c->width, c->height, size); content__set_title(c, title); - c->size += (gif->width * gif->height * 4) + 16 + 44; + c->size += (gif->gif->width * gif->gif->height * 4) + 16 + 44; /* Schedule the animation if we have one */ - c->data.gif.current_frame = 0; - if (gif->frame_count_partial > 1) - schedule(gif->frames[0].frame_delay, nsgif_animate, c); + gif->current_frame = 0; + if (gif->gif->frame_count_partial > 1) + schedule(gif->gif->frames[0].frame_delay, nsgif_animate, c); else - bitmap_set_suspendable(gif->frame_image, gif, nsgif_invalidate); + bitmap_set_suspendable(gif->gif->frame_image, gif->gif, + nsgif_invalidate); /* Exit as a success */ - c->bitmap = gif->frame_image; + c->bitmap = gif->gif->frame_image; content_set_ready(c); content_set_done(c); /* Done: update status bar */ @@ -156,10 +276,12 @@ bool nsgif_redraw(struct content *c, int x, int y, int width, int height, const struct rect *clip, float scale, colour background_colour) { - if (c->data.gif.current_frame != c->data.gif.gif->decoded_frame) + nsgif_content *gif = (nsgif_content *) c; + + if (gif->current_frame != gif->gif->decoded_frame) if (nsgif_get_frame(c) != GIF_OK) return false; - c->bitmap = c->data.gif.gif->frame_image; + c->bitmap = gif->gif->frame_image; if ((width == -1) && (height == -1)) return true; return plot.bitmap(x, y, width, height, c->bitmap, @@ -172,13 +294,14 @@ bool nsgif_redraw_tiled(struct content *c, int x, int y, float scale, colour background_colour, bool repeat_x, bool repeat_y) { + nsgif_content *gif = (nsgif_content *) c; bitmap_flags_t flags = BITMAPF_NONE; - if (c->data.gif.current_frame != c->data.gif.gif->decoded_frame) + if (gif->current_frame != gif->gif->decoded_frame) if (nsgif_get_frame(c) != GIF_OK) return false; - c->bitmap = c->data.gif.gif->frame_image; + c->bitmap = gif->gif->frame_image; if (repeat_x) flags |= BITMAPF_REPEAT_X; @@ -191,28 +314,54 @@ bool nsgif_redraw_tiled(struct content *c, int x, int y, void nsgif_destroy(struct content *c) { + nsgif_content *gif = (nsgif_content *) c; + /* Free all the associated memory buffers */ schedule_remove(nsgif_animate, c); - gif_finalise(c->data.gif.gif); - free(c->data.gif.gif); + gif_finalise(gif->gif); + free(gif->gif); } -bool nsgif_clone(const struct content *old, struct content *new_content) +nserror nsgif_clone(const struct content *old, struct content **newc) { + nsgif_content *gif; + nserror error; + + gif = talloc_zero(0, nsgif_content); + if (gif == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &gif->base); + if (error != NSERROR_OK) { + content_destroy(&gif->base); + return error; + } + /* Simply replay creation and conversion of content */ - if (nsgif_create(new_content, NULL) == false) - return false; + error = nsgif_create_gif_data(gif); + if (error != NSERROR_OK) { + content_destroy(&gif->base); + return error; + } if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (nsgif_convert(new_content) == false) - return false; + if (nsgif_convert(&gif->base) == false) { + content_destroy(&gif->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) gif; + + return NSERROR_OK; } +content_type nsgif_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; +} /** * Updates the GIF bitmap to display the current frame @@ -221,18 +370,19 @@ bool nsgif_clone(const struct content *old, struct content *new_content) */ gif_result nsgif_get_frame(struct content *c) { + nsgif_content *gif = (nsgif_content *) c; int previous_frame, current_frame, frame; gif_result res = GIF_OK; - current_frame = c->data.gif.current_frame; + current_frame = gif->current_frame; if (!option_animate_images) current_frame = 0; - if (current_frame < c->data.gif.gif->decoded_frame) + if (current_frame < gif->gif->decoded_frame) previous_frame = 0; else - previous_frame = c->data.gif.gif->decoded_frame + 1; + previous_frame = gif->gif->decoded_frame + 1; for (frame = previous_frame; frame <= current_frame; frame++) - res = gif_decode_frame(c->data.gif.gif, frame); + res = gif_decode_frame(gif->gif, frame); return res; } @@ -245,105 +395,105 @@ gif_result nsgif_get_frame(struct content *c) */ void nsgif_animate(void *p) { - struct content *c = p; + nsgif_content *gif = p; union content_msg_data data; - struct gif_animation *gif; int delay; int f; /* Advance by a frame, updating the loop count accordingly */ - gif = c->data.gif.gif; - c->data.gif.current_frame++; - if (c->data.gif.current_frame == (int)gif->frame_count_partial) { - c->data.gif.current_frame = 0; + gif->current_frame++; + if (gif->current_frame == (int)gif->gif->frame_count_partial) { + gif->current_frame = 0; /* A loop count of 0 has a special meaning of infinite */ - if (gif->loop_count != 0) { - gif->loop_count--; - if (gif->loop_count == 0) { - c->data.gif.current_frame = - gif->frame_count_partial - 1; - gif->loop_count = -1; + if (gif->gif->loop_count != 0) { + gif->gif->loop_count--; + if (gif->gif->loop_count == 0) { + gif->current_frame = + gif->gif->frame_count_partial - 1; + gif->gif->loop_count = -1; } } } /* Continue animating if we should */ - if (gif->loop_count >= 0) { - delay = gif->frames[c->data.gif.current_frame].frame_delay; + if (gif->gif->loop_count >= 0) { + delay = gif->gif->frames[gif->current_frame].frame_delay; if (delay < option_minimum_gif_delay) delay = option_minimum_gif_delay; - schedule(delay, nsgif_animate, c); + schedule(delay, nsgif_animate, gif); } if ((!option_animate_images) || - (!gif->frames[c->data.gif.current_frame].display)) + (!gif->gif->frames[gif->current_frame].display)) return; /* area within gif to redraw */ - f = c->data.gif.current_frame; - data.redraw.x = gif->frames[f].redraw_x; - data.redraw.y = gif->frames[f].redraw_y; - data.redraw.width = gif->frames[f].redraw_width; - data.redraw.height = gif->frames[f].redraw_height; + f = gif->current_frame; + data.redraw.x = gif->gif->frames[f].redraw_x; + data.redraw.y = gif->gif->frames[f].redraw_y; + data.redraw.width = gif->gif->frames[f].redraw_width; + data.redraw.height = gif->gif->frames[f].redraw_height; /* redraw background (true) or plot on top (false) */ - if (c->data.gif.current_frame > 0) { - data.redraw.full_redraw = gif->frames[f - 1].redraw_required; + if (gif->current_frame > 0) { + data.redraw.full_redraw = + gif->gif->frames[f - 1].redraw_required; /* previous frame needed clearing: expand the redraw area to * cover it */ if (data.redraw.full_redraw) { if (data.redraw.x > - (int)(gif->frames[f - 1].redraw_x)) { + (int)(gif->gif->frames[f - 1].redraw_x)) { data.redraw.width += data.redraw.x - - gif->frames[f - 1].redraw_x; - data.redraw.x = gif->frames[f - 1].redraw_x; + gif->gif->frames[f - 1].redraw_x; + data.redraw.x = + gif->gif->frames[f - 1].redraw_x; } if (data.redraw.y > - (int)(gif->frames[f - 1].redraw_y)) { + (int)(gif->gif->frames[f - 1].redraw_y)) { data.redraw.height += (data.redraw.y - - gif->frames[f - 1].redraw_y); - data.redraw.y = gif->frames[f - 1].redraw_y; + gif->gif->frames[f - 1].redraw_y); + data.redraw.y = + gif->gif->frames[f - 1].redraw_y; } - if ((int)(gif->frames[f - 1].redraw_x + - gif->frames[f - 1].redraw_width) > + if ((int)(gif->gif->frames[f - 1].redraw_x + + gif->gif->frames[f - 1].redraw_width) > (data.redraw.x + data.redraw.width)) data.redraw.width = - gif->frames[f - 1].redraw_x - - data.redraw.x + - gif->frames[f - 1].redraw_width; - if ((int)(gif->frames[f - 1].redraw_y + - gif->frames[f - 1].redraw_height) > + gif->gif->frames[f - 1].redraw_x - + data.redraw.x + + gif->gif->frames[f - 1].redraw_width; + if ((int)(gif->gif->frames[f - 1].redraw_y + + gif->gif->frames[f - 1].redraw_height) > (data.redraw.y + data.redraw.height)) data.redraw.height = - gif->frames[f - 1].redraw_y - - data.redraw.y + - gif->frames[f - 1]. - redraw_height; + gif->gif->frames[f - 1].redraw_y - + data.redraw.y + + gif->gif->frames[f - 1].redraw_height; } } else { /* do advanced check */ if ((data.redraw.x == 0) && (data.redraw.y == 0) && - (data.redraw.width == (int)(gif->width)) && - (data.redraw.height == (int)(gif->height))) { - data.redraw.full_redraw = !gif->frames[f].opaque; + (data.redraw.width == (int)(gif->gif->width)) && + (data.redraw.height == (int)(gif->gif->height))) { + data.redraw.full_redraw = !gif->gif->frames[f].opaque; } else { data.redraw.full_redraw = true; data.redraw.x = 0; data.redraw.y = 0; - data.redraw.width = gif->width; - data.redraw.height = gif->height; + data.redraw.width = gif->gif->width; + data.redraw.height = gif->gif->height; } } /* other data */ - data.redraw.object = c; + data.redraw.object = (struct content *) gif; data.redraw.object_x = 0; data.redraw.object_y = 0; - data.redraw.object_width = c->width; - data.redraw.object_height = c->height; + data.redraw.object_width = gif->base.width; + data.redraw.object_height = gif->base.height; - content_broadcast(c, CONTENT_MSG_REDRAW, data); + content_broadcast(&gif->base, CONTENT_MSG_REDRAW, data); } diff --git a/image/gif.h b/image/gif.h index a9f16d489..4ed06d09e 100644 --- a/image/gif.h +++ b/image/gif.h @@ -30,27 +30,13 @@ #include #include -struct content; -struct http_parameter; -struct rect; - -struct content_gif_data { - struct gif_animation *gif; /**< GIF animation data */ - int current_frame; /**< current frame to display [0...(max-1)] */ -}; - -bool nsgif_create(struct content *c, const struct http_parameter *params); -bool nsgif_convert(struct content *c); -void nsgif_destroy(struct content *c); -bool nsgif_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool nsgif_redraw_tiled(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour, - bool repeat_x, bool repeat_y); -bool nsgif_clone(const struct content *old, struct content *new_content); -void *nsgif_bitmap_create(int width, int height); +nserror nsgif_init(void); +void nsgif_fini(void); + +#else + +#define nsgif_init() NSERROR_OK +#define nsgif_fini() ((void) 0) #endif /* WITH_GIF */ diff --git a/image/ico.c b/image/ico.c index a753f470b..0397c5c7f 100644 --- a/image/ico.c +++ b/image/ico.c @@ -33,42 +33,164 @@ #include "content/hlcache.h" #include "desktop/plotters.h" #include "image/bitmap.h" +#include "image/bmp.h" #include "image/ico.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/utils.h" -bool nsico_create(struct content *c, const struct http_parameter *params) +typedef struct nsico_content { + struct content base; + + struct ico_collection *ico; /** ICO collection data */ +} nsico_content; + +static nserror nsico_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static nserror nsico_create_ico_data(nsico_content *c); +static bool nsico_convert(struct content *c); +static void nsico_destroy(struct content *c); +static bool nsico_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static bool nsico_redraw_tiled(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour, + bool repeat_x, bool repeat_y); +static nserror nsico_clone(const struct content *old, struct content **newc); +static content_type nsico_content_type(lwc_string *mime_type); + +static const content_handler nsico_content_handler = { + nsico_create, + NULL, + nsico_convert, + NULL, + nsico_destroy, + NULL, + NULL, + NULL, + nsico_redraw, + nsico_redraw_tiled, + NULL, + NULL, + nsico_clone, + NULL, + nsico_content_type, + false +}; + +static const char *nsico_types[] = { + "application/ico", + "application/x-ico", + "image/ico", + "image/vnd.microsoft.icon", + "image/x-icon" +}; + +static lwc_string *nsico_mime_types[NOF_ELEMENTS(nsico_types)]; + +nserror nsico_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(nsico_mime_types); i++) { + lerror = lwc_intern_string(nsico_types[i], + strlen(nsico_types[i]), + &nsico_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(nsico_mime_types[i], + &nsico_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + nsico_fini(); + + return error; +} + +void nsico_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(nsico_mime_types); i++) { + if (nsico_mime_types[i] != NULL) + lwc_string_unref(nsico_mime_types[i]); + } +} + +nserror nsico_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + nsico_content *result; + nserror error; + + result = talloc_zero(0, nsico_content); + if (result == NULL) + return NSERROR_NOMEM; + + error = content__init(&result->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(result); + return error; + } + + error = nsico_create_ico_data(result); + if (error != NSERROR_OK) { + talloc_free(result); + return error; + } + + *c = (struct content *) result; + + return NSERROR_OK; +} + +nserror nsico_create_ico_data(nsico_content *c) { union content_msg_data msg_data; - c->data.ico.ico = calloc(sizeof(ico_collection), 1); - if (!c->data.ico.ico) { + + c->ico = calloc(sizeof(ico_collection), 1); + if (c->ico == NULL) { msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } - ico_collection_create(c->data.ico.ico, &bmp_bitmap_callbacks); - return true; + ico_collection_create(c->ico, &bmp_bitmap_callbacks); + return NSERROR_OK; } bool nsico_convert(struct content *c) { + nsico_content *ico = (nsico_content *) c; struct bmp_image *bmp; bmp_result res; - ico_collection *ico; union content_msg_data msg_data; const char *data; unsigned long size; char title[100]; /* set the ico data */ - ico = c->data.ico.ico; - data = content__get_source_data(c, &size); /* analyse the ico */ - res = ico_analyse(ico, size, (unsigned char *) data); + res = ico_analyse(ico->ico, size, (unsigned char *) data); switch (res) { case BMP_OK: @@ -85,15 +207,15 @@ bool nsico_convert(struct content *c) } /* Store our content width and description */ - c->width = ico->width; - c->height = ico->height; + c->width = ico->ico->width; + c->height = ico->ico->height; snprintf(title, sizeof(title), messages_get("ICOTitle"), c->width, c->height, size); content__set_title(c, title); - c->size += (ico->width * ico->height * 4) + 16 + 44; + c->size += (ico->ico->width * ico->ico->height * 4) + 16 + 44; /* exit as a success */ - bmp = ico_find(c->data.ico.ico, 255, 255); + bmp = ico_find(ico->ico, 255, 255); assert(bmp); c->bitmap = bmp->bitmap; bitmap_modified(c->bitmap); @@ -110,7 +232,8 @@ bool nsico_redraw(struct content *c, int x, int y, int width, int height, const struct rect *clip, float scale, colour background_colour) { - struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height); + nsico_content *ico = (nsico_content *) c; + struct bmp_image *bmp = ico_find(ico->ico, width, height); if (!bmp->decoded) if (bmp_decode(bmp) != BMP_OK) return false; @@ -119,33 +242,13 @@ bool nsico_redraw(struct content *c, int x, int y, background_colour, BITMAPF_NONE); } -/** sets the bitmap for an ico according to the dimensions */ - -bool nsico_set_bitmap_from_size(hlcache_handle *h, int width, int height) -{ - struct content *c = hlcache_handle_get_content(h); - struct bmp_image *bmp; - - assert(c != NULL); - - bmp = ico_find(c->data.ico.ico, width, height); - if (bmp == NULL) - return false; - - if ((bmp->decoded == false) && (bmp_decode(bmp) != BMP_OK)) - return false; - - c->bitmap = bmp->bitmap; - - return true; -} - bool nsico_redraw_tiled(struct content *c, int x, int y, int width, int height, const struct rect *clip, float scale, colour background_colour, bool repeat_x, bool repeat_y) { - struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height); + nsico_content *ico = (nsico_content *) c; + struct bmp_image *bmp = ico_find(ico->ico, width, height); bitmap_flags_t flags = BITMAPF_NONE; if (!bmp->decoded) @@ -165,23 +268,50 @@ bool nsico_redraw_tiled(struct content *c, int x, int y, void nsico_destroy(struct content *c) { - ico_finalise(c->data.ico.ico); - free(c->data.ico.ico); + nsico_content *ico = (nsico_content *) c; + + ico_finalise(ico->ico); + free(ico->ico); } -bool nsico_clone(const struct content *old, struct content *new_content) +nserror nsico_clone(const struct content *old, struct content **newc) { + nsico_content *ico; + nserror error; + + ico = talloc_zero(0, nsico_content); + if (ico == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &ico->base); + if (error != NSERROR_OK) { + content_destroy(&ico->base); + return error; + } + /* Simply replay creation and conversion */ - if (nsico_create(new_content, NULL) == false) - return false; + error = nsico_create_ico_data(ico); + if (error != NSERROR_OK) { + content_destroy(&ico->base); + return error; + } if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (nsico_convert(new_content) == false) - return false; + if (nsico_convert(&ico->base) == false) { + content_destroy(&ico->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) ico; + + return NSERROR_OK; +} + +content_type nsico_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; } #endif diff --git a/image/ico.h b/image/ico.h index 666c22371..5df3bca95 100644 --- a/image/ico.h +++ b/image/ico.h @@ -29,28 +29,15 @@ #include #include -struct content; -struct hlcache_handle; -struct http_parameter; -struct rect; - -struct content_ico_data { - struct ico_collection *ico; /** ICO collection data */ -}; - -bool nsico_create(struct content *c, const struct http_parameter *params); -bool nsico_convert(struct content *c); -void nsico_destroy(struct content *c); -bool nsico_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool nsico_redraw_tiled(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour, - bool repeat_x, bool repeat_y); -bool nsico_clone(const struct content *old, struct content *new_content); -bool nsico_set_bitmap_from_size(struct hlcache_handle *h, - int width, int height); +#include "utils/errors.h" + +nserror nsico_init(void); +void nsico_fini(void); + +#else + +#define nsico_init() NSERROR_OK +#define nsico_fini() ((void) 0) #endif /* WITH_BMP */ diff --git a/image/image.c b/image/image.c new file mode 100644 index 000000000..23853f133 --- /dev/null +++ b/image/image.c @@ -0,0 +1,100 @@ +/* + * Copyright 2011 John-Mark Bell + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "image/image.h" + +#include "image/bmp.h" +#include "image/gif.h" +#include "image/ico.h" +#include "image/jpeg.h" +#include "image/mng.h" +#include "image/nssprite.h" +#include "image/png.h" +#include "image/rsvg.h" +#include "image/svg.h" +#include "image/webp.h" + +/** + * Initialise image content handlers + * + * \return NSERROR_OK on success, appropriate error otherwise. + */ +nserror image_init(void) +{ + nserror error; + + error = nsbmp_init(); + if (error != NSERROR_OK) + return error; + + error = nsgif_init(); + if (error != NSERROR_OK) + return error; + + error = nsico_init(); + if (error != NSERROR_OK) + return error; + + error = nsjpeg_init(); + if (error != NSERROR_OK) + return error; + + /* Prefer libpng over libmng for pngs */ + error = nsmng_init(); + if (error != NSERROR_OK) + return error; + error = nspng_init(); + if (error != NSERROR_OK) + return error; + + error = nssprite_init(); + if (error != NSERROR_OK) + return error; + + /* Prefer rsvg over libsvgtiny for svgs */ + error = svg_init(); + if (error != NSERROR_OK) + return error; + error = nsrsvg_init(); + if (error != NSERROR_OK) + return error; + + error = webp_init(); + if (error != NSERROR_OK) + return error; + + return NSERROR_OK; +} + +/** + * Finalise image content handlers + */ +void image_fini(void) +{ + nsbmp_fini(); + nsgif_fini(); + nsico_fini(); + nsjpeg_fini(); + nsmng_fini(); + nssprite_fini(); + nspng_fini(); + nsrsvg_fini(); + svg_fini(); + webp_fini(); +} + diff --git a/image/image.h b/image/image.h new file mode 100644 index 000000000..44ea148a8 --- /dev/null +++ b/image/image.h @@ -0,0 +1,31 @@ +/* + * Copyright 2011 John-Mark Bell + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file + * Initialisation/finalisation of image handlers. + */ + +#ifndef NETSURF_IMAGE_IMAGE_H_ +#define NETSURF_IMAGE_IMAGE_H_ + +#include "utils/errors.h" + +nserror image_init(void); +void image_fini(void); + +#endif diff --git a/image/jpeg.c b/image/jpeg.c index 7ef621121..05519d63f 100644 --- a/image/jpeg.c +++ b/image/jpeg.c @@ -26,20 +26,19 @@ #include "utils/config.h" #ifdef WITH_JPEG -/* This must come first due to libpng issues */ -#include "content/content_protected.h" - #include #include #include #include #include +#include "content/content_protected.h" #include "desktop/plotters.h" #include "image/bitmap.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/utils.h" #define JPEG_INTERNAL_OPTIONS @@ -57,12 +56,30 @@ static char nsjpeg_error_buffer[JMSG_LENGTH_MAX]; +typedef struct nsjpeg_content { + struct content base; +} nsjpeg_content; struct nsjpeg_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; +static nserror nsjpeg_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static bool nsjpeg_convert(struct content *c); +static void nsjpeg_destroy(struct content *c); +static bool nsjpeg_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static bool nsjpeg_redraw_tiled(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour, + bool repeat_x, bool repeat_y); +static nserror nsjpeg_clone(const struct content *old, struct content **newc); +static content_type nsjpeg_content_type(lwc_string *mime_type); static void nsjpeg_error_exit(j_common_ptr cinfo); static void nsjpeg_init_source(j_decompress_ptr cinfo); @@ -70,6 +87,95 @@ static boolean nsjpeg_fill_input_buffer(j_decompress_ptr cinfo); static void nsjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes); static void nsjpeg_term_source(j_decompress_ptr cinfo); +static const content_handler nsjpeg_content_handler = { + nsjpeg_create, + NULL, + nsjpeg_convert, + NULL, + nsjpeg_destroy, + NULL, + NULL, + NULL, + nsjpeg_redraw, + nsjpeg_redraw_tiled, + NULL, + NULL, + nsjpeg_clone, + NULL, + nsjpeg_content_type, + false +}; + +static const char *nsjpeg_types[] = { + "image/jpeg", + "image/jpg", + "image/pjpeg" +}; + +static lwc_string *nsjpeg_mime_types[NOF_ELEMENTS(nsjpeg_types)]; + +nserror nsjpeg_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(nsjpeg_mime_types); i++) { + lerror = lwc_intern_string(nsjpeg_types[i], + strlen(nsjpeg_types[i]), + &nsjpeg_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(nsjpeg_mime_types[i], + &nsjpeg_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + nsjpeg_fini(); + + return error; +} + +void nsjpeg_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(nsjpeg_mime_types); i++) { + if (nsjpeg_mime_types[i] != NULL) + lwc_string_unref(nsjpeg_mime_types[i]); + } +} + +nserror nsjpeg_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + nsjpeg_content *jpeg; + nserror error; + + jpeg = talloc_zero(0, nsjpeg_content); + if (jpeg == NULL) + return NSERROR_NOMEM; + + error = content__init(&jpeg->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(jpeg); + return error; + } + + *c = (struct content *) jpeg; + + return NSERROR_OK; +} /** * Convert a CONTENT_JPEG for display. @@ -286,16 +392,38 @@ void nsjpeg_destroy(struct content *c) } -bool nsjpeg_clone(const struct content *old, struct content *new_content) +nserror nsjpeg_clone(const struct content *old, struct content **newc) { + nsjpeg_content *jpeg; + nserror error; + + jpeg = talloc_zero(0, nsjpeg_content); + if (jpeg == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &jpeg->base); + if (error != NSERROR_OK) { + content_destroy(&jpeg->base); + return error; + } + /* Simply replay conversion */ if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (nsjpeg_convert(new_content) == false) - return false; + if (nsjpeg_convert(&jpeg->base) == false) { + content_destroy(&jpeg->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) jpeg; + + return NSERROR_OK; +} + +content_type nsjpeg_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; } #endif /* WITH_JPEG */ diff --git a/image/jpeg.h b/image/jpeg.h index 70bae4a6b..57b82bdc1 100644 --- a/image/jpeg.h +++ b/image/jpeg.h @@ -28,24 +28,15 @@ #include -struct bitmap; -struct content; -struct rect; - -struct content_jpeg_data { - int dummy; /* NOT USED but to satisfy Norcroft */ -}; - -bool nsjpeg_convert(struct content *c); -void nsjpeg_destroy(struct content *c); -bool nsjpeg_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool nsjpeg_redraw_tiled(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour, - bool repeat_x, bool repeat_y); -bool nsjpeg_clone(const struct content *old, struct content *new_content); +#include "utils/errors.h" + +nserror nsjpeg_init(void); +void nsjpeg_fini(void); + +#else + +#define nsjpeg_init() NSERROR_OK +#define nsjpeg_fini() ((void) 0) #endif /* WITH_JPEG */ diff --git a/image/mng.c b/image/mng.c index 6067aa8e8..a6b0377c4 100644 --- a/image/mng.c +++ b/image/mng.c @@ -23,9 +23,6 @@ #include "utils/config.h" #ifdef WITH_MNG -/* This must come first due to libpng issues */ -#include "content/content_protected.h" - #include #include #include @@ -33,6 +30,7 @@ #include #include #include +#include "content/content_protected.h" #include "desktop/options.h" #include "desktop/plotters.h" #include "image/bitmap.h" @@ -40,12 +38,44 @@ #include "utils/log.h" #include "utils/messages.h" #include "utils/schedule.h" +#include "utils/talloc.h" #include "utils/utils.h" /* We do not currently support any form of colour/gamma correction, nor do we support dynamic MNGs. */ +typedef struct nsmng_content +{ + struct content base; + + bool opaque_test_pending; + bool read_start; + bool read_resume; + int read_size; + bool waiting; + bool displayed; + void *handle; +} nsmng_content; + +static nserror nsmng_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static nserror nsmng_create_mng_data(nsmng_content *c); +static bool nsmng_process_data(struct content *c, const char *data, + unsigned int size); +static bool nsmng_convert(struct content *c); +static void nsmng_destroy(struct content *c); +static bool nsmng_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static bool nsmng_redraw_tiled(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour, + bool repeat_x, bool repeat_y); +static nserror nsmng_clone(const struct content *old, struct content **newc); +static content_type nsmng_content_type(lwc_string *mime_type); static mng_bool nsmng_openstream(mng_handle mng); static mng_bool nsmng_readdata(mng_handle mng, mng_ptr buffer, @@ -59,7 +89,7 @@ static mng_bool nsmng_refresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h); static mng_bool nsmng_settimer(mng_handle mng, mng_uint32 msecs); static void nsmng_animate(void *p); -static bool nsmng_broadcast_error(struct content *c, mng_retcode code); +static nserror nsmng_broadcast_error(nsmng_content *c, mng_retcode code); static mng_bool nsmng_errorproc(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text); @@ -68,8 +98,131 @@ static mng_ptr nsmng_alloc(mng_size_t n); static void nsmng_free(mng_ptr p, mng_size_t n); #endif +static const content_handler nsmng_content_handler = { + nsmng_create, + nsmng_process_data, + nsmng_convert, + NULL, + nsmng_destroy, + NULL, + NULL, + NULL, + nsmng_redraw, + nsmng_redraw_tiled, + NULL, + NULL, + nsmng_clone, + NULL, + nsmng_content_type, + false +}; + +static const char *jng_types[] = { + "image/jng", + "image/x-jng" +}; + +static const char *mng_types[] = { + "image/mng", + "image/x-mng", + "video/mng", + "video/x-mng" +}; + +static const char *png_types[] = { + "image/png" +}; + +static lwc_string *jng_mime_types[NOF_ELEMENTS(jng_types)]; +static lwc_string *mng_mime_types[NOF_ELEMENTS(mng_types)]; +static lwc_string *png_mime_types[NOF_ELEMENTS(png_types)]; + +nserror nsmng_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + +#define register_types(type) \ + for (i = 0; i < NOF_ELEMENTS(type##_mime_types); i++) { \ + lerror = lwc_intern_string(type##_types[i], \ + strlen(type##_types[i]), \ + &type##_mime_types[i]); \ + if (lerror != lwc_error_ok) { \ + error = NSERROR_NOMEM; \ + goto error; \ + } \ + \ + error = content_factory_register_handler( \ + type##_mime_types[i], \ + &nsmng_content_handler); \ + if (error != NSERROR_OK) \ + goto error; \ + } + + register_types(jng) + register_types(mng) + register_types(png) + + return NSERROR_OK; + +error: + nsmng_fini(); + + return error; +} + +void nsmng_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(jng_mime_types); i++) { + if (jng_mime_types[i] != NULL) + lwc_string_unref(jng_mime_types[i]); + } + + for (i = 0; i < NOF_ELEMENTS(mng_mime_types); i++) { + if (mng_mime_types[i] != NULL) + lwc_string_unref(mng_mime_types[i]); + } + + for (i = 0; i < NOF_ELEMENTS(png_mime_types); i++) { + if (png_mime_types[i] != NULL) + lwc_string_unref(png_mime_types[i]); + } +} + +nserror nsmng_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + nsmng_content *mng; + nserror error; + + mng = talloc_zero(0, nsmng_content); + if (mng == NULL) + return NSERROR_NOMEM; + + error = content__init(&mng->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(mng); + return error; + } + + error = nsmng_create_mng_data(mng); + if (error != NSERROR_OK) { + talloc_free(mng); + return error; + } + + *c = (struct content *) mng; -bool nsmng_create(struct content *c, const struct http_parameter *params) + return NSERROR_OK; +} + +nserror nsmng_create_mng_data(nsmng_content *c) { mng_retcode code; union content_msg_data msg_data; @@ -79,20 +232,20 @@ bool nsmng_create(struct content *c, const struct http_parameter *params) /* Initialise the library */ #ifdef MNG_INTERNAL_MEMMNGMT - c->data.mng.handle = mng_initialize(c, MNG_NULL, MNG_NULL, MNG_NULL); + c->handle = mng_initialize(c, MNG_NULL, MNG_NULL, MNG_NULL); #else - c->data.mng.handle = mng_initialize(c, nsmng_alloc, nsmng_free, MNG_NULL); + c->handle = mng_initialize(c, nsmng_alloc, nsmng_free, MNG_NULL); #endif - if (c->data.mng.handle == MNG_NULL) { + if (c->handle == MNG_NULL) { LOG(("Unable to initialise MNG library.")); msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } /* We need to decode in suspension mode */ - code = mng_set_suspensionmode(c->data.mng.handle, MNG_TRUE); + code = mng_set_suspensionmode(c->handle, MNG_TRUE); if (code) { LOG(("Unable to set suspension mode.")); return nsmng_broadcast_error(c, code); @@ -100,22 +253,22 @@ bool nsmng_create(struct content *c, const struct http_parameter *params) /* We need to register our callbacks */ - code = mng_setcb_openstream(c->data.mng.handle, nsmng_openstream); + code = mng_setcb_openstream(c->handle, nsmng_openstream); if (code) { LOG(("Unable to set openstream callback.")); return nsmng_broadcast_error(c, code); } - code = mng_setcb_readdata(c->data.mng.handle, nsmng_readdata); + code = mng_setcb_readdata(c->handle, nsmng_readdata); if (code) { LOG(("Unable to set readdata callback.")); return nsmng_broadcast_error(c, code); } - code = mng_setcb_closestream(c->data.mng.handle, nsmng_closestream); + code = mng_setcb_closestream(c->handle, nsmng_closestream); if (code) { LOG(("Unable to set closestream callback.")); return nsmng_broadcast_error(c, code); } - code = mng_setcb_processheader(c->data.mng.handle, nsmng_processheader); + code = mng_setcb_processheader(c->handle, nsmng_processheader); if (code) { LOG(("Unable to set processheader callback.")); return nsmng_broadcast_error(c, code); @@ -123,29 +276,29 @@ bool nsmng_create(struct content *c, const struct http_parameter *params) /* Register our callbacks for displaying */ - code = mng_setcb_getcanvasline(c->data.mng.handle, nsmng_getcanvasline); + code = mng_setcb_getcanvasline(c->handle, nsmng_getcanvasline); if (code) { LOG(("Unable to set getcanvasline callback.")); return nsmng_broadcast_error(c, code); } - code = mng_setcb_refresh(c->data.mng.handle, nsmng_refresh); + code = mng_setcb_refresh(c->handle, nsmng_refresh); if (code) { LOG(("Unable to set refresh callback.")); return nsmng_broadcast_error(c, code); } - code = mng_setcb_gettickcount(c->data.mng.handle, nsmng_gettickcount); + code = mng_setcb_gettickcount(c->handle, nsmng_gettickcount); if (code) { LOG(("Unable to set gettickcount callback.")); return nsmng_broadcast_error(c, code); } - code = mng_setcb_settimer(c->data.mng.handle, nsmng_settimer); + code = mng_setcb_settimer(c->handle, nsmng_settimer); if (code) { LOG(("Unable to set settimer callback.")); return nsmng_broadcast_error(c, code); } /* register error handling function */ - code = mng_setcb_errorproc(c->data.mng.handle, nsmng_errorproc); + code = mng_setcb_errorproc(c->handle, nsmng_errorproc); if (code) { LOG(("Unable to set errorproc")); return nsmng_broadcast_error(c, code); @@ -153,13 +306,14 @@ bool nsmng_create(struct content *c, const struct http_parameter *params) /* Initialise the reading */ - c->data.mng.read_start = true; - c->data.mng.read_resume = false; - c->data.mng.read_size = 0; - c->data.mng.waiting = false; + c->read_start = true; + c->read_resume = false; + c->read_size = 0; + c->waiting = false; - c->data.mng.displayed = false; - return true; + c->displayed = false; + + return NSERROR_OK; } @@ -176,7 +330,7 @@ mng_bool nsmng_openstream(mng_handle mng) mng_bool nsmng_readdata(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread) { - struct content *c; + nsmng_content *c; const char *data; unsigned long data_size; @@ -186,19 +340,19 @@ mng_bool nsmng_readdata(mng_handle mng, mng_ptr buffer, mng_uint32 size, /* Get our content back */ - c = (struct content *) mng_get_userdata(mng); + c = (nsmng_content *) mng_get_userdata(mng); assert(c != NULL); /* Copy any data we have (maximum of 'size') */ - data = content__get_source_data(c, &data_size); + data = content__get_source_data(&c->base, &data_size); - *bytesread = ((data_size - c->data.mng.read_size) < size) ? - (data_size - c->data.mng.read_size) : size; + *bytesread = ((data_size - c->read_size) < size) ? + (data_size - c->read_size) : size; if ((*bytesread) > 0) { - memcpy(buffer, data + c->data.mng.read_size, *bytesread); - c->data.mng.read_size += *bytesread; + memcpy(buffer, data + c->read_size, *bytesread); + c->read_size += *bytesread; } /* Return success @@ -215,7 +369,7 @@ mng_bool nsmng_closestream(mng_handle mng) mng_bool nsmng_processheader(mng_handle mng, mng_uint32 width, mng_uint32 height) { - struct content *c; + nsmng_content *c; union content_msg_data msg_data; uint8_t *buffer; @@ -224,31 +378,31 @@ mng_bool nsmng_processheader(mng_handle mng, mng_uint32 width, /* This function is called when the header has been read and we know the dimensions of the canvas. */ - c = (struct content *)mng_get_userdata(mng); + c = (nsmng_content *) mng_get_userdata(mng); assert(c != NULL); - c->bitmap = bitmap_create(width, height, BITMAP_NEW); - if (!c->bitmap) { + c->base.bitmap = bitmap_create(width, height, BITMAP_NEW); + if (c->base.bitmap == NULL) { msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); LOG(("Insufficient memory to create canvas.")); return MNG_FALSE; } /* Get the buffer to ensure that it is allocated and the calls in * nsmng_getcanvasline() succeed. */ - buffer = bitmap_get_buffer(c->bitmap); - if (!buffer) { + buffer = bitmap_get_buffer(c->base.bitmap); + if (buffer == NULL) { msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); LOG(("Insufficient memory to create canvas.")); return MNG_FALSE; } /* Initialise the content size */ - c->width = width; - c->height = height; + c->base.width = width; + c->base.height = height; /* Set the canvas style */ @@ -268,6 +422,7 @@ mng_bool nsmng_processheader(mng_handle mng, mng_uint32 width, bool nsmng_process_data(struct content *c, const char *data, unsigned int size) { + nsmng_content *mng = (nsmng_content *) c; mng_retcode status; assert(c != NULL); @@ -275,21 +430,21 @@ bool nsmng_process_data(struct content *c, const char *data, unsigned int size) /* We only need to do any processing if we're starting/resuming reading. */ - if ((!c->data.mng.read_resume) && (!c->data.mng.read_start)) + if ((!mng->read_resume) && (!mng->read_start)) return true; /* Try to start processing, or process some more data */ - if (c->data.mng.read_start) { - status = mng_read(c->data.mng.handle); - c->data.mng.read_start = false; + if (mng->read_start) { + status = mng_read(mng->handle); + mng->read_start = false; } else { - status = mng_read_resume(c->data.mng.handle); + status = mng_read_resume(mng->handle); } - c->data.mng.read_resume = (status == MNG_NEEDMOREDATA); + mng->read_resume = (status == MNG_NEEDMOREDATA); if ((status != MNG_NOERROR) && (status != MNG_NEEDMOREDATA)) { LOG(("Failed to start/continue reading (%i).", status)); - return nsmng_broadcast_error(c, status); + return nsmng_broadcast_error(mng, status) == NSERROR_OK; } /* Continue onwards @@ -300,9 +455,14 @@ bool nsmng_process_data(struct content *c, const char *data, unsigned int size) bool nsmng_convert(struct content *c) { + nsmng_content *mng = (nsmng_content *) c; mng_retcode status; const char *data; unsigned long size; + lwc_string *content_type; + bool match; + bool is_mng = false; + uint32_t i; char title[100]; assert(c != NULL); @@ -312,15 +472,26 @@ bool nsmng_convert(struct content *c) /* by this point, the png should have been parsed * and the bitmap created, so ensure that's the case */ - if (!c->bitmap) - return nsmng_broadcast_error(c, -1); + if (content__get_bitmap(c) == NULL) + return nsmng_broadcast_error(mng, -1) == NSERROR_OK; /* Set the title */ - if (c->type == CONTENT_MNG) { + content_type = content__get_mime_type(c); + + for (i = 0; i < NOF_ELEMENTS(mng_mime_types); i++) { + if (lwc_string_caseless_isequal(content_type, mng_mime_types[i], + &match) == lwc_error_ok && match) { + is_mng = true; + break; + } + } + + if (is_mng) { snprintf(title, sizeof(title), messages_get("MNGTitle"), c->width, c->height, size); - } else if (c->type == CONTENT_PNG) { + } else if (lwc_string_caseless_isequal(content_type, png_mime_types[0], + &match) == lwc_error_ok && match) { snprintf(title, sizeof(title), messages_get("PNGTitle"), c->width, c->height, size); } else { @@ -329,6 +500,8 @@ bool nsmng_convert(struct content *c) } content__set_title(c, title); + lwc_string_unref(content_type); + c->size += c->width * c->height * 4; content_set_ready(c); content_set_done(c); @@ -349,28 +522,27 @@ bool nsmng_convert(struct content *c) */ /* Start displaying */ - status = mng_display(c->data.mng.handle); + status = mng_display(mng->handle); if ((status != MNG_NOERROR) && (status != MNG_NEEDTIMERWAIT)) { LOG(("Unable to start display (%i)", status)); - return nsmng_broadcast_error(c, status); + return nsmng_broadcast_error(mng, status) == NSERROR_OK; } bitmap_modified(c->bitmap); /* Optimise the plotting of JNG/PNGs */ - c->data.mng.opaque_test_pending = (c->type == CONTENT_PNG) || - (c->type == CONTENT_JNG); - if (c->data.mng.opaque_test_pending) + mng->opaque_test_pending = (is_mng == false); + if (mng->opaque_test_pending) bitmap_set_opaque(c->bitmap, false); /* free associated memory except for mngs where it may be subsequently needed for * animation decoding. */ - if (c->type != CONTENT_MNG) { - mng_handle handle = c->data.mng.handle; + if (is_mng == false) { + mng_handle handle = mng->handle; mng_cleanup(&handle); - c->data.mng.handle = NULL; + mng->handle = NULL; } return true; @@ -383,19 +555,19 @@ bool nsmng_convert(struct content *c) mng_ptr nsmng_getcanvasline(mng_handle mng, mng_uint32 line) { - struct content *c; + nsmng_content *c; assert(mng != NULL); /* Get our content back */ - c = (struct content *)mng_get_userdata(mng); + c = (nsmng_content *) mng_get_userdata(mng); assert(c != NULL); /* Calculate the address */ - return bitmap_get_buffer(c->bitmap) + - bitmap_get_rowstride(c->bitmap) * line; + return bitmap_get_buffer(c->base.bitmap) + + bitmap_get_rowstride(c->base.bitmap) * line; } @@ -433,13 +605,13 @@ mng_bool nsmng_refresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h) { union content_msg_data data; - struct content *c; + nsmng_content *c; assert(mng != NULL); /* Get our content back */ - c = (struct content *)mng_get_userdata(mng); + c = (nsmng_content *) mng_get_userdata(mng); assert(c != NULL); /* Set the minimum redraw area @@ -463,11 +635,11 @@ mng_bool nsmng_refresh(mng_handle mng, mng_uint32 x, mng_uint32 y, /* Set the object characteristics */ - data.redraw.object = c; + data.redraw.object = &c->base; data.redraw.object_x = 0; data.redraw.object_y = 0; - data.redraw.object_width = c->width; - data.redraw.object_height = c->height; + data.redraw.object_width = c->base.width; + data.redraw.object_height = c->base.height; /* Only attempt to force the redraw if we've been requested to * display the image in the first place (i.e. nsmng_redraw has @@ -475,21 +647,21 @@ mng_bool nsmng_refresh(mng_handle mng, mng_uint32 x, mng_uint32 y, * an image that shouldn't be shown (e.g. if the image is a fallback * for an object that can't be rendered) */ - if (c->data.mng.displayed) - content_broadcast(c, CONTENT_MSG_REDRAW, data); + if (c->displayed) + content_broadcast(&c->base, CONTENT_MSG_REDRAW, data); return MNG_TRUE; } mng_bool nsmng_settimer(mng_handle mng, mng_uint32 msecs) { - struct content *c; + nsmng_content *c; assert(mng != NULL); /* Get our content back */ - c = (struct content *)mng_get_userdata(mng); + c = (nsmng_content *) mng_get_userdata(mng); assert(c != NULL); /* Perform the scheduling @@ -505,18 +677,20 @@ mng_bool nsmng_settimer(mng_handle mng, mng_uint32 msecs) void nsmng_destroy(struct content *c) { + nsmng_content *mng = (nsmng_content *) c; assert (c != NULL); /* Cleanup the MNG structure and release the canvas memory */ schedule_remove(nsmng_animate, c); - if (c->type == CONTENT_MNG) { - mng_handle handle = c->data.mng.handle; + + if (mng->handle != NULL) { + mng_handle handle = mng->handle; mng_cleanup(&handle); - c->data.mng.handle = NULL; + mng->handle = NULL; } if (c->bitmap) @@ -528,14 +702,15 @@ bool nsmng_redraw(struct content *c, int x, int y, int width, int height, const struct rect *clip, float scale, colour background_colour) { + nsmng_content *mng = (nsmng_content *) c; bool ret; /* mark image as having been requested to display */ - c->data.mng.displayed = true; + mng->displayed = true; - if ((c->bitmap) && (c->data.mng.opaque_test_pending)) { + if ((c->bitmap) && (mng->opaque_test_pending)) { bitmap_set_opaque(c->bitmap, bitmap_test_opaque(c->bitmap)); - c->data.mng.opaque_test_pending = false; + mng->opaque_test_pending = false; } ret = plot.bitmap(x, y, width, height, @@ -543,7 +718,7 @@ bool nsmng_redraw(struct content *c, int x, int y, /* Check if we need to restart the animation */ - if ((c->data.mng.waiting) && (option_animate_images)) + if ((mng->waiting) && (option_animate_images)) nsmng_animate(c); return ret; @@ -555,15 +730,16 @@ bool nsmng_redraw_tiled(struct content *c, int x, int y, float scale, colour background_colour, bool repeat_x, bool repeat_y) { + nsmng_content *mng = (nsmng_content *) c; bool ret; bitmap_flags_t flags = BITMAPF_NONE; /* mark image as having been requested to display */ - c->data.mng.displayed = true; + mng->displayed = true; - if ((c->bitmap) && (c->data.mng.opaque_test_pending)) { + if ((c->bitmap) && (mng->opaque_test_pending)) { bitmap_set_opaque(c->bitmap, bitmap_test_opaque(c->bitmap)); - c->data.mng.opaque_test_pending = false; + mng->opaque_test_pending = false; } if (repeat_x) @@ -577,35 +753,61 @@ bool nsmng_redraw_tiled(struct content *c, int x, int y, /* Check if we need to restart the animation */ - if ((c->data.mng.waiting) && (option_animate_images)) + if ((mng->waiting) && (option_animate_images)) nsmng_animate(c); return ret; } -bool nsmng_clone(const struct content *old, struct content *new_content) +nserror nsmng_clone(const struct content *old, struct content **newc) { + nsmng_content *mng; + nserror error; const char *data; unsigned long size; + mng = talloc_zero(0, nsmng_content); + if (mng == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &mng->base); + if (error != NSERROR_OK) { + content_destroy(&mng->base); + return error; + } + /* Simply replay create/process/convert */ - if (nsmng_create(new_content, NULL) == false) - return false; + error = nsmng_create_mng_data(mng); + if (error != NSERROR_OK) { + content_destroy(&mng->base); + return error; + } - data = content__get_source_data(new_content, &size); + data = content__get_source_data(&mng->base, &size); if (size > 0) { - if (nsmng_process_data(new_content, data, size) == false) - return false; + if (nsmng_process_data(&mng->base, data, size) == false) { + content_destroy(&mng->base); + return NSERROR_CLONE_FAILED; + } } if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (nsmng_convert(new_content) == false) - return false; + if (nsmng_convert(&mng->base) == false) { + content_destroy(&mng->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) mng; + + return NSERROR_OK; +} + +content_type nsmng_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; } /** @@ -613,22 +815,22 @@ bool nsmng_clone(const struct content *old, struct content *new_content) */ void nsmng_animate(void *p) { - struct content *c; + nsmng_content *c; assert(p != NULL); - c = (struct content *)p; + c = (nsmng_content *) p; /* If we used the last animation we advance, if not we try again later */ - if (c->user_list->next == NULL) { - c->data.mng.waiting = true; + if (c->base.user_list->next == NULL) { + c->waiting = true; } else { - c->data.mng.waiting = false; - mng_display_resume(c->data.mng.handle); - c->data.mng.opaque_test_pending = true; - if (c->bitmap) - bitmap_modified(c->bitmap); + c->waiting = false; + mng_display_resume(c->handle); + c->opaque_test_pending = true; + if (c->base.bitmap) + bitmap_modified(c->base.bitmap); } } @@ -638,9 +840,9 @@ void nsmng_animate(void *p) * Broadcasts an error message and returns false * * \param c the content to broadcast for - * \return false + * \return Appropriate error */ -bool nsmng_broadcast_error(struct content *c, mng_retcode code) +nserror nsmng_broadcast_error(nsmng_content *c, mng_retcode code) { union content_msg_data msg_data; char error[100]; @@ -649,14 +851,14 @@ bool nsmng_broadcast_error(struct content *c, mng_retcode code) if (code == MNG_OUTOFMEMORY) { msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } snprintf(error, sizeof error, messages_get("MNGError"), code); msg_data.error = error; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_MNG_ERROR; } @@ -664,12 +866,12 @@ mng_bool nsmng_errorproc(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text) { - struct content *c; + nsmng_content *c; char chunk[5]; assert(mng != NULL); - c = (struct content *)mng_get_userdata(mng); + c = (nsmng_content *) mng_get_userdata(mng); assert(c != NULL); chunk[0] = (char)((chunktype >> 24) & 0xFF); @@ -679,11 +881,11 @@ mng_bool nsmng_errorproc(mng_handle mng, mng_int32 code, chunk[4] = '\0'; LOG(("error playing '%s' chunk %s (%d):", - content__get_url(c), chunk, chunkseq)); + content__get_url(&c->base), chunk, chunkseq)); LOG(("code %d severity %d extra1 %d extra2 %d text:'%s'", code, severity, extra1, extra2, text)); - return (0); + return (0); } diff --git a/image/mng.h b/image/mng.h index 5835fef96..a3318615b 100644 --- a/image/mng.h +++ b/image/mng.h @@ -28,32 +28,13 @@ #include -struct content; -struct http_parameter; -struct rect; - -struct content_mng_data { - bool opaque_test_pending; - bool read_start; - bool read_resume; - int read_size; - bool waiting; - bool displayed; - void *handle; -}; - -bool nsmng_create(struct content *c, const struct http_parameter *params); -bool nsmng_process_data(struct content *c, const char *data, unsigned int size); -bool nsmng_convert(struct content *c); -void nsmng_destroy(struct content *c); -bool nsmng_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool nsmng_redraw_tiled(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour, - bool repeat_x, bool repeat_y); -bool nsmng_clone(const struct content *old, struct content *new_content); +nserror nsmng_init(void); +void nsmng_fini(void); + +#else + +#define nsmng_init() NSERROR_OK +#define nsmng_fini() ((void) 0) #endif /* WITH_MNG */ diff --git a/image/nssprite.c b/image/nssprite.c index a0ad8678c..961188c84 100644 --- a/image/nssprite.c +++ b/image/nssprite.c @@ -29,13 +29,33 @@ #include #include #include "utils/config.h" +#include "content/content_protected.h" #include "desktop/plotters.h" #include "image/bitmap.h" -#include "content/content_protected.h" +#include "image/nssprite.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/utils.h" +typedef struct nssprite_content { + struct content base; + + struct rosprite_area* sprite_area; +} nssprite_content; + +static nserror nssprite_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static bool nssprite_convert(struct content *c); +static void nssprite_destroy(struct content *c); +static bool nssprite_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static nserror nssprite_clone(const struct content *old, struct content **newc); +static content_type nssprite_content_type(lwc_string *mime_type); + #define ERRCHK(x) do { \ rosprite_error err = x; \ if (err == ROSPRITE_EOF) { \ @@ -50,6 +70,94 @@ } \ } while(0) +static const content_handler nssprite_content_handler = { + nssprite_create, + NULL, + nssprite_convert, + NULL, + nssprite_destroy, + NULL, + NULL, + NULL, + nssprite_redraw, + NULL, + NULL, + NULL, + nssprite_clone, + NULL, + nssprite_content_type, + false +}; + +static const char *nssprite_types[] = { + "image/x-riscos-sprite" +}; + +static lwc_string *nssprite_mime_types[NOF_ELEMENTS(nssprite_types)]; + +nserror nssprite_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(nssprite_mime_types); i++) { + lerror = lwc_intern_string(nssprite_types[i], + strlen(nssprite_types[i]), + &nssprite_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(nssprite_mime_types[i], + &nssprite_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + nssprite_fini(); + + return error; +} + +void nssprite_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(nssprite_mime_types); i++) { + if (nssprite_mime_types[i] != NULL) + lwc_string_unref(nssprite_mime_types[i]); + } +} + +nserror nssprite_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + nssprite_content *sprite; + nserror error; + + sprite = talloc_zero(0, nssprite_content); + if (sprite == NULL) + return NSERROR_NOMEM; + + error = content__init(&sprite->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(sprite); + return error; + } + + *c = (struct content *) sprite; + + return NSERROR_OK; +} + /** * Convert a CONTENT_SPRITE for display. * @@ -58,6 +166,7 @@ bool nssprite_convert(struct content *c) { + nssprite_content *nssprite = (nssprite_content *) c; union content_msg_data msg_data; struct rosprite_mem_context* ctx; @@ -72,7 +181,7 @@ bool nssprite_convert(struct content *c) struct rosprite_area* sprite_area; ERRCHK(rosprite_load(rosprite_mem_reader, ctx, &sprite_area)); rosprite_destroy_mem_context(ctx); - c->data.nssprite.sprite_area = sprite_area; + nssprite->sprite_area = sprite_area; assert(sprite_area->sprite_count > 0); @@ -126,8 +235,10 @@ bool nssprite_convert(struct content *c) void nssprite_destroy(struct content *c) { - if (c->data.nssprite.sprite_area != NULL) - rosprite_destroy_sprite_area(c->data.nssprite.sprite_area); + nssprite_content *sprite = (nssprite_content *) c; + + if (sprite->sprite_area != NULL) + rosprite_destroy_sprite_area(sprite->sprite_area); if (c->bitmap != NULL) bitmap_destroy(c->bitmap); } @@ -146,16 +257,38 @@ bool nssprite_redraw(struct content *c, int x, int y, } -bool nssprite_clone(const struct content *old, struct content *new_content) +nserror nssprite_clone(const struct content *old, struct content **newc) { + nssprite_content *sprite; + nserror error; + + sprite = talloc_zero(0, nssprite_content); + if (sprite == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &sprite->base); + if (error != NSERROR_OK) { + content_destroy(&sprite->base); + return error; + } + /* Simply replay convert */ if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (nssprite_convert(new_content) == false) - return false; + if (nssprite_convert(&sprite->base) == false) { + content_destroy(&sprite->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) sprite; + + return NSERROR_OK; +} + +content_type nssprite_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; } #endif diff --git a/image/nssprite.h b/image/nssprite.h index 3b69108cd..1f25896b3 100644 --- a/image/nssprite.h +++ b/image/nssprite.h @@ -28,19 +28,13 @@ #include -struct content; -struct rect; - -struct content_nssprite_data { - struct rosprite_area* sprite_area; -}; - -bool nssprite_convert(struct content *c); -void nssprite_destroy(struct content *c); -bool nssprite_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool nssprite_clone(const struct content *old, struct content *new_content); +nserror nssprite_init(void); +void nssprite_fini(void); + +#else + +#define nssprite_init() NSERROR_OK +#define nssprite_fini() ((void) 0) #endif /* WITH_NSSPRITE */ diff --git a/image/png.c b/image/png.c index 159019996..5469e6923 100644 --- a/image/png.c +++ b/image/png.c @@ -23,8 +23,7 @@ #include #include -/* Ugh -- setjmp.h weirdness ensues if this isn't first... */ -#include "image/png.h" +#include #include "utils/config.h" @@ -33,14 +32,16 @@ #include "content/content_protected.h" #include "image/bitmap.h" +#include "image/png.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/utils.h" #ifdef WITH_PNG -/* accomodate for old versions of libpng (beware security holes!) */ +/* accommodate for old versions of libpng (beware security holes!) */ #ifndef png_jmpbuf #warning you have an antique libpng @@ -51,72 +52,190 @@ #define png_set_expand_gray_1_2_4_to_8(png) png_set_gray_1_2_4_to_8(png) #endif -/* libpng uses names starting png_, so use nspng_ here to avoid clashes */ +typedef struct nspng_content { + struct content base; + + png_structp png; + png_infop info; + int interlace; + struct bitmap *bitmap; /**< Created NetSurf bitmap */ + size_t rowstride, bpp; /**< Bitmap rowstride and bpp */ + size_t rowbytes; /**< Number of bytes per row */ +} nspng_content; + +static nserror nspng_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static nserror nspng_create_png_data(nspng_content *c); +static bool nspng_process_data(struct content *c, const char *data, + unsigned int size); +static bool nspng_convert(struct content *c); +static void nspng_destroy(struct content *c); +static bool nspng_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static bool nspng_redraw_tiled(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour, + bool repeat_x, bool repeat_y); +static nserror nspng_clone(const struct content *old, struct content **newc); +static content_type nspng_content_type(lwc_string *mime_type); static void info_callback(png_structp png, png_infop info); static void row_callback(png_structp png, png_bytep new_row, png_uint_32 row_num, int pass); static void end_callback(png_structp png, png_infop info); +static const content_handler nspng_content_handler = { + nspng_create, + nspng_process_data, + nspng_convert, + NULL, + nspng_destroy, + NULL, + NULL, + NULL, + nspng_redraw, + nspng_redraw_tiled, + NULL, + NULL, + nspng_clone, + NULL, + nspng_content_type, + false +}; + +static const char *nspng_types[] = { + "image/png" +}; + +static lwc_string *nspng_mime_types[NOF_ELEMENTS(nspng_types)]; + +nserror nspng_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(nspng_mime_types); i++) { + lerror = lwc_intern_string(nspng_types[i], + strlen(nspng_types[i]), + &nspng_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(nspng_mime_types[i], + &nspng_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + nspng_fini(); + + return error; +} + +void nspng_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(nspng_mime_types); i++) { + if (nspng_mime_types[i] != NULL) + lwc_string_unref(nspng_mime_types[i]); + } +} -bool nspng_create(struct content *c, const struct http_parameter *params) +nserror nspng_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + nspng_content *png; + nserror error; + + png = talloc_zero(0, nspng_content); + if (png == NULL) + return NSERROR_NOMEM; + + error = content__init(&png->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(png); + return error; + } + + error = nspng_create_png_data(png); + if (error != NSERROR_OK) { + talloc_free(png); + return error; + } + + *c = (struct content *) png; + + return NSERROR_OK; +} + +nserror nspng_create_png_data(nspng_content *c) { union content_msg_data msg_data; - c->data.png.bitmap = NULL; + c->bitmap = NULL; - c->data.png.png = png_create_read_struct(PNG_LIBPNG_VER_STRING, - 0, 0, 0); - if (c->data.png.png == NULL) { + c->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (c->png == NULL) { msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); warn_user("NoMemory", 0); - return false; + return NSERROR_NOMEM; } - c->data.png.info = png_create_info_struct(c->data.png.png); - if (c->data.png.info == NULL) { - png_destroy_read_struct(&c->data.png.png, - &c->data.png.info, 0); + c->info = png_create_info_struct(c->png); + if (c->info == NULL) { + png_destroy_read_struct(&c->png, &c->info, 0); msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); warn_user("NoMemory", 0); - return false; + return NSERROR_NOMEM; } - if (setjmp(png_jmpbuf(c->data.png.png))) { - png_destroy_read_struct(&c->data.png.png, - &c->data.png.info, 0); + if (setjmp(png_jmpbuf(c->png))) { + png_destroy_read_struct(&c->png, &c->info, 0); LOG(("Failed to set callbacks")); - c->data.png.png = NULL; - c->data.png.info = NULL; + c->png = NULL; + c->info = NULL; msg_data.error = messages_get("PNGError"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } - png_set_progressive_read_fn(c->data.png.png, c, + png_set_progressive_read_fn(c->png, c, info_callback, row_callback, end_callback); - return true; + return NSERROR_OK; } bool nspng_process_data(struct content *c, const char *data, unsigned int size) { + nspng_content *png = (nspng_content *) c; union content_msg_data msg_data; - if (setjmp(png_jmpbuf(c->data.png.png))) { - png_destroy_read_struct(&c->data.png.png, - &c->data.png.info, 0); + if (setjmp(png_jmpbuf(png->png))) { + png_destroy_read_struct(&png->png, &png->info, 0); LOG(("Failed to process data")); - c->data.png.png = NULL; - c->data.png.info = NULL; - if (c->data.png.bitmap != NULL) { - bitmap_destroy(c->data.png.bitmap); - c->data.png.bitmap = NULL; + png->png = NULL; + png->info = NULL; + if (png->bitmap != NULL) { + bitmap_destroy(png->bitmap); + png->bitmap = NULL; } msg_data.error = messages_get("PNGError"); @@ -124,8 +243,7 @@ bool nspng_process_data(struct content *c, const char *data, unsigned int size) return false; } - png_process_data(c->data.png.png, c->data.png.info, - (uint8_t *) data, size); + png_process_data(png->png, png->info, (uint8_t *) data, size); return true; } @@ -141,21 +259,21 @@ void info_callback(png_structp png, png_infop info) int bit_depth, color_type, interlace, intent; double gamma; png_uint_32 width, height; - struct content *c = png_get_progressive_ptr(png); + nspng_content *c = png_get_progressive_ptr(png); /* Read the PNG details */ png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace, 0, 0); /* Claim the required memory for the converted PNG */ - c->data.png.bitmap = bitmap_create(width, height, BITMAP_NEW); - if (c->data.png.bitmap == NULL) { + c->bitmap = bitmap_create(width, height, BITMAP_NEW); + if (c->bitmap == NULL) { /* Failed -- bail out */ longjmp(png_jmpbuf(png), 1); } - c->data.png.rowstride = bitmap_get_rowstride(c->data.png.bitmap); - c->data.png.bpp = bitmap_get_bpp(c->data.png.bitmap); + c->rowstride = bitmap_get_rowstride(c->bitmap); + c->bpp = bitmap_get_bpp(c->bitmap); /* Set up our transformations */ if (color_type == PNG_COLOR_TYPE_PALETTE) @@ -187,13 +305,13 @@ void info_callback(png_structp png, png_infop info) png_read_update_info(png, info); - c->data.png.rowbytes = png_get_rowbytes(png, info); - c->data.png.interlace = (interlace == PNG_INTERLACE_ADAM7); - c->width = width; - c->height = height; + c->rowbytes = png_get_rowbytes(png, info); + c->interlace = (interlace == PNG_INTERLACE_ADAM7); + c->base.width = width; + c->base.height = height; LOG(("size %li * %li, bpp %i, rowbytes %zu", (unsigned long)width, - (unsigned long)height, bit_depth, c->data.png.rowbytes)); + (unsigned long)height, bit_depth, c->rowbytes)); } @@ -205,13 +323,13 @@ static unsigned int interlace_row_step[8] = {8, 8, 8, 4, 4, 2, 2}; void row_callback(png_structp png, png_bytep new_row, png_uint_32 row_num, int pass) { - struct content *c = png_get_progressive_ptr(png); - unsigned long i, j, rowbytes = c->data.png.rowbytes; + nspng_content *c = png_get_progressive_ptr(png); + unsigned long i, j, rowbytes = c->rowbytes; unsigned int start, step; unsigned char *buffer, *row; /* Give up if there's no bitmap */ - if (c->data.png.bitmap == NULL) + if (c->bitmap == NULL) return; /* Abort if we've not got any data */ @@ -219,17 +337,17 @@ void row_callback(png_structp png, png_bytep new_row, return; /* Get bitmap buffer */ - buffer = bitmap_get_buffer(c->data.png.bitmap); + buffer = bitmap_get_buffer(c->bitmap); if (buffer == NULL) { /* No buffer, bail out */ longjmp(png_jmpbuf(png), 1); } /* Calculate address of row start */ - row = buffer + (c->data.png.rowstride * row_num); + row = buffer + (c->rowstride * row_num); /* Handle interlaced sprites using the Adam7 algorithm */ - if (c->data.png.interlace) { + if (c->interlace) { start = interlace_start[pass]; step = interlace_step[pass]; row_num = interlace_row_start[pass] + @@ -237,7 +355,7 @@ void row_callback(png_structp png, png_bytep new_row, /* Copy the data to our current row taking interlacing * into consideration */ - row = buffer + (c->data.png.rowstride * row_num); + row = buffer + (c->rowstride * row_num); for (j = 0, i = start; i < rowbytes; i += step) { row[i++] = new_row[j++]; @@ -260,14 +378,15 @@ void end_callback(png_structp png, png_infop info) bool nspng_convert(struct content *c) { + nspng_content *png = (nspng_content *) c; const char *data; unsigned long size; char title[100]; - assert(c->data.png.png != NULL); - assert(c->data.png.info != NULL); + assert(png->png != NULL); + assert(png->info != NULL); - if (c->data.png.bitmap == NULL) { + if (png->bitmap == NULL) { union content_msg_data msg_data; msg_data.error = messages_get("PNGError"); @@ -278,7 +397,7 @@ bool nspng_convert(struct content *c) data = content__get_source_data(c, &size); - png_destroy_read_struct(&c->data.png.png, &c->data.png.info, 0); + png_destroy_read_struct(&png->png, &png->info, 0); snprintf(title, sizeof(title), messages_get("PNGTitle"), c->width, c->height, size); @@ -286,7 +405,7 @@ bool nspng_convert(struct content *c) c->size += (c->width * c->height * 4); - c->bitmap = c->data.png.bitmap; + c->bitmap = png->bitmap; bitmap_set_opaque(c->bitmap, bitmap_test_opaque(c->bitmap)); bitmap_modified(c->bitmap); content_set_ready(c); @@ -299,9 +418,11 @@ bool nspng_convert(struct content *c) void nspng_destroy(struct content *c) { - if (c->data.png.bitmap != NULL) { - bitmap_destroy(c->data.png.bitmap); - } + nspng_content *png = (nspng_content *) c; + + if (png->bitmap != NULL) { + bitmap_destroy(png->bitmap); + } } @@ -333,28 +454,54 @@ bool nspng_redraw_tiled(struct content *c, int x, int y, background_colour, flags); } -bool nspng_clone(const struct content *old, struct content *new_content) +nserror nspng_clone(const struct content *old, struct content **newc) { + nspng_content *png; + nserror error; const char *data; unsigned long size; + png = talloc_zero(0, nspng_content); + if (png == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &png->base); + if (error != NSERROR_OK) { + content_destroy(&png->base); + return error; + } + /* Simply replay create/process/convert */ - if (nspng_create(new_content, NULL) == false) - return false; + error = nspng_create_png_data(png); + if (error != NSERROR_OK) { + content_destroy(&png->base); + return error; + } - data = content__get_source_data(new_content, &size); + data = content__get_source_data(&png->base, &size); if (size > 0) { - if (nspng_process_data(new_content, data, size) == false) - return false; + if (nspng_process_data(&png->base, data, size) == false) { + content_destroy(&png->base); + return NSERROR_NOMEM; + } } if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (nspng_convert(new_content) == false) - return false; + if (nspng_convert(&png->base) == false) { + content_destroy(&png->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) png; + + return NSERROR_OK; +} + +content_type nspng_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; } #endif diff --git a/image/png.h b/image/png.h index fb9efcfd4..1119b6a43 100644 --- a/image/png.h +++ b/image/png.h @@ -24,37 +24,17 @@ #ifdef WITH_PNG -#include "desktop/plot_style.h" - #include -#include - -struct content; -struct bitmap; -struct http_parameter; -struct rect; - -struct content_png_data { - png_structp png; - png_infop info; - int interlace; - struct bitmap *bitmap; /**< Created NetSurf bitmap */ - size_t rowstride, bpp; /**< Bitmap rowstride and bpp */ - size_t rowbytes; /**< Number of bytes per row */ -}; - -bool nspng_create(struct content *c, const struct http_parameter *params); -bool nspng_process_data(struct content *c, const char *data, unsigned int size); -bool nspng_convert(struct content *c); -void nspng_destroy(struct content *c); -bool nspng_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool nspng_redraw_tiled(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour, - bool repeat_x, bool repeat_y); -bool nspng_clone(const struct content *old, struct content *new_content); + +#include "utils/errors.h" + +nserror nspng_init(void); +void nspng_fini(void); + +#else + +#define nspng_init() NSERROR_OK +#define nspng_fini() ((void) 0) #endif diff --git a/image/rsvg.c b/image/rsvg.c index cf3d5cea6..26370de57 100644 --- a/image/rsvg.c +++ b/image/rsvg.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -46,33 +47,151 @@ #include "utils/messages.h" #include "utils/talloc.h" +typedef struct rsvg_content { + struct content base; + + RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */ + cairo_surface_t *cs; /**< The surface built inside a nsbitmap */ + cairo_t *ct; /**< Cairo drawing context */ + struct bitmap *bitmap; /**< Created NetSurf bitmap */ +} rsvg_content; + +static nserror rsvg_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static nserror rsvg_create_svg_data(rsvg_content *c); +static bool rsvg_process_data(struct content *c, const char *data, + unsigned int size); +static bool rsvg_convert(struct content *c); +static void rsvg_destroy(struct content *c); +static bool rsvg_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static nserror rsvg_clone(const struct content *old, struct content **newc); +static content_type rsvg_content_type(lwc_string *mime_type); + static inline void rsvg_argb_to_abgr(uint8_t *pixels, int width, int height, size_t rowstride); -bool rsvg_create(struct content *c, const struct http_parameter *params) +static const content_handler rsvg_content_handler = { + rsvg_create, + rsvg_process_data, + rsvg_convert, + NULL, + rsvg_destroy, + NULL, + NULL, + NULL, + rsvg_redraw, + NULL, + NULL, + NULL, + rsvg_clone, + NULL, + rsvg_content_type, + false +}; + +static const char *rsvg_types[] = { + "image/svg", + "image/svg+xml" +}; + +static lwc_string *rsvg_mime_types[NOF_ELEMENTS(rsvg_types)]; + +nserror nsrsvg_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(rsvg_mime_types); i++) { + lerror = lwc_intern_string(rsvg_types[i], + strlen(rsvg_types[i]), + &rsvg_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(rsvg_mime_types[i], + &rsvg_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + nsrsvg_fini(); + + return error; +} + +void nsrsvg_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(rsvg_mime_types); i++) { + if (rsvg_mime_types[i] != NULL) + lwc_string_unref(rsvg_mime_types[i]); + } +} + +nserror rsvg_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + rsvg_content *svg; + nserror error; + + svg = talloc_zero(0, rsvg_content); + if (svg == NULL) + return NSERROR_NOMEM; + + error = content__init(&svg->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(svg); + return error; + } + + error = rsvg_create_svg_data(svg); + if (error != NSERROR_OK) { + talloc_free(svg); + return error; + } + + *c = (struct content *) svg; + + return NSERROR_OK; +} + +nserror rsvg_create_svg_data(rsvg_content *c) { - struct content_rsvg_data *d = &c->data.rsvg; union content_msg_data msg_data; - d->rsvgh = NULL; - d->cs = NULL; - d->ct = NULL; - d->bitmap = NULL; + c->rsvgh = NULL; + c->cs = NULL; + c->ct = NULL; + c->bitmap = NULL; - if ((d->rsvgh = rsvg_handle_new()) == NULL) { + if ((c->rsvgh = rsvg_handle_new()) == NULL) { LOG(("rsvg_handle_new() returned NULL.")); msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } - return true; + return NSERROR_OK; } bool rsvg_process_data(struct content *c, const char *data, unsigned int size) { - struct content_rsvg_data *d = &c->data.rsvg; + rsvg_content *d = (rsvg_content *) c; union content_msg_data msg_data; GError *err = NULL; @@ -118,7 +237,7 @@ static inline void rsvg_argb_to_abgr(uint8_t *pixels, bool rsvg_convert(struct content *c) { - struct content_rsvg_data *d = &c->data.rsvg; + rsvg_content *d = (rsvg_content *) c; union content_msg_data msg_data; RsvgDimensionData rsvgsize; GError *err = NULL; @@ -191,7 +310,7 @@ bool rsvg_redraw(struct content *c, int x, int y, void rsvg_destroy(struct content *c) { - struct content_rsvg_data *d = &c->data.rsvg; + rsvg_content *d = (rsvg_content *) c; if (d->bitmap != NULL) bitmap_destroy(d->bitmap); if (d->rsvgh != NULL) rsvg_handle_free(d->rsvgh); @@ -201,28 +320,54 @@ void rsvg_destroy(struct content *c) return; } -bool rsvg_clone(const struct content *old, struct content *new_content) +nserror rsvg_clone(const struct content *old, struct content **newc) { + rsvg_content *svg; + nserror error; const char *data; unsigned long size; + svg = talloc_zero(0, rsvg_content); + if (svg == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &svg->base); + if (error != NSERROR_OK) { + content_destroy(&svg->base); + return error; + } + /* Simply replay create/process/convert */ - if (rsvg_create(new_content, NULL) == false) - return false; + error = rsvg_create_svg_data(svg); + if (error != NSERROR_OK) { + content_destroy(&svg->base); + return error; + } - data = content__get_source_data(new_content, &size); + data = content__get_source_data(&svg->base, &size); if (size > 0) { - if (rsvg_process_data(new_content, data, size) == false) - return false; + if (rsvg_process_data(&svg->base, data, size) == false) { + content_destroy(&svg->base); + return NSERROR_NOMEM; + } } if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (rsvg_convert(new_content) == false) - return false; + if (rsvg_convert(&svg->base) == false) { + content_destroy(&svg->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) svg; + + return NSERROR_OK; +} + +content_type rsvg_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; } #endif /* WITH_RSVG */ diff --git a/image/rsvg.h b/image/rsvg.h index 90b4ba8f3..4d4e65fea 100644 --- a/image/rsvg.h +++ b/image/rsvg.h @@ -27,30 +27,16 @@ #ifdef WITH_RSVG #include -#include -#include -#include "desktop/plot_style.h" -#include "image/bitmap.h" - -struct content; -struct http_parameter; -struct rect; - -struct content_rsvg_data { - RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */ - cairo_surface_t *cs; /**< The surface built inside a nsbitmap */ - cairo_t *ct; /**< Cairo drawing context */ - struct bitmap *bitmap; /**< Created NetSurf bitmap */ -}; - -bool rsvg_create(struct content *c, const struct http_parameter *params); -bool rsvg_process_data(struct content *c, const char *data, unsigned int size); -bool rsvg_convert(struct content *c); -void rsvg_destroy(struct content *c); -bool rsvg_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool rsvg_clone(const struct content *old, struct content *new_content); + +#include "utils/errors.h" + +nserror nsrsvg_init(void); +void nsrsvg_fini(void); + +#else + +#define nsrsvg_init() NSERROR_OK +#define nsrsvg_fini() ((void) 0) #endif /* WITH_RSVG */ diff --git a/image/svg.c b/image/svg.c index d77c8e03a..781a9af48 100644 --- a/image/svg.c +++ b/image/svg.c @@ -33,29 +33,145 @@ #include "desktop/plotters.h" #include "image/svg.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/utils.h" +typedef struct svg_content { + struct content base; + + struct svgtiny_diagram *diagram; + bool done_parse; +} svg_content; + +static nserror svg_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static nserror svg_create_svg_data(svg_content *c); +static bool svg_convert(struct content *c); +static void svg_destroy(struct content *c); +static void svg_reformat(struct content *c, int width, int height); +static bool svg_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static nserror svg_clone(const struct content *old, struct content **newc); +static content_type svg_content_type(lwc_string *mime_type); + +static const content_handler svg_content_handler = { + svg_create, + NULL, + svg_convert, + svg_reformat, + svg_destroy, + NULL, + NULL, + NULL, + svg_redraw, + NULL, + NULL, + NULL, + svg_clone, + NULL, + svg_content_type, + false +}; + +static const char *svg_types[] = { + "image/svg", + "image/svg+xml" +}; + +static lwc_string *svg_mime_types[NOF_ELEMENTS(svg_types)]; + +nserror svg_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(svg_mime_types); i++) { + lerror = lwc_intern_string(svg_types[i], + strlen(svg_types[i]), + &svg_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(svg_mime_types[i], + &svg_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + svg_fini(); + + return error; +} + +void svg_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(svg_mime_types); i++) { + if (svg_mime_types[i] != NULL) + lwc_string_unref(svg_mime_types[i]); + } +} /** * Create a CONTENT_SVG. */ -bool svg_create(struct content *c, const struct http_parameter *params) +nserror svg_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + svg_content *svg; + nserror error; + + svg = talloc_zero(0, svg_content); + if (svg == NULL) + return NSERROR_NOMEM; + + error = content__init(&svg->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(svg); + return error; + } + + error = svg_create_svg_data(svg); + if (error != NSERROR_OK) { + talloc_free(svg); + return error; + } + + *c = (struct content *) svg; + + return NSERROR_OK; +} + +nserror svg_create_svg_data(svg_content *c) { union content_msg_data msg_data; - c->data.svg.diagram = svgtiny_create(); - if (!c->data.svg.diagram) + c->diagram = svgtiny_create(); + if (c->diagram == NULL) goto no_memory; - c->data.svg.done_parse = false; + c->done_parse = false; - return true; + return NSERROR_OK; no_memory: msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; + content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } @@ -84,22 +200,23 @@ bool svg_convert(struct content *c) void svg_reformat(struct content *c, int width, int height) { + svg_content *svg = (svg_content *) c; const char *source_data; unsigned long source_size; - assert(c->data.svg.diagram); + assert(svg->diagram); - if (c->data.svg.done_parse == false) { + if (svg->done_parse == false) { source_data = content__get_source_data(c, &source_size); - svgtiny_parse(c->data.svg.diagram, source_data, source_size, + svgtiny_parse(svg->diagram, source_data, source_size, content__get_url(c), width, height); - c->data.svg.done_parse = true; + svg->done_parse = true; } - c->width = c->data.svg.diagram->width; - c->height = c->data.svg.diagram->height; + c->width = svg->diagram->width; + c->height = svg->diagram->height; } @@ -111,8 +228,9 @@ bool svg_redraw(struct content *c, int x, int y, int width, int height, const struct rect *clip, float scale, colour background_colour) { + svg_content *svg = (svg_content *) c; float transform[6]; - struct svgtiny_diagram *diagram = c->data.svg.diagram; + struct svgtiny_diagram *diagram = svg->diagram; bool ok; int px, py; unsigned int i; @@ -173,25 +291,51 @@ bool svg_redraw(struct content *c, int x, int y, void svg_destroy(struct content *c) { - if (c->data.svg.diagram) - svgtiny_free(c->data.svg.diagram); + svg_content *svg = (svg_content *) c; + + if (svg->diagram != NULL) + svgtiny_free(svg->diagram); } -bool svg_clone(const struct content *old, struct content *new_content) +nserror svg_clone(const struct content *old, struct content **newc) { + svg_content *svg; + nserror error; + + svg = talloc_zero(0, svg_content); + if (svg == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &svg->base); + if (error != NSERROR_OK) { + content_destroy(&svg->base); + return error; + } + /* Simply replay create/convert */ - if (svg_create(new_content, NULL) == false) - return false; + error = svg_create_svg_data(svg); + if (error != NSERROR_OK) { + content_destroy(&svg->base); + return error; + } if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (svg_convert(new_content) == false) - return false; + if (svg_convert(&svg->base) == false) { + content_destroy(&svg->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) svg; + + return NSERROR_OK; } +content_type svg_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; +} #endif /* WITH_NS_SVG */ diff --git a/image/svg.h b/image/svg.h index d836cb310..0e8ad8559 100644 --- a/image/svg.h +++ b/image/svg.h @@ -23,25 +23,22 @@ #ifndef _NETSURF_IMAGE_SVG_H_ #define _NETSURF_IMAGE_SVG_H_ +#include "utils/config.h" + +#ifdef WITH_NS_SVG + #include -struct content; -struct http_parameter; -struct svgtiny_diagram; -struct rect; - -struct content_svg_data { - struct svgtiny_diagram *diagram; - bool done_parse; -}; - -bool svg_create(struct content *c, const struct http_parameter *params); -bool svg_convert(struct content *c); -void svg_destroy(struct content *c); -void svg_reformat(struct content *c, int width, int height); -bool svg_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool svg_clone(const struct content *old, struct content *new_content); +#include "utils/errors.h" + +nserror svg_init(void); +void svg_fini(void); + +#else + +#define svg_init() NSERROR_OK +#define svg_fini() ((void) 0) + +#endif #endif diff --git a/image/webp.c b/image/webp.c index 439bdfc9b..a76c0918c 100644 --- a/image/webp.c +++ b/image/webp.c @@ -33,8 +33,114 @@ #include "content/content_protected.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/talloc.h" #include "utils/utils.h" +typedef struct webp_content +{ + struct content base; +} webp_content; + +static nserror webp_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c); +static bool webp_convert(struct content *c); +static void webp_destroy(struct content *c); +static bool webp_redraw(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); +static nserror webp_clone(const struct content *old, struct content **newc); +static content_type webp_content_type(lwc_string *mime_type); + +static const content_handler webp_content_handler = { + webp_create, + NULL, + webp_convert, + NULL, + webp_destroy, + NULL, + NULL, + NULL, + webp_redraw, + NULL, + NULL, + NULL, + webp_clone, + NULL, + webp_content_type, + false +}; + +static const char *webp_types[] = { + "image/webp" +}; + +static lwc_string *webp_mime_types[NOF_ELEMENTS(webp_types)]; + +nserror webp_init(void) +{ + uint32_t i; + lwc_error lerror; + nserror error; + + for (i = 0; i < NOF_ELEMENTS(webp_mime_types); i++) { + lerror = lwc_intern_string(webp_types[i], + strlen(webp_types[i]), + &webp_mime_types[i]); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + + error = content_factory_register_handler(webp_mime_types[i], + &webp_content_handler); + if (error != NSERROR_OK) + goto error; + } + + return NSERROR_OK; + +error: + webp_fini(); + + return error; +} + +void webp_fini(void) +{ + uint32_t i; + + for (i = 0; i < NOF_ELEMENTS(webp_mime_types); i++) { + if (webp_mime_types[i] != NULL) + lwc_string_unref(webp_mime_types[i]); + } +} + +nserror webp_create(const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + webp_content *webp; + nserror error; + + webp = talloc_zero(0, webp_content); + if (webp == NULL) + return NSERROR_NOMEM; + + error = content__init(&webp->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + talloc_free(webp); + return error; + } + + *c = (struct content *) webp; + + return NSERROR_OK; +} + /** * Convert a CONTENT_WEBP for display. * @@ -124,16 +230,38 @@ bool webp_redraw(struct content *c, int x, int y, } -bool webp_clone(const struct content *old, struct content *new_content) +nserror webp_clone(const struct content *old, struct content **newc) { + webp_content *webp; + nserror error; + + webp = talloc_zero(0, webp_content); + if (webp == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, &webp->base); + if (error != NSERROR_OK) { + content_destroy(&webp->base); + return error; + } + /* Simply replay convert */ if (old->status == CONTENT_STATUS_READY || old->status == CONTENT_STATUS_DONE) { - if (webp_convert(new_content) == false) - return false; + if (webp_convert(&webp->base) == false) { + content_destroy(&webp->base); + return NSERROR_CLONE_FAILED; + } } - return true; + *newc = (struct content *) webp; + + return NSERROR_OK; +} + +content_type webp_content_type(lwc_string *mime_type) +{ + return CONTENT_IMAGE; } #endif diff --git a/image/webp.h b/image/webp.h index a89713ac3..3d976d13e 100644 --- a/image/webp.h +++ b/image/webp.h @@ -28,19 +28,15 @@ #include -struct content; -struct rect; - -struct content_webp_data { -/* empty */ -}; - -bool webp_convert(struct content *c); -void webp_destroy(struct content *c); -bool webp_redraw(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); -bool webp_clone(const struct content *old, struct content *new_content); +#include "utils/errors.h" + +nserror webp_init(void); +void webp_fini(void); + +#else + +#define webp_init() NSERROR_OK +#define webp_fini() ((void) 0) #endif /* WITH_WEBP */ -- cgit v1.2.3