From 066df9802ad04d415b5ce972268092aa73dc6613 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 20 Feb 2013 17:13:23 +0000 Subject: deal with inline styles on updates instead of insert --- render/html.c | 237 ++++++++++++++++++++++++++++++++++++++-------------------- render/html.h | 1 + 2 files changed, 159 insertions(+), 79 deletions(-) diff --git a/render/html.c b/render/html.c index 421b5c5ef..917976263 100644 --- a/render/html.c +++ b/render/html.c @@ -487,70 +487,29 @@ 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); + } } -/** - * 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 bool html_process_style_element(html_content *c, dom_node *style) +static nserror +html_stylesheet_from_domnode(html_content *c, + dom_node *node, + struct content_css_data **ret_sheet) { 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) { - 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 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) * (c->stylesheet_count + 1)); - if (stylesheets == NULL) - goto no_memory; - - c->stylesheets = stylesheets; - - c->stylesheets[c->stylesheet_count].type = HTML_STYLESHEET_INTERNAL; - c->stylesheets[c->stylesheet_count].data.internal = NULL; + css_error csserror; /* create stylesheet */ sheet = calloc(1, sizeof(struct content_css_data)); if (sheet == NULL) { - goto no_memory; + return NSERROR_NOMEM; } error = nscss_create_css_data(sheet, @@ -558,18 +517,14 @@ static bool html_process_style_element(html_content *c, dom_node *style) html_inline_style_done, c); if (error != NSERROR_OK) { free(sheet); - content_broadcast_errorcode(&c->base, error); - return false; + return error; } - /* 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); + exc = dom_node_get_first_child(node, &child); if (exc != DOM_NO_ERR) { nscss_destroy_css_data(sheet); free(sheet); - goto no_memory; + return NSERROR_DOM; } while (child != NULL) { @@ -580,16 +535,17 @@ static bool html_process_style_element(html_content *c, dom_node *style) dom_node_unref(child); nscss_destroy_css_data(sheet); free(sheet); - goto no_memory; + return NSERROR_DOM; } - if (nscss_process_css_data(sheet, dom_string_data(data), + 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; + return NSERROR_CSS; } dom_string_unref(data); @@ -599,7 +555,7 @@ static bool html_process_style_element(html_content *c, dom_node *style) dom_node_unref(child); nscss_destroy_css_data(sheet); free(sheet); - goto no_memory; + return NSERROR_DOM; } dom_node_unref(child); @@ -610,27 +566,123 @@ static bool html_process_style_element(html_content *c, dom_node *style) LOG(("%d fetches active", c->base.active)); /* Convert the content -- manually, as we want the result */ - if (nscss_convert_css_data(sheet) != CSS_OK) { + 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); - sheet = NULL; + return css_error_to_nserror(csserror); } - /* Update index */ - c->stylesheets[c->stylesheet_count].data.internal = sheet; - c->stylesheet_count++; + *ret_sheet = sheet; + return NSERROR_OK; +} - return true; +/** + * 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 + */ -no_memory: - content_broadcast_errorcode(&c->base, NSERROR_NOMEM); - return false; +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) { @@ -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; -- cgit v1.2.3