diff --git a/amiga/filetype.c b/amiga/filetype.c index d69f20bad..7808ff7d2 100644 --- a/amiga/filetype.c +++ b/amiga/filetype.c @@ -194,6 +194,7 @@ nserror ami_mime_init(const char *mimefile) ami_mime_list = NewObjList(); rargs = AllocDosObjectTags(DOS_RDARGS,TAG_DONE); + if(rargs == NULL) return NSERROR_NOMEM; if(fh = FOpen(mimefile, MODE_OLDFILE, 0)) { @@ -251,10 +252,12 @@ nserror ami_mime_init(const char *mimefile) if (lerror != lwc_error_ok) return NSERROR_NOMEM; } + FreeArgs(rargs); } } FClose(fh); } + FreeDosObject(DOS_RDARGS, rargs); } void ami_mime_free(void) diff --git a/render/form.c b/render/form.c index 0c0eef2cb..46d5b28f6 100644 --- a/render/form.c +++ b/render/form.c @@ -212,6 +212,10 @@ struct form_control *form_new_control(void *node, form_control_type type) */ void form_add_control(struct form *form, struct form_control *control) { + if (form == NULL) { + return; + } + control->form = form; if (form->controls != NULL) { diff --git a/render/html.c b/render/html.c index e697c9f12..aeb5a5b73 100644 --- a/render/html.c +++ b/render/html.c @@ -311,7 +311,567 @@ 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= */ + 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) +{ + dom_event_target *node; + dom_node_type type; + dom_string *name; + dom_exception exc; + html_content *htmlc = pw; + + exc = dom_event_get_target(evt, &node); + if ((exc == DOM_NO_ERR) && (node != NULL)) { + exc = dom_node_get_node_type(node, &type); + if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) { + /* an element node has been inserted */ + exc = dom_node_get_node_name(node, &name); + 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); + } + } + } + } +} + +/* callback for DOMNodeInserted end type */ +static void +dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw) +{ + dom_event_target *node; + dom_node_type type; + dom_string *name; + dom_exception exc; + html_content *htmlc = pw; + + exc = dom_event_get_target(evt, &node); + if ((exc == DOM_NO_ERR) && (node != NULL)) { + exc = dom_node_get_node_type(node, &type); + if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) { + /* an element node has been inserted */ + exc = dom_node_get_node_name(node, &name); + 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); + } + } + } + } +} + +/* callback function selector + * + * selects a callback function for libdom to call based on the type and phase. + * dom_default_action_phase from events/document_event.h + * + * @return callback function pointer or NULL for none + */ +static dom_default_action_callback +dom_event_fetcher(dom_string *type, + dom_default_action_phase phase, + void **pw) +{ + //LOG(("type:%s", dom_string_data(type))); + + if (phase == DOM_DEFAULT_ACTION_END) { + if (dom_string_isequal(type, corestring_dom_DOMNodeInserted)) { + return dom_default_action_DOMNodeInserted_cb; + } else if (dom_string_isequal(type, corestring_dom_DOMSubtreeModified)) { + return dom_default_action_DOMSubtreeModified_cb; + } + } + return NULL; +} static nserror html_create_html_data(html_content *c, const http_parameter *params) @@ -384,7 +944,7 @@ html_create_html_data(html_content *c, const http_parameter *params) parse_params.msg = NULL; parse_params.script = html_process_script; parse_params.ctx = c; - parse_params.daf = NULL; + parse_params.daf = dom_event_fetcher; error = dom_hubbub_parser_create(&parse_params, &c->parser, @@ -502,7 +1062,7 @@ html_process_encoding_change(struct content *c, parse_params.msg = NULL; parse_params.script = html_process_script; parse_params.ctx = html; - parse_params.daf = NULL; + parse_params.daf = dom_event_fetcher; /* Create new binding, using the new encoding */ error = dom_hubbub_parser_create(&parse_params, @@ -1492,480 +2052,6 @@ static void html_object_refresh(void *p) } - - - -/** - * 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_finish_conversion(parent); - - return NSERROR_OK; -} - -/** - * 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; - - if (--html->base.active == 0) - html_finish_conversion(html); -} - -/** - * Process an inline stylesheet in the document. - * - * \param c content structure - * \param index Index of stylesheet in stylesheet_content array, - * updated if successful - * \param style xml node of style element - * \return true on success, false if an error occurred - */ - -static bool -html_process_style_element(html_content *c, - unsigned int *index, - dom_node *style) -{ - dom_node *child, *next; - dom_string *val; - dom_exception exc; - struct html_stylesheet *stylesheets; - struct content_css_data *sheet; - nserror error; - - /* 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 true; - } - 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 true; - } - dom_string_unref(val); - } - - /* Extend array */ - stylesheets = realloc(c->stylesheets, - sizeof(struct html_stylesheet) * (*index + 1)); - if (stylesheets == NULL) - goto no_memory; - - c->stylesheets = stylesheets; - c->stylesheet_count++; - - c->stylesheets[(*index)].type = HTML_STYLESHEET_INTERNAL; - c->stylesheets[(*index)].data.internal = NULL; - - /* create stylesheet */ - sheet = calloc(1, sizeof(struct content_css_data)); - if (sheet == NULL) { - c->stylesheet_count--; - goto no_memory; - } - - 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); - c->stylesheet_count--; - content_broadcast_errorcode(&c->base, error); - return false; - } - - /* can't just use xmlNodeGetContent(style), because that won't - * give the content of comments which may be used to 'hide' - * the content */ - exc = dom_node_get_first_child(style, &child); - if (exc != DOM_NO_ERR) { - nscss_destroy_css_data(sheet); - free(sheet); - c->stylesheet_count--; - goto no_memory; - } - - 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); - c->stylesheet_count--; - goto no_memory; - } - - 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); - c->stylesheet_count--; - goto no_memory; - } - - 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); - c->stylesheet_count--; - goto no_memory; - } - - 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 */ - if (nscss_convert_css_data(sheet) != CSS_OK) { - /* conversion failed */ - c->base.active--; - LOG(("%d fetches active", c->base.active)); - nscss_destroy_css_data(sheet); - free(sheet); - sheet = NULL; - } - - /* Update index */ - c->stylesheets[(*index)].data.internal = sheet; - (*index)++; - - return true; - -no_memory: - content_broadcast_errorcode(&c->base, NSERROR_NOMEM); - return false; -} - - - -struct find_stylesheet_ctx { - unsigned int count; - html_content *c; -}; - -/** callback to process stylesheet elements - */ -static bool -html_process_stylesheet(dom_node *node, dom_string *name, void *vctx) -{ - struct find_stylesheet_ctx *ctx = (struct find_stylesheet_ctx *)vctx; - dom_string *rel, *type_attr, *media, *href; - struct html_stylesheet *stylesheets; - nsurl *joined; - dom_exception exc; - nserror ns_error; - hlcache_child_context child; - - /* deal with style nodes */ - if (dom_string_caseless_lwc_isequal(name, corestring_lwc_style)) { - if (!html_process_style_element(ctx->c, &ctx->count, node)) - return false; - return true; - } - - /* if it is not a link node skip it */ - if (!dom_string_caseless_lwc_isequal(name, corestring_lwc_link)) { - return true; - } - - /* rel= */ - 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(ctx->c->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'", ctx->count, nsurl_access(joined))); - - /* start fetch */ - stylesheets = realloc(ctx->c->stylesheets, - sizeof(struct html_stylesheet) * (ctx->count + 1)); - if (stylesheets == NULL) { - nsurl_unref(joined); - ns_error = NSERROR_NOMEM; - goto no_memory; - } - - ctx->c->stylesheets = stylesheets; - ctx->c->stylesheet_count++; - ctx->c->stylesheets[ctx->count].type = HTML_STYLESHEET_EXTERNAL; - - child.charset = ctx->c->encoding; - child.quirks = ctx->c->base.quirks; - - ns_error = hlcache_handle_retrieve(joined, - 0, - content_get_url(&ctx->c->base), - NULL, - html_convert_css_callback, - ctx->c, - &child, - CONTENT_CSS, - &ctx->c->stylesheets[ctx->count].data.external); - - nsurl_unref(joined); - - if (ns_error != NSERROR_OK) - goto no_memory; - - ctx->c->base.active++; - LOG(("%d fetches active", ctx->c->base.active)); - - ctx->count++; - - return true; - -no_memory: - content_broadcast_errorcode(&ctx->c->base, ns_error); - return false; -} - - -/** - * Process inline stylesheets and fetch linked stylesheets. - * - * Uses STYLE and LINK elements inside and outside HEAD - * - * \param c content structure - * \param html dom node of html element - * \return true on success, false if an error occurred - */ - -static bool html_find_stylesheets(html_content *c, dom_node *html) -{ - nserror ns_error; - bool result; - struct find_stylesheet_ctx ctx; - hlcache_child_context child; - - /* setup context */ - ctx.c = c; - ctx.count = STYLESHEET_START; - - /* 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)); - - result = libdom_treewalk(html, html_process_stylesheet, &ctx); - - assert(c->stylesheet_count == ctx.count); - - return result; - -html_find_stylesheets_no_memory: - content_broadcast_errorcode(&c->base, ns_error); - return false; -} - /** * Convert a CONTENT_HTML for display. * @@ -2006,6 +2092,7 @@ html_begin_conversion(html_content *htmlc) dom_string *node_name = NULL; dom_hubbub_error error; + LOG(("Completing parse")); /* complete parsing */ error = dom_hubbub_parser_completed(htmlc->parser); if (error != DOM_HUBBUB_OK) { @@ -2154,15 +2241,13 @@ html_begin_conversion(html_content *htmlc) } dom_node_unref(head); + dom_node_unref(html); - /* get stylesheets */ - if (html_find_stylesheets(htmlc, html) == false) { - dom_node_unref(html); + /* ensure stylesheets are initialised */ + if (html_init_stylesheets(htmlc) == false) { return false; } - dom_node_unref(html); - if (htmlc->base.active == 0) { html_finish_conversion(htmlc); } diff --git a/render/html.h b/render/html.h index c208f47d6..6920fa8c7 100644 --- a/render/html.h +++ b/render/html.h @@ -58,6 +58,7 @@ struct selection; struct html_stylesheet { /** Type of sheet */ enum { HTML_STYLESHEET_EXTERNAL, HTML_STYLESHEET_INTERNAL } type; + struct dom_node *node; /**< dom node associated with sheet */ union { struct hlcache_handle *external; struct content_css_data *internal; diff --git a/utils/corestrings.c b/utils/corestrings.c index f39a59c21..06c7906bd 100644 --- a/utils/corestrings.c +++ b/utils/corestrings.c @@ -145,6 +145,10 @@ dom_string *corestring_dom_coords; dom_string *corestring_dom_cuechange; dom_string *corestring_dom_dblclick; dom_string *corestring_dom_defer; +dom_string *corestring_dom_DOMAttrModified; +dom_string *corestring_dom_DOMNodeInserted; +dom_string *corestring_dom_DOMNodeInsertedIntoDocument; +dom_string *corestring_dom_DOMSubtreeModified; dom_string *corestring_dom_drag; dom_string *corestring_dom_dragend; dom_string *corestring_dom_dragenter; @@ -212,6 +216,7 @@ dom_string *corestring_dom_sizes; dom_string *corestring_dom_src; dom_string *corestring_dom_stalled; dom_string *corestring_dom_storage; +dom_string *corestring_dom_style; dom_string *corestring_dom_submit; dom_string *corestring_dom_suspend; dom_string *corestring_dom_target; @@ -369,6 +374,10 @@ void corestrings_fini(void) CSS_DOM_STRING_UNREF(cuechange); CSS_DOM_STRING_UNREF(dblclick); CSS_DOM_STRING_UNREF(defer); + CSS_DOM_STRING_UNREF(DOMAttrModified); + CSS_DOM_STRING_UNREF(DOMNodeInserted); + CSS_DOM_STRING_UNREF(DOMNodeInsertedIntoDocument); + CSS_DOM_STRING_UNREF(DOMSubtreeModified); CSS_DOM_STRING_UNREF(drag); CSS_DOM_STRING_UNREF(dragend); CSS_DOM_STRING_UNREF(dragenter); @@ -436,6 +445,7 @@ void corestrings_fini(void) CSS_DOM_STRING_UNREF(src); CSS_DOM_STRING_UNREF(stalled); CSS_DOM_STRING_UNREF(storage); + CSS_DOM_STRING_UNREF(style); CSS_DOM_STRING_UNREF(submit); CSS_DOM_STRING_UNREF(suspend); CSS_DOM_STRING_UNREF(target); @@ -624,6 +634,10 @@ nserror corestrings_init(void) CSS_DOM_STRING_INTERN(cuechange); CSS_DOM_STRING_INTERN(dblclick); CSS_DOM_STRING_INTERN(defer); + CSS_DOM_STRING_INTERN(DOMAttrModified); + CSS_DOM_STRING_INTERN(DOMNodeInserted); + CSS_DOM_STRING_INTERN(DOMNodeInsertedIntoDocument); + CSS_DOM_STRING_INTERN(DOMSubtreeModified); CSS_DOM_STRING_INTERN(drag); CSS_DOM_STRING_INTERN(dragend); CSS_DOM_STRING_INTERN(dragenter); @@ -691,6 +705,7 @@ nserror corestrings_init(void) CSS_DOM_STRING_INTERN(src); CSS_DOM_STRING_INTERN(stalled); CSS_DOM_STRING_INTERN(storage); + CSS_DOM_STRING_INTERN(style); CSS_DOM_STRING_INTERN(submit); CSS_DOM_STRING_INTERN(suspend); CSS_DOM_STRING_INTERN(target); diff --git a/utils/corestrings.h b/utils/corestrings.h index e28b713eb..d4e8fc3f7 100644 --- a/utils/corestrings.h +++ b/utils/corestrings.h @@ -151,6 +151,10 @@ extern struct dom_string *corestring_dom_coords; extern struct dom_string *corestring_dom_cuechange; extern struct dom_string *corestring_dom_dblclick; extern struct dom_string *corestring_dom_defer; +extern struct dom_string *corestring_dom_DOMAttrModified; +extern struct dom_string *corestring_dom_DOMNodeInserted; +extern struct dom_string *corestring_dom_DOMNodeInsertedIntoDocument; +extern struct dom_string *corestring_dom_DOMSubtreeModified; extern struct dom_string *corestring_dom_drag; extern struct dom_string *corestring_dom_dragend; extern struct dom_string *corestring_dom_dragenter; @@ -218,6 +222,7 @@ extern struct dom_string *corestring_dom_sizes; extern struct dom_string *corestring_dom_src; extern struct dom_string *corestring_dom_stalled; extern struct dom_string *corestring_dom_storage; +extern struct dom_string *corestring_dom_style; extern struct dom_string *corestring_dom_submit; extern struct dom_string *corestring_dom_suspend; extern struct dom_string *corestring_dom_target;