diff options
Diffstat (limited to 'render/html.c')
-rw-r--r-- | render/html.c | 682 |
1 files changed, 17 insertions, 665 deletions
diff --git a/render/html.c b/render/html.c index aeb5a5b73..37178de9c 100644 --- a/render/html.c +++ b/render/html.c @@ -72,48 +72,6 @@ static const char *html_types[] = { /* forward declared functions */ static void html_object_refresh(void *p); -/* pre-interned character set */ -static lwc_string *html_charset; - -static nsurl *html_default_stylesheet_url; -static nsurl *html_adblock_stylesheet_url; -static nsurl *html_quirks_stylesheet_url; -static nsurl *html_user_stylesheet_url; - -static nserror css_error_to_nserror(css_error error) -{ - switch (error) { - case CSS_OK: - return NSERROR_OK; - - case CSS_NOMEM: - return NSERROR_NOMEM; - - case CSS_BADPARM: - return NSERROR_BAD_PARAMETER; - - case CSS_INVALID: - return NSERROR_INVALID; - - case CSS_FILENOTFOUND: - return NSERROR_NOT_FOUND; - - case CSS_NEEDDATA: - return NSERROR_NEED_DATA; - - case CSS_BADCHARSET: - return NSERROR_BAD_ENCODING; - - case CSS_EOF: - case CSS_IMPORTS_PENDING: - case CSS_PROPERTY_NOT_SET: - default: - break; - } - return NSERROR_CSS; -} - - static void html_destroy_objects(html_content *html) { while (html->object_list != NULL) { @@ -218,8 +176,6 @@ void html_finish_conversion(html_content *c) union content_msg_data msg_data; dom_exception exc; /* returned by libdom functions */ dom_node *html; - uint32_t i; - css_error css_ret; nserror error; /* Bail out if we've been aborted */ @@ -229,55 +185,14 @@ void html_finish_conversion(html_content *c) return; } - /* check that the base stylesheet loaded; layout fails without it */ - if (c->stylesheets[STYLESHEET_BASE].data.external == NULL) { - content_broadcast_errorcode(&c->base, NSERROR_CSS_BASE); - content_set_error(&c->base); - return; - } - - /* Create selection context */ - css_ret = css_select_ctx_create(ns_realloc, c, &c->select_ctx); - if (css_ret != CSS_OK) { - content_broadcast_errorcode(&c->base, - css_error_to_nserror(css_ret)); + /* create new css selection context */ + error = html_css_new_selection_context(c, &c->select_ctx); + if (error != NSERROR_OK) { + content_broadcast_errorcode(&c->base, error); content_set_error(&c->base); return; } - /* Add sheets to it */ - for (i = STYLESHEET_BASE; i != c->stylesheet_count; i++) { - const struct html_stylesheet *hsheet = &c->stylesheets[i]; - css_stylesheet *sheet; - css_origin origin = CSS_ORIGIN_AUTHOR; - - if (i < STYLESHEET_USER) - origin = CSS_ORIGIN_UA; - else if (i < STYLESHEET_START) - origin = CSS_ORIGIN_USER; - - if (hsheet->type == HTML_STYLESHEET_EXTERNAL && - hsheet->data.external != NULL) { - sheet = nscss_get_stylesheet(hsheet->data.external); - } else if (hsheet->type == HTML_STYLESHEET_INTERNAL) { - sheet = hsheet->data.internal->sheet; - } else { - sheet = NULL; - } - - if (sheet != NULL) { - css_ret = css_select_ctx_append_sheet(c->select_ctx, - sheet, - origin, - CSS_MEDIA_SCREEN); - if (css_ret != CSS_OK) { - content_broadcast_errorcode(&c->base, - css_error_to_nserror(css_ret)); - content_set_error(&c->base); - return; - } - } - } /* fire a simple event named load at the Document's Window * object, but with its target set to the Document object (and @@ -311,492 +226,6 @@ void html_finish_conversion(html_content *c) dom_node_unref(html); } -/** - * Callback for fetchcache() for linked stylesheets. - */ - -static nserror -html_convert_css_callback(hlcache_handle *css, - const hlcache_event *event, - void *pw) -{ - html_content *parent = pw; - unsigned int i; - struct html_stylesheet *s; - - /* Find sheet */ - for (i = 0, s = parent->stylesheets; - i != parent->stylesheet_count; i++, s++) { - if (s->type == HTML_STYLESHEET_EXTERNAL && - s->data.external == css) - break; - } - - assert(i != parent->stylesheet_count); - - switch (event->type) { - case CONTENT_MSG_LOADING: - break; - - case CONTENT_MSG_READY: - break; - - case CONTENT_MSG_DONE: - LOG(("done stylesheet slot %d '%s'", i, - nsurl_access(hlcache_handle_get_url(css)))); - parent->base.active--; - LOG(("%d fetches active", parent->base.active)); - break; - - case CONTENT_MSG_ERROR: - LOG(("stylesheet %s failed: %s", - nsurl_access(hlcache_handle_get_url(css)), - event->data.error)); - hlcache_handle_release(css); - s->data.external = NULL; - parent->base.active--; - LOG(("%d fetches active", parent->base.active)); - content_add_error(&parent->base, "?", 0); - break; - - case CONTENT_MSG_STATUS: - if (event->data.explicit_status_text == NULL) { - /* Object content's status text updated */ - html_set_status(parent, - content_get_status_message(css)); - content_broadcast(&parent->base, CONTENT_MSG_STATUS, - event->data); - } else { - /* Object content wants to set explicit message */ - content_broadcast(&parent->base, CONTENT_MSG_STATUS, - event->data); - } - break; - - case CONTENT_MSG_POINTER: - /* Really don't want this to continue after the switch */ - return NSERROR_OK; - - default: - assert(0); - } - - if (parent->base.active == 0) { - html_begin_conversion(parent); - } - - return NSERROR_OK; -} - -/** - * Initialise core stylesheets - * - * \param c content structure - * \return true on success, false if an error occurred - */ - -static bool html_init_stylesheets(html_content *c) -{ - nserror ns_error; - hlcache_child_context child; - - if (c->stylesheets != NULL) { - return true; /* already initialised */ - } - - /* stylesheet 0 is the base style sheet, - * stylesheet 1 is the quirks mode style sheet, - * stylesheet 2 is the adblocking stylesheet, - * stylesheet 3 is the user stylesheet */ - c->stylesheets = calloc(STYLESHEET_START, sizeof(struct html_stylesheet)); - if (c->stylesheets == NULL) { - ns_error = NSERROR_NOMEM; - goto html_find_stylesheets_no_memory; - } - - c->stylesheets[STYLESHEET_BASE].type = HTML_STYLESHEET_EXTERNAL; - c->stylesheets[STYLESHEET_BASE].data.external = NULL; - c->stylesheets[STYLESHEET_QUIRKS].type = HTML_STYLESHEET_EXTERNAL; - c->stylesheets[STYLESHEET_QUIRKS].data.external = NULL; - c->stylesheets[STYLESHEET_ADBLOCK].type = HTML_STYLESHEET_EXTERNAL; - c->stylesheets[STYLESHEET_ADBLOCK].data.external = NULL; - c->stylesheets[STYLESHEET_USER].type = HTML_STYLESHEET_EXTERNAL; - c->stylesheets[STYLESHEET_USER].data.external = NULL; - c->stylesheet_count = STYLESHEET_START; - - child.charset = c->encoding; - child.quirks = c->base.quirks; - - ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0, - content_get_url(&c->base), NULL, - html_convert_css_callback, c, &child, CONTENT_CSS, - &c->stylesheets[STYLESHEET_BASE].data.external); - if (ns_error != NSERROR_OK) - goto html_find_stylesheets_no_memory; - - c->base.active++; - LOG(("%d fetches active", c->base.active)); - - if (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL) { - ns_error = hlcache_handle_retrieve(html_quirks_stylesheet_url, - 0, content_get_url(&c->base), NULL, - html_convert_css_callback, c, &child, - CONTENT_CSS, - &c->stylesheets[STYLESHEET_QUIRKS].data.external); - if (ns_error != NSERROR_OK) - goto html_find_stylesheets_no_memory; - - c->base.active++; - LOG(("%d fetches active", c->base.active)); - - } - - if (nsoption_bool(block_ads)) { - ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url, - 0, content_get_url(&c->base), NULL, - html_convert_css_callback, c, &child, CONTENT_CSS, - &c->stylesheets[STYLESHEET_ADBLOCK]. - data.external); - if (ns_error != NSERROR_OK) - goto html_find_stylesheets_no_memory; - - c->base.active++; - LOG(("%d fetches active", c->base.active)); - - } - - ns_error = hlcache_handle_retrieve(html_user_stylesheet_url, 0, - content_get_url(&c->base), NULL, - html_convert_css_callback, c, &child, CONTENT_CSS, - &c->stylesheets[STYLESHEET_USER].data.external); - if (ns_error != NSERROR_OK) - goto html_find_stylesheets_no_memory; - - c->base.active++; - LOG(("%d fetches active", c->base.active)); - - return true; - -html_find_stylesheets_no_memory: - content_broadcast_errorcode(&c->base, ns_error); - return false; -} - -/** - * Handle notification of inline style completion - * - * \param css Inline style object - * \param pw Private data - */ -static void html_inline_style_done(struct content_css_data *css, void *pw) -{ - html_content *html = pw; - - html->base.active--; - LOG(("%d fetches active", html->base.active)); -} - -static nserror -html_stylesheet_from_domnode(html_content *c, - dom_node *node, - struct content_css_data **ret_sheet) -{ - dom_node *child, *next; - dom_exception exc; - struct content_css_data *sheet; - nserror error; - css_error csserror; - - /* create stylesheet */ - sheet = calloc(1, sizeof(struct content_css_data)); - if (sheet == NULL) { - return NSERROR_NOMEM; - } - - error = nscss_create_css_data(sheet, - nsurl_access(c->base_url), NULL, c->quirks, - html_inline_style_done, c); - if (error != NSERROR_OK) { - free(sheet); - return error; - } - - exc = dom_node_get_first_child(node, &child); - if (exc != DOM_NO_ERR) { - nscss_destroy_css_data(sheet); - free(sheet); - return NSERROR_DOM; - } - - while (child != NULL) { - dom_string *data; - - exc = dom_node_get_text_content(child, &data); - if (exc != DOM_NO_ERR) { - dom_node_unref(child); - nscss_destroy_css_data(sheet); - free(sheet); - return NSERROR_DOM; - } - - if (nscss_process_css_data(sheet, - dom_string_data(data), - dom_string_byte_length(data)) == false) { - dom_string_unref(data); - dom_node_unref(child); - nscss_destroy_css_data(sheet); - free(sheet); - return NSERROR_CSS; - } - - dom_string_unref(data); - - exc = dom_node_get_next_sibling(child, &next); - if (exc != DOM_NO_ERR) { - dom_node_unref(child); - nscss_destroy_css_data(sheet); - free(sheet); - return NSERROR_DOM; - } - - dom_node_unref(child); - child = next; - } - - c->base.active++; - LOG(("%d fetches active", c->base.active)); - - /* Convert the content -- manually, as we want the result */ - csserror = nscss_convert_css_data(sheet); - if (csserror != CSS_OK) { - /* conversion failed */ - c->base.active--; - LOG(("%d fetches active", c->base.active)); - nscss_destroy_css_data(sheet); - free(sheet); - return css_error_to_nserror(csserror); - } - - *ret_sheet = sheet; - return NSERROR_OK; -} - -/** - * Process an inline stylesheet in the document. - * - * \param c content structure - * \param style xml node of style element - * \return true on success, false if an error occurred - */ - -static struct html_stylesheet * -html_create_style_element(html_content *c, dom_node *style) -{ - dom_string *val; - dom_exception exc; - struct html_stylesheet *stylesheets; - - /* ensure sheets are initialised */ - if (html_init_stylesheets(c) == false) { - return false; - } - - /* type='text/css', or not present (invalid but common) */ - exc = dom_element_get_attribute(style, corestring_dom_type, &val); - if (exc == DOM_NO_ERR && val != NULL) { - if (!dom_string_caseless_lwc_isequal(val, - corestring_lwc_text_css)) { - dom_string_unref(val); - return NULL; - } - dom_string_unref(val); - } - - /* media contains 'screen' or 'all' or not present */ - exc = dom_element_get_attribute(style, corestring_dom_media, &val); - if (exc == DOM_NO_ERR && val != NULL) { - if (strcasestr(dom_string_data(val), "screen") == NULL && - strcasestr(dom_string_data(val), - "all") == NULL) { - dom_string_unref(val); - return NULL; - } - dom_string_unref(val); - } - - /* Extend array */ - stylesheets = realloc(c->stylesheets, - sizeof(struct html_stylesheet) * (c->stylesheet_count + 1)); - if (stylesheets == NULL) { - - content_broadcast_errorcode(&c->base, NSERROR_NOMEM); - return false; - - } - c->stylesheets = stylesheets; - - c->stylesheets[c->stylesheet_count].type = HTML_STYLESHEET_INTERNAL; - c->stylesheets[c->stylesheet_count].node = style; - c->stylesheets[c->stylesheet_count].data.internal = NULL; - c->stylesheet_count++; - - return c->stylesheets + (c->stylesheet_count - 1); -} - -static bool html_process_style_element_update(html_content *c, dom_node *style) -{ - struct content_css_data *sheet = NULL; - nserror error; - unsigned int i; - struct html_stylesheet *s; - - /* Find sheet */ - for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) { - if ((s->type == HTML_STYLESHEET_INTERNAL) && - (s->node == style)) - break; - } - if (i == c->stylesheet_count) { - s = html_create_style_element(c, style); - } - if (s == NULL) { - LOG(("Could not find or create inline stylesheet for %p", - style)); - return false; - } - - LOG(("Found sheet %p slot %d for node %p", s,i, style)); - - error = html_stylesheet_from_domnode(c, style, &sheet); - if (error != NSERROR_OK) { - LOG(("Failed to update sheet")); - content_broadcast_errorcode(&c->base, error); - return false; - } - - LOG(("Updating sheet %p with %p", s->data.internal, sheet)); - - /* Update index */ - if (s->data.internal != NULL) { - nscss_destroy_css_data(s->data.internal); - free(s->data.internal); - } - s->data.internal = sheet; - return true; -} - -static bool html_process_stylesheet_link(html_content *htmlc, dom_node *node) -{ - dom_string *rel, *type_attr, *media, *href; - struct html_stylesheet *stylesheets; - nsurl *joined; - dom_exception exc; - nserror ns_error; - hlcache_child_context child; - - /* ensure sheets are initialised */ - if (html_init_stylesheets(htmlc) == false) { - return false; - } - - /* rel=<space separated list, including 'stylesheet'> */ - exc = dom_element_get_attribute(node, corestring_dom_rel, &rel); - if (exc != DOM_NO_ERR || rel == NULL) - return true; - - if (strcasestr(dom_string_data(rel), "stylesheet") == 0) { - dom_string_unref(rel); - return true; - } else if (strcasestr(dom_string_data(rel), "alternate") != 0) { - /* Ignore alternate stylesheets */ - dom_string_unref(rel); - return true; - } - dom_string_unref(rel); - - /* type='text/css' or not present */ - exc = dom_element_get_attribute(node, corestring_dom_type, &type_attr); - if (exc == DOM_NO_ERR && type_attr != NULL) { - if (!dom_string_caseless_lwc_isequal(type_attr, - corestring_lwc_text_css)) { - dom_string_unref(type_attr); - return true; - } - dom_string_unref(type_attr); - } - - /* media contains 'screen' or 'all' or not present */ - exc = dom_element_get_attribute(node, corestring_dom_media, &media); - if (exc == DOM_NO_ERR && media != NULL) { - if (strcasestr(dom_string_data(media), "screen") == NULL && - strcasestr(dom_string_data(media), "all") == NULL) { - dom_string_unref(media); - return true; - } - dom_string_unref(media); - } - - /* href='...' */ - exc = dom_element_get_attribute(node, corestring_dom_href, &href); - if (exc != DOM_NO_ERR || href == NULL) - return true; - - /* TODO: only the first preferred stylesheets (ie. - * those with a title attribute) should be loaded - * (see HTML4 14.3) */ - - ns_error = nsurl_join(htmlc->base_url, dom_string_data(href), &joined); - if (ns_error != NSERROR_OK) { - dom_string_unref(href); - goto no_memory; - } - dom_string_unref(href); - - LOG(("linked stylesheet %i '%s'", htmlc->stylesheet_count, nsurl_access(joined))); - - /* extend stylesheets array to allow for new sheet */ - stylesheets = realloc(htmlc->stylesheets, - sizeof(struct html_stylesheet) * (htmlc->stylesheet_count + 1)); - if (stylesheets == NULL) { - nsurl_unref(joined); - ns_error = NSERROR_NOMEM; - goto no_memory; - } - - htmlc->stylesheets = stylesheets; - htmlc->stylesheets[htmlc->stylesheet_count].type = HTML_STYLESHEET_EXTERNAL; - - /* start fetch */ - child.charset = htmlc->encoding; - child.quirks = htmlc->base.quirks; - - ns_error = hlcache_handle_retrieve(joined, - 0, - content_get_url(&htmlc->base), - NULL, - html_convert_css_callback, - htmlc, - &child, - CONTENT_CSS, - &htmlc->stylesheets[htmlc->stylesheet_count].data.external); - - nsurl_unref(joined); - - if (ns_error != NSERROR_OK) - goto no_memory; - - htmlc->stylesheet_count++; - - htmlc->base.active++; - LOG(("%d fetches active", htmlc->base.active)); - - return true; - -no_memory: - content_broadcast_errorcode(&htmlc->base, ns_error); - return false; -} - /* callback for DOMNodeInserted end type */ static void dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw) @@ -816,7 +245,7 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw) if ((exc == DOM_NO_ERR) && (name != NULL)) { /* LOG(("element htmlc:%p node %p name:%s", htmlc, node, dom_string_data(name))); */ if (dom_string_caseless_isequal(name, corestring_dom_link)) { - html_process_stylesheet_link(htmlc, (dom_node *)node); + html_css_process_link(htmlc, (dom_node *)node); } } } @@ -842,7 +271,7 @@ dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw) if ((exc == DOM_NO_ERR) && (name != NULL)) { /* LOG(("element htmlc:%p node:%p name:%s", htmlc, node, dom_string_data(name))); */ if (dom_string_caseless_isequal(name, corestring_dom_style)) { - html_process_style_element_update(htmlc, (dom_node *)node); + html_css_update_style(htmlc, (dom_node *)node); } } } @@ -922,7 +351,7 @@ html_create_html_data(html_content *c, const http_parameter *params) selection_prepare(&c->sel, (struct content *)c, true); - nerror = http_parameter_list_find_item(params, html_charset, &charset); + nerror = http_parameter_list_find_item(params, corestring_lwc_charset, &charset); if (nerror == NSERROR_OK) { c->encoding = strdup(lwc_string_data(charset)); @@ -961,7 +390,6 @@ html_create_html_data(html_content *c, const http_parameter *params) &c->parser, &c->document); } - if (error != DOM_HUBBUB_OK) { nsurl_unref(c->base_url); c->base_url = NULL; @@ -1013,6 +441,13 @@ html_create(const content_handler *handler, return error; } + error = html_css_new_stylesheets(html); + if (error != NSERROR_OK) { + content_broadcast_errorcode(&html->base, error); + free(html); + return error; + } + *c = (struct content *) html; return NSERROR_OK; @@ -2243,11 +1678,6 @@ html_begin_conversion(html_content *htmlc) dom_node_unref(head); dom_node_unref(html); - /* ensure stylesheets are initialised */ - if (html_init_stylesheets(htmlc) == false) { - return false; - } - if (htmlc->base.active == 0) { html_finish_conversion(htmlc); } @@ -2522,7 +1952,6 @@ static void html_free_layout(html_content *htmlc) static void html_destroy(struct content *c) { html_content *html = (html_content *) c; - unsigned int i; struct form *f, *g; LOG(("content %p", c)); @@ -2582,19 +2011,7 @@ static void html_destroy(struct content *c) } /* Free stylesheets */ - for (i = 0; i != html->stylesheet_count; i++) { - if (html->stylesheets[i].type == HTML_STYLESHEET_EXTERNAL && - html->stylesheets[i].data.external != NULL) { - hlcache_handle_release( - html->stylesheets[i].data.external); - } else if (html->stylesheets[i].type == - HTML_STYLESHEET_INTERNAL && - html->stylesheets[i].data.internal != NULL) { - nscss_destroy_css_data( - html->stylesheets[i].data.internal); - } - } - free(html->stylesheets); + html_css_free_stylesheets(html); /* Free scripts */ html_free_scripts(html); @@ -3291,25 +2708,6 @@ const char *html_get_base_target(hlcache_handle *h) } /** - * Retrieve stylesheets used by HTML document - * - * \param h Content to retrieve stylesheets from - * \param n Pointer to location to receive number of sheets - * \return Pointer to array of stylesheets - */ -struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n) -{ - html_content *c = (html_content *) hlcache_handle_get_content(h); - - assert(c != NULL); - assert(n != NULL); - - *n = c->stylesheet_count; - - return c->stylesheets; -} - -/** * Retrieve objects used by HTML document * * \param h Content to retrieve objects from @@ -3369,30 +2767,7 @@ static void html_fini(void) { box_construct_fini(); - if (html_user_stylesheet_url != NULL) { - nsurl_unref(html_user_stylesheet_url); - html_user_stylesheet_url = NULL; - } - - if (html_quirks_stylesheet_url != NULL) { - nsurl_unref(html_quirks_stylesheet_url); - html_quirks_stylesheet_url = NULL; - } - - if (html_adblock_stylesheet_url != NULL) { - nsurl_unref(html_adblock_stylesheet_url); - html_adblock_stylesheet_url = NULL; - } - - if (html_default_stylesheet_url != NULL) { - nsurl_unref(html_default_stylesheet_url); - html_default_stylesheet_url = NULL; - } - - if (html_charset != NULL) { - lwc_string_unref(html_charset); - html_charset = NULL; - } + html_css_fini(); } static const content_handler html_content_handler = { @@ -3423,32 +2798,9 @@ static const content_handler html_content_handler = { nserror html_init(void) { uint32_t i; - lwc_error lerror; nserror error; - lerror = lwc_intern_string("charset", SLEN("charset"), &html_charset); - if (lerror != lwc_error_ok) { - error = NSERROR_NOMEM; - goto error; - } - - error = nsurl_create("resource:default.css", - &html_default_stylesheet_url); - if (error != NSERROR_OK) - goto error; - - error = nsurl_create("resource:adblock.css", - &html_adblock_stylesheet_url); - if (error != NSERROR_OK) - goto error; - - error = nsurl_create("resource:quirks.css", - &html_quirks_stylesheet_url); - if (error != NSERROR_OK) - goto error; - - error = nsurl_create("resource:user.css", - &html_user_stylesheet_url); + error = html_css_init(); if (error != NSERROR_OK) goto error; |