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 --- content/content.c | 613 +++++++------------------------------------- content/content.h | 10 +- content/content_factory.c | 195 ++++++++++++++ content/content_factory.h | 42 +++ content/content_protected.h | 158 ++++-------- content/content_type.h | 63 +---- content/hlcache.c | 39 +-- content/hlcache.h | 6 +- 8 files changed, 411 insertions(+), 715 deletions(-) create mode 100644 content/content_factory.c create mode 100644 content/content_factory.h (limited to 'content') diff --git a/content/content.c b/content/content.c index 95e5e049c..dd5c01ae7 100644 --- a/content/content.c +++ b/content/content.c @@ -40,52 +40,6 @@ #include "desktop/options.h" #include "render/html.h" #include "render/textplain.h" -#ifdef WITH_JPEG -#include "image/jpeg.h" -#endif -#ifdef WITH_MNG -#include "image/mng.h" -#endif -#ifdef WITH_GIF -#include "image/gif.h" -#endif -#ifdef WITH_BMP -#include "image/bmp.h" -#include "image/ico.h" -#endif -#ifdef WITH_NS_SVG -#include "image/svg.h" -#endif -#ifdef WITH_RSVG -#include "image/rsvg.h" -#endif -#ifdef WITH_SPRITE -#include "riscos/sprite.h" -#endif -#ifdef WITH_NSSPRITE -#include "image/nssprite.h" -#endif -#ifdef WITH_DRAW -#include "riscos/draw.h" -#endif -#ifdef WITH_PLUGIN -#include "desktop/plugin.h" -#endif -#ifdef WITH_ARTWORKS -#include "riscos/artworks.h" -#endif -#ifdef WITH_PNG -#include "image/png.h" -#endif -#ifdef WITH_WEBP -#include "image/webp.h" -#endif -#ifdef WITH_AMIGA_ICON -#include "amiga/icon.h" -#endif -#ifdef WITH_APPLE_IMAGE -#include "cocoa/apple_image.h" -#endif #include "utils/http.h" #include "utils/log.h" @@ -94,179 +48,6 @@ #include "utils/utils.h" -/** An entry in mime_map. */ -struct mime_entry { - char mime_type[40]; - content_type type; -}; -/** A map from MIME type to ::content_type. Must be sorted by mime_type. */ -static const struct mime_entry mime_map[] = { -#ifdef WITH_BMP - {"application/bmp", CONTENT_BMP}, -#endif -#ifdef WITH_DRAW - {"application/drawfile", CONTENT_DRAW}, -#endif -#ifdef WITH_BMP - {"application/ico", CONTENT_ICO}, - {"application/preview", CONTENT_BMP}, - {"application/x-bmp", CONTENT_BMP}, -#endif -#ifdef WITH_DRAW - {"application/x-drawfile", CONTENT_DRAW}, -#endif -#ifdef WITH_BMP - {"application/x-ico", CONTENT_ICO}, -#endif -#ifdef WITH_THEME_INSTALL - {"application/x-netsurf-theme", CONTENT_THEME}, -#endif -#ifdef WITH_BMP - {"application/x-win-bitmap", CONTENT_BMP}, -#endif - {"application/xhtml+xml", CONTENT_HTML}, -#ifdef WITH_BMP - {"image/bmp", CONTENT_BMP}, -#endif -#ifdef WITH_DRAW - {"image/drawfile", CONTENT_DRAW}, -#endif -#ifdef WITH_GIF - {"image/gif", CONTENT_GIF}, -#endif -#ifdef WITH_BMP - {"image/ico", CONTENT_ICO}, -#endif -#ifdef WITH_MNG - {"image/jng", CONTENT_JNG}, -#endif -#ifdef WITH_JPEG - {"image/jpeg", CONTENT_JPEG}, - {"image/jpg", CONTENT_JPEG}, -#endif -#ifdef WITH_APPLE_IMAGE - {"image/jpeg", CONTENT_APPLE_IMAGE}, - {"image/jpg", CONTENT_APPLE_IMAGE}, -#endif -#ifdef WITH_MNG - {"image/mng", CONTENT_MNG}, -#endif -#ifdef WITH_BMP - {"image/ms-bmp", CONTENT_BMP}, -#endif -#ifdef WITH_JPEG - {"image/pjpeg", CONTENT_JPEG}, -#endif -#ifdef WITH_APPLE_IMAGE - {"image/pjpeg", CONTENT_APPLE_IMAGE}, -#endif -#if defined(WITH_MNG) || defined(WITH_PNG) - {"image/png", CONTENT_PNG}, -#endif -#if defined(WITH_NS_SVG) || defined (WITH_RSVG) - {"image/svg", CONTENT_SVG}, - {"image/svg+xml", CONTENT_SVG}, -#endif -#ifdef WITH_BMP - {"image/vnd.microsoft.icon", CONTENT_ICO}, -#endif -#ifdef WITH_WEBP - {"image/webp", CONTENT_WEBP}, -#endif -#ifdef WITH_AMIGA_ICON - {"image/x-amiga-icon", CONTENT_AMIGA_ICON}, -#endif -#ifdef WITH_ARTWORKS - {"image/x-artworks", CONTENT_ARTWORKS}, -#endif -#ifdef WITH_BMP - {"image/x-bitmap", CONTENT_BMP}, - {"image/x-bmp", CONTENT_BMP}, -#endif -#ifdef WITH_DRAW - {"image/x-drawfile", CONTENT_DRAW}, -#endif -#ifdef WITH_BMP - {"image/x-icon", CONTENT_ICO}, -#endif -#ifdef WITH_MNG - {"image/x-jng", CONTENT_JNG}, - {"image/x-mng", CONTENT_MNG}, -#endif -#ifdef WITH_BMP - {"image/x-ms-bmp", CONTENT_BMP}, -#endif -#if defined(WITH_SPRITE) || defined(WITH_NSSPRITE) - {"image/x-riscos-sprite", CONTENT_SPRITE}, -#endif -#ifdef WITH_BMP - {"image/x-win-bitmap", CONTENT_BMP}, - {"image/x-windows-bmp", CONTENT_BMP}, - {"image/x-xbitmap", CONTENT_BMP}, -#endif - {"text/css", CONTENT_CSS}, - {"text/html", CONTENT_HTML}, - {"text/plain", CONTENT_TEXTPLAIN}, -#ifdef WITH_MNG - {"video/mng", CONTENT_MNG}, - {"video/x-mng", CONTENT_MNG}, -#endif -}; -#define MIME_MAP_COUNT (sizeof(mime_map) / sizeof(mime_map[0])) - -const char * const content_type_name[] = { - "HTML", - "TEXTPLAIN", - "CSS", -#ifdef WITH_JPEG - "JPEG", -#endif -#ifdef WITH_GIF - "GIF", -#endif -#ifdef WITH_BMP - "BMP", - "ICO", -#endif -#if defined(WITH_MNG) || defined(WITH_PNG) - "PNG", -#endif -#ifdef WITH_MNG - "JNG", - "MNG", -#endif -#if defined(WITH_SPRITE) || defined(WITH_NSSPRITE) - "SPRITE", -#endif -#ifdef WITH_DRAW - "DRAW", -#endif -#ifdef WITH_PLUGIN - "PLUGIN", -#endif - "DIRECTORY", -#ifdef WITH_THEME_INSTALL - "THEME", -#endif -#ifdef WITH_ARTWORKS - "ARTWORKS", -#endif -#if defined(WITH_NS_SVG) || defined(WITH_RSVG) - "SVG", -#endif -#ifdef WITH_WEBP - "WEBP", -#endif -#ifdef WITH_AMIGA_ICON - "AMIGA_ICON", -#endif -#ifdef WITH_APPLE_IMAGE - "APPLE_IMAGE", -#endif - "OTHER", - "UNKNOWN" -}; - const char * const content_status_name[] = { "LOADING", "READY", @@ -274,139 +55,6 @@ const char * const content_status_name[] = { "ERROR" }; -/** An entry in handler_map. */ -struct handler_entry { - bool (*create)(struct content *c, const http_parameter *params); - bool (*process_data)(struct content *c, - const char *data, unsigned int size); - bool (*convert)(struct content *c); - void (*reformat)(struct content *c, int width, int height); - void (*destroy)(struct content *c); - void (*stop)(struct content *c); - void (*mouse_track)(struct content *c, struct browser_window *bw, - browser_mouse_state mouse, int x, int y); - void (*mouse_action)(struct content *c, struct browser_window *bw, - browser_mouse_state mouse, int x, int y); - bool (*redraw)(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - float scale, colour background_colour); - bool (*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); - void (*open)(struct content *c, struct browser_window *bw, - struct content *page, - struct box *box, - struct object_params *params); - void (*close)(struct content *c); - bool (*clone)(const struct content *old, struct content *new_content); - /** There must be one content per user for this type. */ - bool no_share; -}; -/** A table of handler functions, indexed by ::content_type. - * Must be ordered as enum ::content_type. */ -static const struct handler_entry handler_map[] = { - {html_create, html_process_data, html_convert, - html_reformat, html_destroy, html_stop, html_mouse_track, - html_mouse_action, html_redraw, 0, html_open, html_close, - html_clone, true}, - {textplain_create, textplain_process_data, textplain_convert, - textplain_reformat, textplain_destroy, 0, textplain_mouse_track, - textplain_mouse_action, textplain_redraw, 0, 0, 0, - textplain_clone, true}, - {nscss_create, nscss_process_data, nscss_convert, 0, nscss_destroy, - 0, 0, 0, 0, 0, 0, 0, nscss_clone, false}, -#ifdef WITH_JPEG - {0, 0, nsjpeg_convert, 0, nsjpeg_destroy, 0, 0, 0, - nsjpeg_redraw, nsjpeg_redraw_tiled, 0, 0, nsjpeg_clone, false}, -#endif -#ifdef WITH_GIF - {nsgif_create, 0, nsgif_convert, 0, nsgif_destroy, 0, 0, 0, - nsgif_redraw, nsgif_redraw_tiled, 0, 0, nsgif_clone, false}, -#endif -#ifdef WITH_BMP - {nsbmp_create, 0, nsbmp_convert, 0, nsbmp_destroy, 0, 0, 0, - nsbmp_redraw, nsbmp_redraw_tiled, 0, 0, nsbmp_clone, false}, - {nsico_create, 0, nsico_convert, 0, nsico_destroy, 0, 0, 0, - nsico_redraw, nsico_redraw_tiled, 0, 0, nsico_clone, false}, -#endif - -#ifdef WITH_PNG - {nspng_create, nspng_process_data, nspng_convert, - 0, nspng_destroy, 0, 0, 0, nspng_redraw, nspng_redraw_tiled, - 0, 0, nspng_clone, false}, -#else -#ifdef WITH_MNG - {nsmng_create, nsmng_process_data, nsmng_convert, - 0, nsmng_destroy, 0, 0, 0, nsmng_redraw, nsmng_redraw_tiled, - 0, 0, nsmng_clone, false}, -#endif -#endif -#ifdef WITH_MNG - {nsmng_create, nsmng_process_data, nsmng_convert, - 0, nsmng_destroy, 0, 0, 0, nsmng_redraw, nsmng_redraw_tiled, - 0, 0, nsmng_clone, false}, - {nsmng_create, nsmng_process_data, nsmng_convert, - 0, nsmng_destroy, 0, 0, 0, nsmng_redraw, nsmng_redraw_tiled, - 0, 0, nsmng_clone, false}, -#endif -#ifdef WITH_SPRITE - {0, 0, sprite_convert, - 0, sprite_destroy, 0, 0, 0, sprite_redraw, 0, - 0, 0, sprite_clone, false}, -#endif -#ifdef WITH_NSSPRITE - {0, 0, nssprite_convert, - 0, nssprite_destroy, 0, 0, 0, nssprite_redraw, 0, - 0, 0, nssprite_clone, false}, -#endif -#ifdef WITH_DRAW - {0, 0, draw_convert, - 0, draw_destroy, 0, 0, 0, draw_redraw, 0, 0, 0, draw_clone, - false}, -#endif -#ifdef WITH_PLUGIN - {plugin_create, 0, plugin_convert, - plugin_reformat, plugin_destroy, 0, 0, 0, plugin_redraw, 0, - plugin_open, plugin_close, plugin_clone, - true}, -#endif -#ifdef WITH_THEME_INSTALL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}, -#endif -#ifdef WITH_ARTWORKS - {0, 0, artworks_convert, - 0, artworks_destroy, 0, 0, 0, artworks_redraw, 0, - 0, 0, artworks_clone, false}, -#endif -#ifdef WITH_NS_SVG - {svg_create, 0, svg_convert, - svg_reformat, svg_destroy, 0, 0, 0, svg_redraw, 0, - 0, 0, svg_clone, true}, -#endif -#ifdef WITH_RSVG - {rsvg_create, rsvg_process_data, rsvg_convert, - 0, rsvg_destroy, 0, 0, 0, rsvg_redraw, 0, 0, 0, rsvg_clone, - false}, -#endif -#ifdef WITH_WEBP - {0, 0, webp_convert, - 0, webp_destroy, 0, 0, 0, webp_redraw, 0, - 0, 0, webp_clone, false}, -#endif -#ifdef WITH_AMIGA_ICON - {0, 0, amiga_icon_convert, - 0, amiga_icon_destroy, 0, 0, 0, amiga_icon_redraw, 0, - 0, 0, amiga_icon_clone, false}, -#endif -#ifdef WITH_APPLE_IMAGE - {0, 0, apple_image_convert, 0, apple_image_destroy, 0, 0, 0, - apple_image_redraw, apple_image_redraw_tiled, 0, 0, apple_image_clone, false}, -#endif - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false} -}; -#define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0])) - static nserror content_llcache_callback(llcache_handle *llcache, const llcache_event *event, void *pw); static void content_convert(struct content *c); @@ -414,95 +62,41 @@ static void content_update_status(struct content *c); /** - * Convert a MIME type to a content_type. + * Initialise a new content structure. * - * The returned ::content_type will always be suitable for content_create(). - */ - -content_type content_lookup(const char *mime_type) -{ - struct mime_entry *m; - m = bsearch(mime_type, mime_map, MIME_MAP_COUNT, sizeof(mime_map[0]), - (int (*)(const void *, const void *)) strcasecmp); - if (m == 0) { -#ifdef WITH_PLUGIN - if (plugin_handleable(mime_type)) - return CONTENT_PLUGIN; -#endif - return CONTENT_OTHER; - } - return m->type; -} - - -/** - * Create a new content structure. - * - * \param url URL of content, copied - * \return the new content structure, or 0 on memory exhaustion + * \param c Content to initialise (allocated with talloc) + * \param handler Content handler + * \param imime_type MIME type of content + * \param params HTTP parameters + * \param llcache Source data handle + * \param fallback_charset Fallback charset + * \param quirks Quirkiness of content + * \return NSERROR_OK on success, appropriate error otherwise */ -struct content * content_create(llcache_handle *llcache, - const char *fallback_charset, bool quirks) +nserror content__init(struct content *c, const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks) { - struct content *c; struct content_user *user_sentinel; - const char *content_type_header; - content_type type; - char *mime_type; - http_parameter *params; nserror error; - content_type_header = - llcache_handle_get_header(llcache, "Content-Type"); - if (content_type_header == NULL) - content_type_header = "text/plain"; - - error = http_parse_content_type(content_type_header, &mime_type, - ¶ms); - if (error != NSERROR_OK) - return NULL; - - type = content_lookup(mime_type); - - c = talloc_zero(0, struct content); - if (c == NULL) { - http_parameter_list_destroy(params); - free(mime_type); - return NULL; - } - LOG(("url %s -> %p", llcache_handle_get_url(llcache), c)); user_sentinel = talloc(c, struct content_user); if (user_sentinel == NULL) { - talloc_free(c); - http_parameter_list_destroy(params); - free(mime_type); - return NULL; + return NSERROR_NOMEM; } c->fallback_charset = talloc_strdup(c, fallback_charset); if (fallback_charset != NULL && c->fallback_charset == NULL) { - talloc_free(c); - http_parameter_list_destroy(params); - free(mime_type); - return NULL; - } - - c->mime_type = talloc_strdup(c, mime_type); - if (c->mime_type == NULL) { - talloc_free(c); - http_parameter_list_destroy(params); - free(mime_type); - return NULL; + return NSERROR_NOMEM; } - /* No longer require mime_type */ - free(mime_type); - c->llcache = llcache; - c->type = type; + c->mime_type = lwc_string_ref(imime_type); + c->handler = handler; c->status = CONTENT_STATUS_LOADING; c->width = 0; c->height = 0; @@ -526,24 +120,15 @@ struct content * content_create(llcache_handle *llcache, content_set_status(c, messages_get("Loading")); - if (handler_map[type].create) { - if (handler_map[type].create(c, params) == false) { - talloc_free(c); - http_parameter_list_destroy(params); - return NULL; - } - } - - http_parameter_list_destroy(params); - /* Finally, claim low-level cache events */ - if (llcache_handle_change_callback(llcache, - content_llcache_callback, c) != NSERROR_OK) { - talloc_free(c); - return NULL; + error = llcache_handle_change_callback(llcache, + content_llcache_callback, c); + if (error != NSERROR_OK) { + lwc_string_unref(c->mime_type); + return error; } - return c; + return NSERROR_OK; } /** @@ -566,8 +151,8 @@ nserror content_llcache_callback(llcache_handle *llcache, /* Will never happen: handled in hlcache */ break; case LLCACHE_EVENT_HAD_DATA: - if (handler_map[c->type].process_data) { - if (handler_map[c->type].process_data(c, + if (c->handler->process_data != NULL) { + if (c->handler->process_data(c, (const char *) event->data.data.buf, event->data.data.len) == false) { llcache_handle_abort(c->llcache); @@ -618,7 +203,7 @@ bool content_can_reformat(hlcache_handle *h) if (c == NULL) return false; - return (handler_map[c->type].reformat != NULL); + return (c->handler->reformat != NULL); } @@ -687,7 +272,6 @@ void content_update_status(struct content *c) void content_convert(struct content *c) { assert(c); - assert(c->type < HANDLER_MAP_COUNT); assert(c->status == CONTENT_STATUS_LOADING || c->status == CONTENT_STATUS_ERROR); @@ -699,9 +283,9 @@ void content_convert(struct content *c) LOG(("content %s (%p)", llcache_handle_get_url(c->llcache), c)); - if (handler_map[c->type].convert) { + if (c->handler->convert != NULL) { c->locked = true; - if (handler_map[c->type].convert(c) == false) { + if (c->handler->convert(c) == false) { c->locked = false; c->status = CONTENT_STATUS_ERROR; } @@ -766,8 +350,8 @@ void content__reformat(struct content *c, int width, int height) LOG(("%p %s", c, llcache_handle_get_url(c->llcache))); c->locked = true; c->available_width = width; - if (handler_map[c->type].reformat) { - handler_map[c->type].reformat(c, width, height); + if (c->handler->reformat != NULL) { + c->handler->reformat(c, width, height); content_broadcast(c, CONTENT_MSG_REFORMAT, data); } c->locked = false; @@ -786,12 +370,14 @@ void content_destroy(struct content *c) LOG(("content %p %s", c, llcache_handle_get_url(c->llcache))); assert(c->locked == false); - if (c->type < HANDLER_MAP_COUNT && handler_map[c->type].destroy) - handler_map[c->type].destroy(c); + if (c->handler->destroy != NULL) + c->handler->destroy(c); llcache_handle_release(c->llcache); c->llcache = NULL; + lwc_string_unref(c->mime_type); + talloc_free(c); } @@ -812,8 +398,9 @@ void content_mouse_track(hlcache_handle *h, struct browser_window *bw, struct content *c = hlcache_handle_get_content(h); assert(c != NULL); - if (handler_map[c->type].mouse_track) - handler_map[c->type].mouse_track(c, bw, mouse, x, y); + if (c->handler->mouse_track != NULL) + c->handler->mouse_track(c, bw, mouse, x, y); + return; } @@ -840,8 +427,9 @@ void content_mouse_action(hlcache_handle *h, struct browser_window *bw, struct content *c = hlcache_handle_get_content(h); assert(c != NULL); - if (handler_map[c->type].mouse_action) - handler_map[c->type].mouse_action(c, bw, mouse, x, y); + if (c->handler->mouse_action != NULL) + c->handler->mouse_action(c, bw, mouse, x, y); + return; } @@ -925,11 +513,11 @@ bool content_redraw(hlcache_handle *h, int x, int y, return true; } - if (handler_map[c->type].redraw == NULL) { + if (c->handler->redraw == NULL) { return true; } - return handler_map[c->type].redraw(c, x, y, width, height, + return c->handler->redraw(c, x, y, width, height, clip, scale, background_colour); } @@ -956,18 +544,19 @@ bool content_redraw_tiled(hlcache_handle *h, int x, int y, if (c->locked) /* not safe to attempt redraw */ return true; - if (handler_map[c->type].redraw_tiled) { - return handler_map[c->type].redraw_tiled(c, x, y, width, height, + + if (c->handler->redraw_tiled != NULL) { + return c->handler->redraw_tiled(c, x, y, width, height, clip, scale, background_colour, repeat_x, repeat_y); } else { /* ensure we have a redrawable content */ - if ((!handler_map[c->type].redraw) || (width == 0) || + if ((c->handler->redraw == NULL) || (width == 0) || (height == 0)) return true; /* simple optimisation for no repeat (common for backgrounds) */ if ((!repeat_x) && (!repeat_y)) - return handler_map[c->type].redraw(c, x, y, width, + return c->handler->redraw(c, x, y, width, height, clip, scale, background_colour); /* find the redraw boundaries to loop within*/ x0 = x; @@ -987,7 +576,7 @@ bool content_redraw_tiled(hlcache_handle *h, int x, int y, /* repeatedly plot our content */ for (y = y0; y < y1; y += height) for (x = x0; x < x1; x += width) - if (!handler_map[c->type].redraw(c, x, y, + if (!c->handler->redraw(c, x, y, width, height, clip, scale, background_colour)) return false; @@ -1086,11 +675,10 @@ uint32_t content_count_users(struct content *c) */ bool content_matches_quirks(struct content *c, bool quirks) { - /* If the content isn't CSS, we don't care about quirks */ - if (c->type != CONTENT_CSS) + if (c->handler->matches_quirks == NULL) return true; - return c->quirks == quirks; + return c->handler->matches_quirks(c, quirks); } /** @@ -1101,7 +689,7 @@ bool content_matches_quirks(struct content *c, bool quirks) */ bool content_is_shareable(struct content *c) { - return handler_map[c->type].no_share == false; + return c->handler->no_share == false; } /** @@ -1141,10 +729,9 @@ void content_open(hlcache_handle *h, struct browser_window *bw, { struct content *c = hlcache_handle_get_content(h); assert(c != 0); - assert(c->type < CONTENT_UNKNOWN); LOG(("content %p %s", c, llcache_handle_get_url(c->llcache))); - if (handler_map[c->type].open) - handler_map[c->type].open(c, bw, page, box, params); + if (c->handler->open != NULL) + c->handler->open(c, bw, page, box, params); } @@ -1158,10 +745,9 @@ void content_close(hlcache_handle *h) { struct content *c = hlcache_handle_get_content(h); assert(c != 0); - assert(c->type < CONTENT_UNKNOWN); LOG(("content %p %s", c, llcache_handle_get_url(c->llcache))); - if (handler_map[c->type].close) - handler_map[c->type].close(c); + if (c->handler->close != NULL) + c->handler->close(c); } @@ -1185,41 +771,38 @@ bool content__set_title(struct content *c, const char *title) } /** - * Retrieve type of content + * Retrieve computed type of content * * \param c Content to retrieve type of - * \return Content type + * \return Computed content type */ content_type content_get_type(hlcache_handle *h) { - return content__get_type(hlcache_handle_get_content(h)); -} + struct content *c = hlcache_handle_get_content(h); -content_type content__get_type(struct content *c) -{ if (c == NULL) - return CONTENT_UNKNOWN; + return CONTENT_NONE; - return c->type; + return c->handler->type(c->mime_type); } /** * Retrieve mime-type of content * * \param c Content to retrieve mime-type of - * \return Pointer to mime-type, or NULL if not found. + * \return Pointer to referenced mime-type, or NULL if not found. */ -const char *content_get_mime_type(hlcache_handle *h) +lwc_string *content_get_mime_type(hlcache_handle *h) { return content__get_mime_type(hlcache_handle_get_content(h)); } -const char *content__get_mime_type(struct content *c) +lwc_string *content__get_mime_type(struct content *c) { if (c == NULL) return NULL; - return c->mime_type; + return lwc_string_ref(c->mime_type); } /** @@ -1501,29 +1084,37 @@ const llcache_handle *content_get_llcache_handle(struct content *c) */ struct content *content_clone(struct content *c) { - struct content *nc = talloc_zero(0, struct content); + struct content *nc; + nserror error; - if (nc == NULL) { - return NULL; - } - - if (llcache_handle_clone(c->llcache, &(nc->llcache)) != NSERROR_OK) { - content_destroy(nc); + error = c->handler->clone(c, &nc); + if (error != NSERROR_OK) return NULL; + + return nc; +}; + +/** + * Clone a content's data members + * + * \param c Content to clone + * \param nc Content to populate (allocated with talloc) + * \return NSERROR_OK on success, appropriate error otherwise + */ +nserror content__clone(const struct content *c, struct content *nc) +{ + nserror error; + + error = llcache_handle_clone(c->llcache, &(nc->llcache)); + if (error != NSERROR_OK) { + return error; } llcache_handle_change_callback(nc->llcache, content_llcache_callback, nc); - - nc->type = c->type; - if (c->mime_type != NULL) { - nc->mime_type = talloc_strdup(nc, c->mime_type); - if (nc->mime_type == NULL) { - content_destroy(nc); - return NULL; - } - } + nc->mime_type = lwc_string_ref(c->mime_type); + nc->handler = c->handler; nc->status = c->status; @@ -1535,16 +1126,14 @@ struct content *content_clone(struct content *c) if (c->fallback_charset != NULL) { nc->fallback_charset = talloc_strdup(nc, c->fallback_charset); if (nc->fallback_charset == NULL) { - content_destroy(nc); - return NULL; + return NSERROR_NOMEM; } } if (c->refresh != NULL) { nc->refresh = talloc_strdup(nc, c->refresh); if (nc->refresh == NULL) { - content_destroy(nc); - return NULL; + return NSERROR_NOMEM; } } @@ -1556,8 +1145,7 @@ struct content *content_clone(struct content *c) if (c->title != NULL) { nc->title = talloc_strdup(nc, c->title); if (nc->title == NULL) { - content_destroy(nc); - return NULL; + return NSERROR_NOMEM; } } @@ -1570,15 +1158,7 @@ struct content *content_clone(struct content *c) nc->total_size = c->total_size; nc->http_code = c->http_code; - /* Duplicate the data member (and bitmap, if appropriate) */ - if (handler_map[nc->type].clone != NULL) { - if (handler_map[nc->type].clone(c, nc) == false) { - content_destroy(nc); - return NULL; - } - } - - return nc; + return NSERROR_OK; } /** @@ -1592,13 +1172,8 @@ nserror content_abort(struct content *c) LOG(("Aborting %p", c)); if (c->status == CONTENT_STATUS_READY) { - switch (c->type) { - case CONTENT_HTML: - html_stop(c); - break; - default: - LOG(("Unable to abort sub-parts for type %d", c->type)); - } + if (c->handler->stop != NULL) + c->handler->stop(c); } /* And for now, abort our llcache object */ diff --git a/content/content.h b/content/content.h index 0bb40779f..b3e0b1ce2 100644 --- a/content/content.h +++ b/content/content.h @@ -28,8 +28,12 @@ #include +#include + #include "utils/config.h" #include "utils/errors.h" +#include "utils/http.h" +#include "content/content_factory.h" #include "content/content_type.h" #include "desktop/mouse.h" #include "desktop/plot_style.h" @@ -88,11 +92,7 @@ union content_msg_data { struct llcache_handle *download; }; - /* The following are for hlcache */ -content_type content_lookup(const char *mime_type); -struct content *content_create(struct llcache_handle *llcache, - const char *fallback_charset, bool quirks); void content_destroy(struct content *c); bool content_add_user(struct content *h, @@ -138,7 +138,7 @@ void content_close(struct hlcache_handle *h); /* Member accessors */ content_type content_get_type(struct hlcache_handle *c); -const char *content_get_mime_type(struct hlcache_handle *c); +lwc_string *content_get_mime_type(struct hlcache_handle *c); const char *content_get_url(struct hlcache_handle *c); const char *content_get_title(struct hlcache_handle *c); content_status content_get_status(struct hlcache_handle *c); diff --git a/content/content_factory.c b/content/content_factory.c new file mode 100644 index 000000000..95e7679ad --- /dev/null +++ b/content/content_factory.c @@ -0,0 +1,195 @@ +/* + * 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 + * Content factory (implementation) + */ + +#include +#include +#include + +#include "content/content.h" +#include "content/content_factory.h" +#include "content/content_protected.h" +#include "content/llcache.h" + +/** + * Entry in list of content handlers + */ +typedef struct content_handler_entry { + /** Next entry */ + struct content_handler_entry *next; + + /** MIME type handled by handler */ + lwc_string *mime_type; + /** Content handler object */ + const content_handler *handler; +} content_handler_entry; + +static content_handler_entry *content_handlers; + +/** + * Register a handler with the content factory + * + * \param mime_type MIME type to handle + * \param handler Content handler for MIME type + * \return NSERROR_OK on success, appropriate error otherwise + * + * \note Latest registration for a MIME type wins + */ +nserror content_factory_register_handler(lwc_string *mime_type, + const content_handler *handler) +{ + content_handler_entry *entry; + bool match; + + for (entry = content_handlers; entry != NULL; entry = entry->next) { + if (lwc_string_caseless_isequal(mime_type, entry->mime_type, + &match) == lwc_error_ok && match) + break; + } + + if (entry == NULL) { + entry = malloc(sizeof(content_handler_entry)); + if (entry == NULL) + return NSERROR_NOMEM; + + entry->next = content_handlers; + content_handlers = entry; + + entry->mime_type = lwc_string_ref(mime_type); + } + + entry->handler = handler; + + return NSERROR_OK; +} + +/** + * Find a handler for a MIME type. + * + * \param mime_type MIME type to search for + * \return Associated handler, or NULL if none + */ +static const content_handler *content_lookup(lwc_string *mime_type) +{ + content_handler_entry *entry; + bool match; + + for (entry = content_handlers; entry != NULL; entry = entry->next) { + if (lwc_string_caseless_isequal(mime_type, entry->mime_type, + &match) == lwc_error_ok && match) + break; + } + + if (entry != NULL) + return entry->handler; + + return NULL; +} + +/** + * Compute the generic content type for a MIME type + * + * \param mime_type MIME type to consider + * \return Generic content type + */ +content_type content_factory_type_from_mime_type(const char *mime_type) +{ + const content_handler *handler; + lwc_string *imime_type; + lwc_error lerror; + content_type type = CONTENT_NONE; + + lerror = lwc_intern_string(mime_type, strlen(mime_type), &imime_type); + if (lerror != lwc_error_ok) + return CONTENT_NONE; + + handler = content_lookup(imime_type); + if (handler != NULL) { + type = handler->type(imime_type); + } + + lwc_string_unref(imime_type); + + return type; +} + +/** + * Create a content object + * + * \param llcache Underlying source data handle + * \param fallback_charset Character set to fall back to if none specified + * \param quirks Quirkiness of containing document + * \return Pointer to content object, or NULL on failure + */ +struct content *content_factory_create_content(llcache_handle *llcache, + const char *fallback_charset, bool quirks) +{ + struct content *c; + const char *content_type_header; + const content_handler *handler; + char *mime_type; + http_parameter *params; + lwc_string *imime_type; + lwc_error lerr; + nserror error; + + content_type_header = + llcache_handle_get_header(llcache, "Content-Type"); + if (content_type_header == NULL) + content_type_header = "text/plain"; + + error = http_parse_content_type(content_type_header, &mime_type, + ¶ms); + if (error != NSERROR_OK) + return NULL; + + lerr = lwc_intern_string(mime_type, strlen(mime_type), &imime_type); + if (lerr != lwc_error_ok) { + http_parameter_list_destroy(params); + free(mime_type); + return NULL; + } + + free(mime_type); + + handler = content_lookup(imime_type); + if (handler == NULL) { + lwc_string_unref(imime_type); + http_parameter_list_destroy(params); + return NULL; + } + + assert(handler->create != NULL); + + error = handler->create(handler, imime_type, params, llcache, + fallback_charset, quirks, &c); + if (error != NSERROR_OK) { + lwc_string_unref(imime_type); + http_parameter_list_destroy(params); + return NULL; + } + + lwc_string_unref(imime_type); + http_parameter_list_destroy(params); + + return c; +} + diff --git a/content/content_factory.h b/content/content_factory.h new file mode 100644 index 000000000..330ce6812 --- /dev/null +++ b/content/content_factory.h @@ -0,0 +1,42 @@ +/* + * 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 . + */ + +#ifndef NETSURF_CONTENT_CONTENT_FACTORY_H_ +#define NETSURF_CONTENT_CONTENT_FACTORY_H_ + +#include + +#include + +#include "content/content_type.h" +#include "utils/errors.h" + +struct content; +struct llcache_handle; + +typedef struct content_handler content_handler; + +nserror content_factory_register_handler(lwc_string *mime_type, + const content_handler *handler); + +struct content *content_factory_create_content(struct llcache_handle *llcache, + const char *fallback_charset, bool quirks); + +content_type content_factory_type_from_mime_type(const char *mime_type); + +#endif diff --git a/content/content_protected.h b/content/content_protected.h index a37d96c42..1d88de972 100644 --- a/content/content_protected.h +++ b/content/content_protected.h @@ -26,68 +26,53 @@ #ifndef _NETSURF_CONTENT_CONTENT_PROTECTED_H_ #define _NETSURF_CONTENT_CONTENT_PROTECTED_H_ -/* Irritatingly this must come first, or odd include errors - * will occur to do with setjmp.h. - */ -#ifdef WITH_PNG -#include "image/png.h" -#endif - #include #include #include "utils/config.h" #include "content/content.h" +#include "content/content_factory.h" #include "content/llcache.h" -#include "css/css.h" -#include "render/html.h" -#include "render/textplain.h" -#ifdef WITH_JPEG -#include "image/jpeg.h" -#endif -#ifdef WITH_GIF -#include "image/gif.h" -#endif -#ifdef WITH_BMP -#include "image/bmp.h" -#include "image/ico.h" -#endif -#ifdef WITH_PLUGIN -#include "desktop/plugin.h" -#endif -#ifdef WITH_MNG -#include "image/mng.h" -#endif -#ifdef WITH_SPRITE -#include "riscos/sprite.h" -#endif -#ifdef WITH_NSSPRITE -#include "image/nssprite.h" -#endif -#ifdef WITH_DRAW -#include "riscos/draw.h" -#endif -#ifdef WITH_ARTWORKS -#include "riscos/artworks.h" -#endif -#ifdef WITH_NS_SVG -#include "image/svg.h" -#endif -#ifdef WITH_RSVG -#include "image/rsvg.h" -#endif -#ifdef WITH_WEBP -#include "image/webp.h" -#endif -#ifdef WITH_AMIGA_ICON -#include "amiga/icon.h" -#endif -#ifdef WITH_APPLE_IMAGE -#include "cocoa/apple_image.h" -#endif +#include "utils/errors.h" struct bitmap; struct content; +struct content_handler { + nserror (*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); + + bool (*process_data)(struct content *c, + const char *data, unsigned int size); + bool (*convert)(struct content *c); + void (*reformat)(struct content *c, int width, int height); + void (*destroy)(struct content *c); + void (*stop)(struct content *c); + void (*mouse_track)(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); + void (*mouse_action)(struct content *c, struct browser_window *bw, + browser_mouse_state mouse, int x, int y); + bool (*redraw)(struct content *c, int x, int y, + int width, int height, const struct rect *clip, + float scale, colour background_colour); + bool (*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); + void (*open)(struct content *c, struct browser_window *bw, + struct content *page, + struct box *box, + struct object_params *params); + void (*close)(struct content *c); + nserror (*clone)(const struct content *old, struct content **newc); + bool (*matches_quirks)(const struct content *c, bool quirks); + content_type (*type)(lwc_string *mime_type); + /** There must be one content per user for this type. */ + bool no_share; +}; + /** Linked list of users of a content. */ struct content_user { @@ -102,8 +87,9 @@ struct content_user struct content { llcache_handle *llcache; /**< Low-level cache object */ - content_type type; /**< Type of content. */ - char *mime_type; /**< Original MIME type of data, or 0. */ + lwc_string *mime_type; /**< Original MIME type of data */ + + const content_handler *handler; /**< Handler for content */ content_status status; /**< Current status. */ @@ -113,59 +99,6 @@ struct content { bool quirks; /**< Content is in quirks mode */ char *fallback_charset; /**< Fallback charset, or NULL */ - /** Data dependent on type. */ - union { - struct content_html_data html; - struct content_textplain_data textplain; - struct content_css_data css; -#ifdef WITH_JPEG - struct content_jpeg_data jpeg; -#endif -#ifdef WITH_GIF - struct content_gif_data gif; -#endif -#ifdef WITH_BMP - struct content_bmp_data bmp; - struct content_ico_data ico; -#endif -#ifdef WITH_MNG - struct content_mng_data mng; -#endif -#ifdef WITH_SPRITE - struct content_sprite_data sprite; -#endif -#ifdef WITH_NSSPRITE - struct content_nssprite_data nssprite; -#endif -#ifdef WITH_DRAW - struct content_draw_data draw; -#endif -#ifdef WITH_PLUGIN - struct content_plugin_data plugin; -#endif -#ifdef WITH_ARTWORKS - struct content_artworks_data artworks; -#endif -#ifdef WITH_NS_SVG - struct content_svg_data svg; -#endif -#ifdef WITH_RSVG - struct content_rsvg_data rsvg; -#endif -#ifdef WITH_PNG - struct content_png_data png; -#endif -#ifdef WITH_WEBP - struct content_webp_data webp; -#endif -#ifdef WITH_AMIGA_ICON - struct content_amiga_icon_data amiga_icon; -#endif -#ifdef WITH_APPLE_IMAGE - struct content_apple_image_data apple_image; -#endif - } data; - /**< URL for refresh request, in standard form as from url_join. */ char *refresh; @@ -208,6 +141,12 @@ struct content { extern const char * const content_type_name[]; extern const char * const content_status_name[]; +nserror content__init(struct content *c, const content_handler *handler, + lwc_string *imime_type, const http_parameter *params, + struct llcache_handle *llcache, const char *fallback_charset, + bool quirks); +nserror content__clone(const struct content *c, struct content *nc); + void content_set_ready(struct content *c); void content_set_done(struct content *c); void content_set_status(struct content *c, const char *status_message, ...); @@ -220,8 +159,7 @@ void content__reformat(struct content *c, int width, int height); bool content__set_title(struct content *c, const char *title); -content_type content__get_type(struct content *c); -const char *content__get_mime_type(struct content *c); +lwc_string *content__get_mime_type(struct content *c); const char *content__get_url(struct content *c); const char *content__get_title(struct content *c); const char *content__get_status_message(struct content *c); diff --git a/content/content_type.h b/content/content_type.h index 0b086a599..8e24e4e8e 100644 --- a/content/content_type.h +++ b/content/content_type.h @@ -30,56 +30,19 @@ /** The type of a content. */ typedef enum { - CONTENT_HTML, - CONTENT_TEXTPLAIN, - CONTENT_CSS, -#ifdef WITH_JPEG - CONTENT_JPEG, -#endif -#ifdef WITH_GIF - CONTENT_GIF, -#endif -#ifdef WITH_BMP - CONTENT_BMP, - CONTENT_ICO, -#endif -#if defined(WITH_MNG) || defined(WITH_PNG) - CONTENT_PNG, -#endif -#ifdef WITH_MNG - CONTENT_JNG, - CONTENT_MNG, -#endif -#if defined(WITH_SPRITE) || defined(WITH_NSSPRITE) - CONTENT_SPRITE, -#endif -#ifdef WITH_DRAW - CONTENT_DRAW, -#endif -#ifdef WITH_PLUGIN - CONTENT_PLUGIN, -#endif -#ifdef WITH_THEME_INSTALL - CONTENT_THEME, -#endif -#ifdef WITH_ARTWORKS - CONTENT_ARTWORKS, -#endif -#if defined(WITH_NS_SVG) || defined(WITH_RSVG) - CONTENT_SVG, -#endif -#ifdef WITH_WEBP - CONTENT_WEBP, -#endif -#ifdef WITH_AMIGA_ICON - CONTENT_AMIGA_ICON, -#endif -#ifdef WITH_APPLE_IMAGE - CONTENT_APPLE_IMAGE, -#endif - /* these must be the last two */ - CONTENT_OTHER, - CONTENT_UNKNOWN /**< content-type not received yet */ + CONTENT_NONE = 0x00, + + CONTENT_HTML = 0x01, + CONTENT_TEXTPLAIN = 0x02, + CONTENT_CSS = 0x04, + + CONTENT_IMAGE = 0x08, + + CONTENT_PLUGIN = 0x10, + + CONTENT_THEME = 0x20, + + CONTENT_ANY = 0x3f } content_type; diff --git a/content/hlcache.c b/content/hlcache.c index a53db5d9f..b684ed01c 100644 --- a/content/hlcache.c +++ b/content/hlcache.c @@ -48,7 +48,7 @@ struct hlcache_retrieval_ctx { uint32_t flags; /**< Retrieval flags */ - const content_type *accepted_types; /**< Accepted types, or NULL */ + content_type accepted_types; /**< Accepted types */ hlcache_child_context child; /**< Child context */ }; @@ -80,8 +80,7 @@ static void hlcache_clean(void *ignored); static nserror hlcache_llcache_callback(llcache_handle *handle, const llcache_event *event, void *pw); static bool hlcache_type_is_acceptable(llcache_handle *llcache, - const content_type *accepted_types, - content_type *computed_type); + content_type accepted_types, content_type *computed_type); static nserror hlcache_find_content(hlcache_retrieval_ctx *ctx); static void hlcache_content_callback(struct content *c, content_msg msg, union content_msg_data data, void *pw); @@ -124,7 +123,7 @@ void hlcache_finalise(void) num_contents++; } - LOG(("%d contents to before cache drain", num_contents)); + LOG(("%d contents remain before cache drain", num_contents)); /* Drain cache */ do { @@ -189,7 +188,7 @@ nserror hlcache_handle_retrieve(const char *url, uint32_t flags, const char *referer, llcache_post_data *post, hlcache_handle_callback cb, void *pw, hlcache_child_context *child, - const content_type *accepted_types, hlcache_handle **result) + content_type accepted_types, hlcache_handle **result) { hlcache_retrieval_ctx *ctx; nserror error; @@ -449,7 +448,7 @@ nserror hlcache_llcache_callback(llcache_handle *handle, switch (event->type) { case LLCACHE_EVENT_HAD_HEADERS: { - content_type type = CONTENT_UNKNOWN; + content_type type = 0; /* Unlink the context to prevent recursion */ RING_REMOVE(hlcache_retrieval_ctx_ring, ctx); @@ -472,8 +471,8 @@ nserror hlcache_llcache_callback(llcache_handle *handle, free(ctx); return error; } - } else if (type == CONTENT_OTHER && - ctx->flags & HLCACHE_RETRIEVE_MAY_DOWNLOAD) { + } else if (type == CONTENT_NONE && + (ctx->flags & HLCACHE_RETRIEVE_MAY_DOWNLOAD)) { /* Unknown type, and we can download, so convert */ llcache_handle_force_stream(handle); @@ -539,14 +538,13 @@ nserror hlcache_llcache_callback(llcache_handle *handle, * \return True if the type is acceptable, false otherwise */ bool hlcache_type_is_acceptable(llcache_handle *llcache, - const content_type *accepted_types, content_type *computed_type) + content_type accepted_types, content_type *computed_type) { const char *content_type_header; char *mime_type; http_parameter *params; content_type type; nserror error; - bool acceptable; content_type_header = llcache_handle_get_header(llcache, "Content-Type"); @@ -558,27 +556,14 @@ bool hlcache_type_is_acceptable(llcache_handle *llcache, if (error != NSERROR_OK) return false; - type = content_lookup(mime_type); + type = content_factory_type_from_mime_type(mime_type); free(mime_type); http_parameter_list_destroy(params); - if (accepted_types == NULL) { - acceptable = type != CONTENT_OTHER; - } else { - while (*accepted_types != CONTENT_UNKNOWN) { - if (*accepted_types == type) - break; - - accepted_types++; - } - - acceptable = *accepted_types == type; - } - *computed_type = type; - return acceptable; + return ((accepted_types & type) != 0); } /** @@ -614,7 +599,7 @@ nserror hlcache_find_content(hlcache_retrieval_ctx *ctx) continue; /* Ensure that quirks mode is acceptable */ - if (content_matches_quirks(entry->content, + if (content_matches_quirks(entry->content, ctx->child.quirks) == false) continue; @@ -634,7 +619,7 @@ nserror hlcache_find_content(hlcache_retrieval_ctx *ctx) return NSERROR_NOMEM; /* Create content using llhandle */ - entry->content = content_create(ctx->llcache, + entry->content = content_factory_create_content(ctx->llcache, ctx->child.charset, ctx->child.quirks); if (entry->content == NULL) { free(entry); diff --git a/content/hlcache.h b/content/hlcache.h index c4e10915a..2372158e1 100644 --- a/content/hlcache.h +++ b/content/hlcache.h @@ -101,7 +101,7 @@ nserror hlcache_poll(void); * \param cb Callback to handle object events * \param pw Pointer to client-specific data for callback * \param child Child retrieval context, or NULL for top-level content - * \param accepted_types Array of acceptable content types, or NULL for any + * \param accepted_types Bitmap of acceptable content types * \param result Pointer to location to recieve cache handle * \return NSERROR_OK on success, appropriate error otherwise * @@ -109,8 +109,6 @@ nserror hlcache_poll(void); * The quirks field is ignored for child contents whose behaviour is not * affected by quirks mode. * - * The \a accepted_types array must be terminated with CONTENT_UNKNOWN - * * \todo The above rules should be encoded in the handler_map. * * \todo Is there any way to sensibly reduce the number of parameters here? @@ -119,7 +117,7 @@ nserror hlcache_handle_retrieve(const char *url, uint32_t flags, const char *referer, llcache_post_data *post, hlcache_handle_callback cb, void *pw, hlcache_child_context *child, - const content_type *accepted_types, hlcache_handle **result); + content_type accepted_types, hlcache_handle **result); /** * Release a high-level cache handle -- cgit v1.2.3