From 066df9802ad04d415b5ce972268092aa73dc6613 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 20 Feb 2013 17:13:23 +0000 Subject: [PATCH] deal with inline styles on updates instead of insert --- render/html.c | 257 +++++++++++++++++++++++++++++++++----------------- render/html.h | 1 + 2 files changed, 169 insertions(+), 89 deletions(-) diff --git a/render/html.c b/render/html.c index 421b5c5ef..917976263 100644 --- a/render/html.c +++ b/render/html.c @@ -487,8 +487,97 @@ static void html_inline_style_done(struct content_css_data *css, void *pw) { html_content *html = pw; - if (--html->base.active == 0) + html->base.active--; + LOG(("%d fetches active", html->base.active)); + + if (html->base.active == 0) { html_finish_conversion(html); + } +} + +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; } /** @@ -499,14 +588,12 @@ static void html_inline_style_done(struct content_css_data *css, void *pw) * \return true on success, false if an error occurred */ -static bool html_process_style_element(html_content *c, dom_node *style) +static struct html_stylesheet * +html_create_style_element(html_content *c, dom_node *style) { - dom_node *child, *next; dom_string *val; dom_exception exc; struct html_stylesheet *stylesheets; - struct content_css_data *sheet; - nserror error; /* ensure sheets are initialised */ if (html_init_stylesheets(c) == false) { @@ -519,7 +606,7 @@ static bool html_process_style_element(html_content *c, dom_node *style) if (!dom_string_caseless_lwc_isequal(val, corestring_lwc_text_css)) { dom_string_unref(val); - return true; + return NULL; } dom_string_unref(val); } @@ -531,7 +618,7 @@ static bool html_process_style_element(html_content *c, dom_node *style) strcasestr(dom_string_data(val), "all") == NULL) { dom_string_unref(val); - return true; + return NULL; } dom_string_unref(val); } @@ -539,99 +626,64 @@ static bool html_process_style_element(html_content *c, dom_node *style) /* Extend array */ stylesheets = realloc(c->stylesheets, sizeof(struct html_stylesheet) * (c->stylesheet_count + 1)); - if (stylesheets == NULL) - goto no_memory; + 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++; - /* create stylesheet */ - sheet = calloc(1, sizeof(struct content_css_data)); - if (sheet == NULL) { - goto no_memory; + 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; } - error = nscss_create_css_data(sheet, - nsurl_access(c->base_url), NULL, c->quirks, - html_inline_style_done, c); + LOG(("Found sheet %p slot %d for node %p", s,i, style)); + + error = html_stylesheet_from_domnode(c, style, &sheet); if (error != NSERROR_OK) { - free(sheet); + LOG(("Failed to update sheet")); 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); - 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); - 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); - 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); - 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; - } + LOG(("Updating sheet %p with %p", s->data.internal, sheet)); /* Update index */ - c->stylesheets[c->stylesheet_count].data.internal = sheet; - c->stylesheet_count++; - + if (s->data.internal != NULL) { + nscss_destroy_css_data(s->data.internal); + free(s->data.internal); + } + s->data.internal = sheet; return true; - -no_memory: - content_broadcast_errorcode(&c->base, NSERROR_NOMEM); - return false; } - - static bool html_process_stylesheet_link(html_content *htmlc, dom_node *node) { dom_string *rel, *type_attr, *media, *href; @@ -761,10 +813,8 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw) /* 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 name:%s", htmlc, dom_string_data(name))); */ - if (dom_string_caseless_isequal(name, corestring_dom_style)) { - html_process_style_element(htmlc, (dom_node *)node); - } else if (dom_string_caseless_isequal(name, corestring_dom_link)) { + 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); } } @@ -772,6 +822,32 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw) } } +/* 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. @@ -786,9 +862,12 @@ dom_event_fetcher(dom_string *type, { //LOG(("type:%s", dom_string_data(type))); - if ((phase == DOM_DEFAULT_ACTION_END) && - dom_string_isequal(type, corestring_dom_DOMNodeInserted)) { - return dom_default_action_DOMNodeInserted_cb; + 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; } diff --git a/render/html.h b/render/html.h index a9f7967f6..810a9f268 100644 --- a/render/html.h +++ b/render/html.h @@ -57,6 +57,7 @@ struct search_context; 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;