diff --git a/render/html.h b/render/html.h
index a17e4a50b..162541d72 100644
--- a/render/html.h
+++ b/render/html.h
@@ -56,9 +56,9 @@ struct selection;
* Container for stylesheets used by an HTML document
*/
struct html_stylesheet {
- /** Type of sheet */
struct dom_node *node; /**< dom node associated with sheet */
struct hlcache_handle *sheet;
+ bool modified;
};
/**
diff --git a/render/html_css.c b/render/html_css.c
index 3eabec419..a87e0d512 100644
--- a/render/html_css.c
+++ b/render/html_css.c
@@ -33,6 +33,7 @@
#include "utils/corestrings.h"
#include "utils/config.h"
#include "utils/log.h"
+#include "utils/schedule.h"
static nsurl *html_default_stylesheet_url;
static nsurl *html_adblock_stylesheet_url;
@@ -149,131 +150,6 @@ html_convert_css_callback(hlcache_handle *css,
return NSERROR_OK;
}
-/* exported interface documented in render/html.h */
-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;
-}
-
-
-/* exported interface documented in render/html_internal.h */
-nserror html_css_free_stylesheets(html_content *html)
-{
- unsigned int i;
-
- for (i = 0; i != html->stylesheet_count; i++) {
- if (html->stylesheets[i].sheet != NULL) {
- hlcache_handle_release(html->stylesheets[i].sheet);
- }
- }
- free(html->stylesheets);
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in render/html_internal.h */
-nserror html_css_quirks_stylesheets(html_content *c)
-{
- nserror ns_error = NSERROR_OK;
- hlcache_child_context child;
-
- assert(c->stylesheets != NULL);
-
- if (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL) {
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- 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].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- c->base.active++;
- LOG(("%d fetches active", c->base.active));
- }
-
- return ns_error;
-}
-
-/* exported interface documented in render/html_internal.h */
-nserror html_css_new_stylesheets(html_content *c)
-{
- nserror ns_error;
- hlcache_child_context child;
-
- if (c->stylesheets != NULL) {
- return NSERROR_OK; /* 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) {
- return NSERROR_NOMEM;
- }
-
- c->stylesheets[STYLESHEET_BASE].sheet = NULL;
- c->stylesheets[STYLESHEET_QUIRKS].sheet = NULL;
- c->stylesheets[STYLESHEET_ADBLOCK].sheet = NULL;
- c->stylesheets[STYLESHEET_USER].sheet = 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].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- 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].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- 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].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- c->base.active++;
- LOG(("%d fetches active", c->base.active));
-
- return ns_error;
-}
-
static nserror
html_stylesheet_from_domnode(html_content *c,
dom_node *node,
@@ -377,37 +253,21 @@ html_create_style_element(html_content *c, dom_node *style)
}
c->stylesheets = stylesheets;
- c->stylesheets[c->stylesheet_count].node = style;
+ c->stylesheets[c->stylesheet_count].node = dom_node_ref(style);
c->stylesheets[c->stylesheet_count].sheet = NULL;
+ c->stylesheets[c->stylesheet_count].modified = false;
c->stylesheet_count++;
return c->stylesheets + (c->stylesheet_count - 1);
}
-bool html_css_update_style(html_content *c, dom_node *style)
+static bool html_css_process_modified_style(html_content *c,
+ struct html_stylesheet *s)
{
- nserror error;
- unsigned int i;
- struct html_stylesheet *s;
hlcache_handle *sheet = NULL;
+ nserror error;
- /* Find sheet */
- for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) {
- if (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);
+ error = html_stylesheet_from_domnode(c, s->node, &sheet);
if (error != NSERROR_OK) {
LOG(("Failed to update sheet"));
content_broadcast_errorcode(&c->base, error);
@@ -431,6 +291,53 @@ bool html_css_update_style(html_content *c, dom_node *style)
s->sheet = sheet;
}
+ s->modified = false;
+
+ return true;
+}
+
+static void html_css_process_modified_styles(void *pw)
+{
+ html_content *c = pw;
+ struct html_stylesheet *s;
+ unsigned int i;
+ bool all_done = true;
+
+ for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) {
+ if (c->stylesheets[i].modified) {
+ all_done &= html_css_process_modified_style(c, s);
+ }
+ }
+
+ /* If we failed to process any sheet, schedule a retry */
+ if (all_done == false) {
+ schedule(100, html_css_process_modified_styles, c);
+ }
+}
+
+bool html_css_update_style(html_content *c, dom_node *style)
+{
+ unsigned int i;
+ struct html_stylesheet *s;
+
+ /* Find sheet */
+ for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) {
+ if (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;
+ }
+
+ s->modified = true;
+
+ schedule(0, html_css_process_modified_styles, c);
+
return true;
}
@@ -508,6 +415,8 @@ bool html_css_process_link(html_content *htmlc, dom_node *node)
}
htmlc->stylesheets = stylesheets;
+ htmlc->stylesheets[htmlc->stylesheet_count].node = NULL;
+ htmlc->stylesheets[htmlc->stylesheet_count].modified = false;
/* start fetch */
child.charset = htmlc->encoding;
@@ -540,6 +449,136 @@ no_memory:
return false;
}
+/* exported interface documented in render/html.h */
+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;
+}
+
+
+/* exported interface documented in render/html_internal.h */
+nserror html_css_free_stylesheets(html_content *html)
+{
+ unsigned int i;
+
+ schedule_remove(html_css_process_modified_styles, html);
+
+ for (i = 0; i != html->stylesheet_count; i++) {
+ if (html->stylesheets[i].sheet != NULL) {
+ hlcache_handle_release(html->stylesheets[i].sheet);
+ }
+ if (html->stylesheets[i].node != NULL) {
+ dom_node_unref(html->stylesheets[i].node);
+ }
+ }
+ free(html->stylesheets);
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in render/html_internal.h */
+nserror html_css_quirks_stylesheets(html_content *c)
+{
+ nserror ns_error = NSERROR_OK;
+ hlcache_child_context child;
+
+ assert(c->stylesheets != NULL);
+
+ if (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL) {
+ child.charset = c->encoding;
+ child.quirks = c->base.quirks;
+
+ 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].sheet);
+ if (ns_error != NSERROR_OK) {
+ return ns_error;
+ }
+
+ c->base.active++;
+ LOG(("%d fetches active", c->base.active));
+ }
+
+ return ns_error;
+}
+
+/* exported interface documented in render/html_internal.h */
+nserror html_css_new_stylesheets(html_content *c)
+{
+ nserror ns_error;
+ hlcache_child_context child;
+
+ if (c->stylesheets != NULL) {
+ return NSERROR_OK; /* 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) {
+ return NSERROR_NOMEM;
+ }
+
+ c->stylesheets[STYLESHEET_BASE].sheet = NULL;
+ c->stylesheets[STYLESHEET_QUIRKS].sheet = NULL;
+ c->stylesheets[STYLESHEET_ADBLOCK].sheet = NULL;
+ c->stylesheets[STYLESHEET_USER].sheet = 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].sheet);
+ if (ns_error != NSERROR_OK) {
+ return ns_error;
+ }
+
+ 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].sheet);
+ if (ns_error != NSERROR_OK) {
+ return ns_error;
+ }
+
+ 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].sheet);
+ if (ns_error != NSERROR_OK) {
+ return ns_error;
+ }
+
+ c->base.active++;
+ LOG(("%d fetches active", c->base.active));
+
+ return ns_error;
+}
+
nserror
html_css_new_selection_context(html_content *c, css_select_ctx **ret_select_ctx)
{