summaryrefslogtreecommitdiff
path: root/render/html.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2013-02-20 17:13:23 +0000
committerVincent Sanders <vince@netsurf-browser.org>2013-02-20 17:13:23 +0000
commit066df9802ad04d415b5ce972268092aa73dc6613 (patch)
tree83f1f149da1aff49d5d5aca7524ebf4de94db975 /render/html.c
parent5be20a0d6e8eb264d3d0d212413e218b8eeb7536 (diff)
downloadnetsurf-066df9802ad04d415b5ce972268092aa73dc6613.tar.gz
netsurf-066df9802ad04d415b5ce972268092aa73dc6613.tar.bz2
deal with inline styles on updates instead of insert
Diffstat (limited to 'render/html.c')
-rw-r--r--render/html.c237
1 files changed, 158 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;
}