diff options
author | Vincent Sanders <vince@kyllikki.org> | 2016-05-26 11:18:41 +0100 |
---|---|---|
committer | Vincent Sanders <vince@kyllikki.org> | 2016-05-26 11:18:41 +0100 |
commit | 6722943b81c0dba84ed187b2d117cc92972117ed (patch) | |
tree | 5de3de53a92696c9a4b9edcfd54e7f608ad2fb04 /css/css.c | |
parent | c25eb6b7e7a08d7e2aaf33994c2c24053cf47b82 (diff) | |
download | netsurf-6722943b81c0dba84ed187b2d117cc92972117ed.tar.gz netsurf-6722943b81c0dba84ed187b2d117cc92972117ed.tar.bz2 |
move the CSS content handler
Diffstat (limited to 'css/css.c')
-rw-r--r-- | css/css.c | 847 |
1 files changed, 0 insertions, 847 deletions
diff --git a/css/css.c b/css/css.c deleted file mode 100644 index 66dc6d4ba..000000000 --- a/css/css.c +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <assert.h> -#include <libwapcaplet/libwapcaplet.h> -#include <dom/dom.h> - -#include "content/content_protected.h" -#include "content/fetch.h" -#include "content/hlcache.h" -#include "desktop/system_colour.h" -#include "utils/corestrings.h" -#include "utils/utils.h" -#include "utils/http.h" -#include "utils/log.h" -#include "utils/messages.h" - -#include "css/css.h" -#include "css/hints.h" -#include "css/internal.h" - -/* Define to trace import fetches */ -#undef NSCSS_IMPORT_TRACE - -struct content_css_data; - -/** - * Type of callback called when a CSS object has finished - * - * \param css CSS object that has completed - * \param pw Client-specific data - */ -typedef void (*nscss_done_callback)(struct content_css_data *css, void *pw); - -/** - * CSS content data - */ -struct content_css_data -{ - css_stylesheet *sheet; /**< Stylesheet object */ - char *charset; /**< Character set of stylesheet */ - struct nscss_import *imports; /**< Array of imported sheets */ - uint32_t import_count; /**< Number of sheets imported */ - uint32_t next_to_register; /**< Index of next import to register */ - nscss_done_callback done; /**< Completion callback */ - void *pw; /**< Client data */ -}; - -/** - * CSS content data - */ -typedef struct nscss_content -{ - struct content base; /**< Underlying content object */ - - struct content_css_data data; /**< CSS data */ -} nscss_content; - -/** - * Context for import fetches - */ -typedef struct { - struct content_css_data *css; /**< Object containing import */ - uint32_t index; /**< Index into parent sheet's - * imports array */ -} nscss_import_ctx; - -static bool nscss_process_data(struct content *c, const char *data, - unsigned int size); -static bool nscss_convert(struct content *c); -static void nscss_destroy(struct content *c); -static nserror nscss_clone(const struct content *old, struct content **newc); -static bool nscss_matches_quirks(const struct content *c, bool quirks); -static content_type nscss_content_type(void); - -static nserror nscss_create_css_data(struct content_css_data *c, - const char *url, const char *charset, bool quirks, - nscss_done_callback done, void *pw); -static css_error nscss_process_css_data(struct content_css_data *c, const char *data, - unsigned int size); -static css_error nscss_convert_css_data(struct content_css_data *c); -static void nscss_destroy_css_data(struct content_css_data *c); - -static void nscss_content_done(struct content_css_data *css, void *pw); -static css_error nscss_handle_import(void *pw, css_stylesheet *parent, - lwc_string *url, uint64_t media); -static nserror nscss_import(hlcache_handle *handle, - const hlcache_event *event, void *pw); -static css_error nscss_import_complete(nscss_import_ctx *ctx); - -static css_error nscss_register_imports(struct content_css_data *c); -static css_error nscss_register_import(struct content_css_data *c, - const hlcache_handle *import); - - -static css_stylesheet *blank_import; - - -/** - * Initialise a CSS content - * - * \param handler content handler - * \param imime_type mime-type - * \param params Content-Type parameters - * \param llcache handle to content - * \param fallback_charset The character set to fallback to. - * \param quirks allow quirks - * \param c Content to initialise - * \return NSERROR_OK or error cod eon faliure - */ -static nserror -nscss_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) -{ - nscss_content *result; - const char *charset = NULL; - const char *xnsbase = NULL; - lwc_string *charset_value = NULL; - union content_msg_data msg_data; - nserror error; - - result = calloc(1, sizeof(nscss_content)); - if (result == NULL) - return NSERROR_NOMEM; - - error = content__init(&result->base, handler, imime_type, - params, llcache, fallback_charset, quirks); - if (error != NSERROR_OK) { - free(result); - return error; - } - - /* Find charset specified on HTTP layer, if any */ - error = http_parameter_list_find_item(params, corestring_lwc_charset, - &charset_value); - if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) { - /* No charset specified, use fallback, if any */ - /** \todo libcss will take this as gospel, which is wrong */ - charset = fallback_charset; - } else { - charset = lwc_string_data(charset_value); - } - - /* Compute base URL for stylesheet */ - xnsbase = llcache_handle_get_header(llcache, "X-NS-Base"); - if (xnsbase == NULL) { - xnsbase = nsurl_access(content_get_url(&result->base)); - } - - error = nscss_create_css_data(&result->data, - xnsbase, charset, result->base.quirks, - nscss_content_done, result); - if (error != NSERROR_OK) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data); - if (charset_value != NULL) - lwc_string_unref(charset_value); - free(result); - return error; - } - - if (charset_value != NULL) - lwc_string_unref(charset_value); - - *c = (struct content *) result; - - return NSERROR_OK; -} - -/** - * Create a struct content_css_data, creating a stylesheet object - * - * \param c Struct to populate - * \param url URL of stylesheet - * \param charset Stylesheet charset - * \param quirks Stylesheet quirks mode - * \param done Callback to call when content has completed - * \param pw Client data for \a done - * \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion - */ -static nserror nscss_create_css_data(struct content_css_data *c, - const char *url, const char *charset, bool quirks, - nscss_done_callback done, void *pw) -{ - css_error error; - css_stylesheet_params params; - - c->pw = pw; - c->done = done; - c->next_to_register = (uint32_t) -1; - c->import_count = 0; - c->imports = NULL; - if (charset != NULL) - c->charset = strdup(charset); - else - c->charset = NULL; - - params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; - params.level = CSS_LEVEL_DEFAULT; - params.charset = charset; - params.url = url; - params.title = NULL; - params.allow_quirks = quirks; - params.inline_style = false; - params.resolve = nscss_resolve_url; - params.resolve_pw = NULL; - params.import = nscss_handle_import; - params.import_pw = c; - params.color = ns_system_colour; - params.color_pw = NULL; - params.font = NULL; - params.font_pw = NULL; - - error = css_stylesheet_create(¶ms, &c->sheet); - if (error != CSS_OK) { - return NSERROR_NOMEM; - } - - return NSERROR_OK; -} - -/** - * Process CSS source data - * - * \param c Content structure - * \param data Data to process - * \param size Number of bytes to process - * \return true on success, false on failure - */ -bool nscss_process_data(struct content *c, const char *data, unsigned int size) -{ - nscss_content *css = (nscss_content *) c; - union content_msg_data msg_data; - css_error error; - - error = nscss_process_css_data(&css->data, data, size); - if (error != CSS_OK && error != CSS_NEEDDATA) { - msg_data.error = "?"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - } - - return (error == CSS_OK || error == CSS_NEEDDATA); -} - -/** - * Process CSS data - * - * \param c CSS content object - * \param data Data to process - * \param size Number of bytes to process - * \return CSS_OK on success, appropriate error otherwise - */ -static css_error nscss_process_css_data(struct content_css_data *c, - const char *data, unsigned int size) -{ - return css_stylesheet_append_data(c->sheet, - (const uint8_t *) data, size); -} - -/** - * Convert a CSS content ready for use - * - * \param c Content to convert - * \return true on success, false on failure - */ -bool nscss_convert(struct content *c) -{ - nscss_content *css = (nscss_content *) c; - union content_msg_data msg_data; - css_error error; - - error = nscss_convert_css_data(&css->data); - if (error != CSS_OK) { - msg_data.error = "?"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - } - - return true; -} - -/** - * Convert CSS data ready for use - * - * \param c CSS data to convert - * \return CSS error - */ -static css_error nscss_convert_css_data(struct content_css_data *c) -{ - css_error error; - - error = css_stylesheet_data_done(c->sheet); - - /* Process pending imports */ - if (error == CSS_IMPORTS_PENDING) { - /* We must not have registered any imports yet */ - assert(c->next_to_register == (uint32_t) -1); - - /* Start registering, until we find one that - * hasn't finished fetching */ - c->next_to_register = 0; - error = nscss_register_imports(c); - } else if (error == CSS_OK) { - /* No imports, and no errors, so complete conversion */ - c->done(c, c->pw); - } else { - const char *url; - - if (css_stylesheet_get_url(c->sheet, &url) == CSS_OK) { - LOG("Failed converting %p %s (%d)", c, url, error); - } else { - LOG("Failed converting %p (%d)", c, error); - } - } - - return error; -} - -/** - * Clean up a CSS content - * - * \param c Content to clean up - */ -void nscss_destroy(struct content *c) -{ - nscss_content *css = (nscss_content *) c; - - nscss_destroy_css_data(&css->data); -} - -/** - * Clean up CSS data - * - * \param c CSS data to clean up - */ -static void nscss_destroy_css_data(struct content_css_data *c) -{ - uint32_t i; - - for (i = 0; i < c->import_count; i++) { - if (c->imports[i].c != NULL) { - hlcache_handle_release(c->imports[i].c); - } - c->imports[i].c = NULL; - } - - free(c->imports); - - if (c->sheet != NULL) { - css_stylesheet_destroy(c->sheet); - c->sheet = NULL; - } - - free(c->charset); -} - -nserror nscss_clone(const struct content *old, struct content **newc) -{ - const nscss_content *old_css = (const nscss_content *) old; - nscss_content *new_css; - const char *data; - unsigned long size; - nserror error; - - new_css = calloc(1, sizeof(nscss_content)); - if (new_css == NULL) - return NSERROR_NOMEM; - - /* Clone content */ - error = content__clone(old, &new_css->base); - if (error != NSERROR_OK) { - content_destroy(&new_css->base); - return error; - } - - /* Simply replay create/process/convert */ - error = nscss_create_css_data(&new_css->data, - nsurl_access(content_get_url(&new_css->base)), - old_css->data.charset, - new_css->base.quirks, - nscss_content_done, new_css); - if (error != NSERROR_OK) { - content_destroy(&new_css->base); - return error; - } - - data = content__get_source_data(&new_css->base, &size); - if (size > 0) { - if (nscss_process_data(&new_css->base, data, size) == false) { - content_destroy(&new_css->base); - return NSERROR_CLONE_FAILED; - } - } - - if (old->status == CONTENT_STATUS_READY || - old->status == CONTENT_STATUS_DONE) { - if (nscss_convert(&new_css->base) == false) { - content_destroy(&new_css->base); - return NSERROR_CLONE_FAILED; - } - } - - *newc = (struct content *) new_css; - - return NSERROR_OK; -} - -bool nscss_matches_quirks(const struct content *c, bool quirks) -{ - return c->quirks == quirks; -} - -/** - * Retrieve the stylesheet object associated with a CSS content - * - * \param h Stylesheet content - * \return Pointer to stylesheet object - */ -css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h) -{ - nscss_content *c = (nscss_content *) hlcache_handle_get_content(h); - - assert(c != NULL); - - return c->data.sheet; -} - -/** - * Retrieve imported stylesheets - * - * \param h Stylesheet containing imports - * \param n Pointer to location to receive number of imports - * \return Pointer to array of imported stylesheets - */ -struct nscss_import *nscss_get_imports(hlcache_handle *h, uint32_t *n) -{ - nscss_content *c = (nscss_content *) hlcache_handle_get_content(h); - - assert(c != NULL); - assert(n != NULL); - - *n = c->data.import_count; - - return c->data.imports; -} - -/** - * Compute the type of a content - * - * \return CONTENT_CSS - */ -content_type nscss_content_type(void) -{ - return CONTENT_CSS; -} - -/***************************************************************************** - * Object completion * - *****************************************************************************/ - -/** - * Handle notification that a CSS object is done - * - * \param css CSS object - * \param pw Private data - */ -void nscss_content_done(struct content_css_data *css, void *pw) -{ - union content_msg_data msg_data; - struct content *c = pw; - uint32_t i; - size_t size; - css_error error; - - /* Retrieve the size of this sheet */ - error = css_stylesheet_size(css->sheet, &size); - if (error != CSS_OK) { - msg_data.error = "?"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - content_set_error(c); - return; - } - c->size += size; - - /* Add on the size of the imported sheets */ - for (i = 0; i < css->import_count; i++) { - if (css->imports[i].c != NULL) { - struct content *import = hlcache_handle_get_content( - css->imports[i].c); - - if (import != NULL) { - c->size += import->size; - } - } - } - - /* Finally, catch the content's users up with reality */ - content_set_ready(c); - content_set_done(c); -} - -/***************************************************************************** - * Import handling * - *****************************************************************************/ - -/** - * Handle notification of the need for an imported stylesheet - * - * \param pw CSS object requesting the import - * \param parent Stylesheet requesting the import - * \param url URL of the imported sheet - * \param media Applicable media for the imported sheet - * \return CSS_OK on success, appropriate error otherwise - */ -css_error nscss_handle_import(void *pw, css_stylesheet *parent, - lwc_string *url, uint64_t media) -{ - content_type accept = CONTENT_CSS; - struct content_css_data *c = pw; - nscss_import_ctx *ctx; - hlcache_child_context child; - struct nscss_import *imports; - const char *referer; - css_error error; - nserror nerror; - - nsurl *ns_url; - nsurl *ns_ref; - - assert(parent == c->sheet); - - error = css_stylesheet_get_url(c->sheet, &referer); - if (error != CSS_OK) { - return error; - } - - ctx = malloc(sizeof(*ctx)); - if (ctx == NULL) - return CSS_NOMEM; - - ctx->css = c; - ctx->index = c->import_count; - - /* Increase space in table */ - imports = realloc(c->imports, (c->import_count + 1) * - sizeof(struct nscss_import)); - if (imports == NULL) { - free(ctx); - return CSS_NOMEM; - } - c->imports = imports; - - /** \todo fallback charset */ - child.charset = NULL; - error = css_stylesheet_quirks_allowed(c->sheet, &child.quirks); - if (error != CSS_OK) { - free(ctx); - return error; - } - - /* Create content */ - c->imports[c->import_count].media = media; - - /** \todo Why aren't we getting a relative url part, to join? */ - nerror = nsurl_create(lwc_string_data(url), &ns_url); - if (nerror != NSERROR_OK) { - free(ctx); - return CSS_NOMEM; - } - - /** \todo Constructing nsurl for referer here is silly, avoid */ - nerror = nsurl_create(referer, &ns_ref); - if (nerror != NSERROR_OK) { - nsurl_unref(ns_url); - free(ctx); - return CSS_NOMEM; - } - - /* Avoid importing ourself */ - if (nsurl_compare(ns_url, ns_ref, NSURL_COMPLETE)) { - c->imports[c->import_count].c = NULL; - /* No longer require context as we're not fetching anything */ - free(ctx); - ctx = NULL; - } else { - nerror = hlcache_handle_retrieve(ns_url, - 0, ns_ref, NULL, nscss_import, ctx, - &child, accept, - &c->imports[c->import_count].c); - if (nerror != NSERROR_OK) { - free(ctx); - return CSS_NOMEM; - } - } - - nsurl_unref(ns_url); - nsurl_unref(ns_ref); - -#ifdef NSCSS_IMPORT_TRACE - LOG("Import %d '%s' -> (handle: %p ctx: %p)", c->import_count, lwc_string_data(url), c->imports[c->import_count].c, ctx); -#endif - - c->import_count++; - - return CSS_OK; -} - -/** - * Handler for imported stylesheet events - * - * \param handle Handle for stylesheet - * \param event Event object - * \param pw Callback context - * \return NSERROR_OK on success, appropriate error otherwise - */ -nserror nscss_import(hlcache_handle *handle, - const hlcache_event *event, void *pw) -{ - nscss_import_ctx *ctx = pw; - css_error error = CSS_OK; - -#ifdef NSCSS_IMPORT_TRACE - LOG("Event %d for %p (%p)", event->type, handle, ctx); -#endif - - assert(ctx->css->imports[ctx->index].c == handle); - - switch (event->type) { - case CONTENT_MSG_DONE: - error = nscss_import_complete(ctx); - break; - - case CONTENT_MSG_ERROR: - hlcache_handle_release(handle); - ctx->css->imports[ctx->index].c = NULL; - - error = nscss_import_complete(ctx); - /* Already released handle */ - break; - - default: - break; - } - - /* Preserve out-of-memory. Anything else is OK */ - return error == CSS_NOMEM ? NSERROR_NOMEM : NSERROR_OK; -} - -/** - * Handle an imported stylesheet completing - * - * \param ctx Import context - * \return CSS_OK on success, appropriate error otherwise - */ -css_error nscss_import_complete(nscss_import_ctx *ctx) -{ - css_error error = CSS_OK; - - /* If this import is the next to be registered, do so */ - if (ctx->css->next_to_register == ctx->index) - error = nscss_register_imports(ctx->css); - -#ifdef NSCSS_IMPORT_TRACE - LOG("Destroying import context %p for %d", ctx, ctx->index); -#endif - - /* No longer need import context */ - free(ctx); - - return error; -} - -/***************************************************************************** - * Import registration * - *****************************************************************************/ - -/** - * Register imports with a stylesheet - * - * \param c CSS object containing the imports - * \return CSS_OK on success, appropriate error otherwise - */ -css_error nscss_register_imports(struct content_css_data *c) -{ - uint32_t index; - css_error error; - - assert(c->next_to_register != (uint32_t) -1); - assert(c->next_to_register < c->import_count); - - /* Register imported sheets */ - for (index = c->next_to_register; index < c->import_count; index++) { - /* Stop registering if we encounter one whose fetch hasn't - * completed yet. We'll resume at this point when it has - * completed. - */ - if (c->imports[index].c != NULL && - content_get_status(c->imports[index].c) != - CONTENT_STATUS_DONE) { - break; - } - - error = nscss_register_import(c, c->imports[index].c); - if (error != CSS_OK) - return error; - } - - /* Record identity of the next import to register */ - c->next_to_register = (uint32_t) index; - - if (c->next_to_register == c->import_count) { - /* No more imports: notify parent that we're DONE */ - c->done(c, c->pw); - } - - return CSS_OK; -} - - -/** - * Register an import with a stylesheet - * - * \param c CSS object that requested the import - * \param import Cache handle of import, or NULL for blank - * \return CSS_OK on success, appropriate error otherwise - */ -css_error nscss_register_import(struct content_css_data *c, - const hlcache_handle *import) -{ - css_stylesheet *sheet; - css_error error; - - if (import != NULL) { - nscss_content *s = - (nscss_content *) hlcache_handle_get_content(import); - sheet = s->data.sheet; - } else { - /* Create a blank sheet if needed. */ - if (blank_import == NULL) { - css_stylesheet_params params; - - params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; - params.level = CSS_LEVEL_DEFAULT; - params.charset = NULL; - params.url = ""; - params.title = NULL; - params.allow_quirks = false; - params.inline_style = false; - params.resolve = nscss_resolve_url; - params.resolve_pw = NULL; - params.import = NULL; - params.import_pw = NULL; - params.color = ns_system_colour; - params.color_pw = NULL; - params.font = NULL; - params.font_pw = NULL; - - error = css_stylesheet_create(¶ms, &blank_import); - if (error != CSS_OK) { - return error; - } - - error = css_stylesheet_data_done(blank_import); - if (error != CSS_OK) { - css_stylesheet_destroy(blank_import); - return error; - } - } - - sheet = blank_import; - } - - error = css_stylesheet_register_import(c->sheet, sheet); - if (error != CSS_OK) { - return error; - } - - return error; -} - -/** - * Clean up after the CSS content handler - */ -static void nscss_fini(void) -{ - if (blank_import != NULL) { - css_stylesheet_destroy(blank_import); - blank_import = NULL; - } - css_hint_fini(); -} - -static const content_handler css_content_handler = { - .fini = nscss_fini, - .create = nscss_create, - .process_data = nscss_process_data, - .data_complete = nscss_convert, - .destroy = nscss_destroy, - .clone = nscss_clone, - .matches_quirks = nscss_matches_quirks, - .type = nscss_content_type, - .no_share = false, -}; - -/** - * Initialise the CSS content handler - */ -nserror nscss_init(void) -{ - nserror error; - - error = content_factory_register_handler("text/css", - &css_content_handler); - if (error != NSERROR_OK) - goto error; - - error = css_hint_init(); - if (error != NSERROR_OK) - goto error; - - return NSERROR_OK; - -error: - nscss_fini(); - - return error; -} |