summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2012-06-19 09:35:51 +0000
committerVincent Sanders <vince@netsurf-browser.org>2012-06-19 09:35:51 +0000
commit49effe103a260a60949d3c95494ae81b031799d9 (patch)
tree5a205757088c1f1d978eea067a7bf186568c582a
parenta229a35767760c71c94ae66567f7b172c5b8c356 (diff)
downloadnetsurf-49effe103a260a60949d3c95494ae81b031799d9.tar.gz
restructure javascript binding layout to be more explicit
fix html content so it correctly loads all the script tags svn path=/trunk/netsurf/; revision=13968
-rw-r--r--Makefile.sources4
-rw-r--r--desktop/options_main.h8
-rw-r--r--javascript/jsapi.c (renamed from javascript/js.c)6
-rw-r--r--javascript/jsapi.h (renamed from javascript/global.h)8
-rw-r--r--javascript/jsapi/global.c (renamed from javascript/global.c)4
-rw-r--r--javascript/none.c (renamed from javascript/nojs.c)0
-rw-r--r--render/html.c765
-rw-r--r--render/html.h20
-rw-r--r--render/html_internal.h10
9 files changed, 589 insertions, 236 deletions
diff --git a/Makefile.sources b/Makefile.sources
index 8806071c1..50c8a9b50 100644
--- a/Makefile.sources
+++ b/Makefile.sources
@@ -29,9 +29,9 @@ S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \
# Javascript sources
ifeq ($(NETSURF_USE_JS),YES)
-S_JAVASCRIPT += js.c global.c
+S_JAVASCRIPT += jsapi.c jsapi/global.c
else
-S_JAVASCRIPT += nojs.c
+S_JAVASCRIPT += none.c
endif
# S_COMMON are sources common to all builds
diff --git a/desktop/options_main.h b/desktop/options_main.h
index d56d3a446..d44c26505 100644
--- a/desktop/options_main.h
+++ b/desktop/options_main.h
@@ -70,7 +70,7 @@
int disc_cache_age; \
/** Whether to block advertisements */ \
bool block_ads; \
- /** Disable website tracking, see \
+ /** Disable website tracking, see \
* http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas */ \
bool do_not_track; \
/** Minimum GIF animation delay */ \
@@ -83,6 +83,8 @@
bool background_images; \
/** Whether to animate images */ \
bool animate_images; \
+ /** Whether to execute javascript */ \
+ bool enable_javascript; \
/** How many days to retain URL data for */ \
int expire_url; \
/** Default font family */ \
@@ -262,7 +264,8 @@
.max_cached_fetch_handles = 6, \
.suppress_curl_debug = true, \
.target_blank = true, \
- .button_2_tab = true
+ .button_2_tab = true, \
+ .enable_javascript = true
#define NSOPTION_MAIN_SYS_COLOUR_DEFAULTS \
.sys_colour_ActiveBorder = 0x00000000, \
@@ -320,6 +323,7 @@
{ "foreground_images", OPTION_BOOL, &nsoptions.foreground_images }, \
{ "background_images", OPTION_BOOL, &nsoptions.background_images }, \
{ "animate_images", OPTION_BOOL, &nsoptions.animate_images }, \
+ { "enable_javasctipt", OPTION_BOOL, &nsoptions.enable_javascript}, \
{ "expire_url", OPTION_INTEGER, &nsoptions.expire_url }, \
{ "font_default", OPTION_INTEGER, &nsoptions.font_default }, \
{ "ca_bundle", OPTION_STRING, &nsoptions.ca_bundle }, \
diff --git a/javascript/js.c b/javascript/jsapi.c
index 833e01785..6f5b510ef 100644
--- a/javascript/js.c
+++ b/javascript/jsapi.c
@@ -19,7 +19,7 @@
#include "mozjs/jsapi.h"
#include "content/content.h"
-#include "javascript/global.h"
+#include "javascript/jsapi.h"
#include "javascript/js.h"
#include "utils/log.h"
@@ -50,7 +50,7 @@ void js_finalise(void)
/* The error reporter callback. */
static void js_reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
- LOG(("%s:%u:%s\n",
+ LOG(("%s:%u:%s",
report->filename ? report->filename : "<no filename>",
(unsigned int) report->lineno,
message));
@@ -131,7 +131,7 @@ jsobject *js_newcompartment(jscontext *ctx, struct content* c)
JS_SetContextPrivate(cx, c); /* private pointer to content */
- js_new_globalfunc(cx, global);
+ jsapi_new_globalfunc(cx, global);
/* Populate the global object with the standard globals, like
Object and Array. */
diff --git a/javascript/global.h b/javascript/jsapi.h
index 329c82c8d..ce2051148 100644
--- a/javascript/global.h
+++ b/javascript/jsapi.h
@@ -17,12 +17,12 @@
*/
/** \file
- * spidermonkey engine global functions.
+ * spidermonkey jsapi bindings.
*/
-#ifndef _NETSURF_JAVASCRIPT_GLOBAL_H_
-#define _NETSURF_JAVASCRIPT_GLOBAL_H_
+#ifndef _NETSURF_JAVASCRIPT_JSAPI_H_
+#define _NETSURF_JAVASCRIPT_JSAPI_H_
-bool js_new_globalfunc(JSContext *cx, JSObject *global);
+bool jsapi_new_globalfunc(JSContext *cx, JSObject *global);
#endif
diff --git a/javascript/global.c b/javascript/jsapi/global.c
index c2033d4fc..b86400428 100644
--- a/javascript/global.c
+++ b/javascript/jsapi/global.c
@@ -19,7 +19,7 @@
#include "mozjs/jsapi.h"
#include "content/content.h"
-#include "javascript/global.h"
+#include "javascript/jsapi.h"
#include "utils/log.h"
static JSBool jsalert(JSContext *cx, uintN argc, jsval *vp)
@@ -54,7 +54,7 @@ static JSFunctionSpec global_functions[] =
JS_FS_END
};
-bool js_new_globalfunc(JSContext *cx, JSObject *global)
+bool jsapi_new_globalfunc(JSContext *cx, JSObject *global)
{
return JS_DefineFunctions(cx, global, global_functions);
}
diff --git a/javascript/nojs.c b/javascript/none.c
index ec0ccc0f8..ec0ccc0f8 100644
--- a/javascript/nojs.c
+++ b/javascript/none.c
diff --git a/render/html.c b/render/html.c
index e7ebbd54c..a3b5e01a2 100644
--- a/render/html.c
+++ b/render/html.c
@@ -93,6 +93,7 @@ static dom_string *html_dom_string_title;
static dom_string *html_dom_string_base;
static dom_string *html_dom_string_link;
static dom_string *html_dom_string_script;
+static dom_string *html_dom_string_src;
dom_string *html_dom_string_target;
static dom_string *html_dom_string__parent;
static dom_string *html_dom_string__self;
@@ -147,6 +148,8 @@ html_create_html_data(html_content *c, const http_parameter *params)
c->box = NULL;
c->font_func = &nsfont;
c->scrollbar = NULL;
+ c->scripts_count = 0;
+ c->scripts = NULL;
c->jscontext = NULL;
if (lwc_intern_string("*", SLEN("*"), &c->universal) != lwc_error_ok) {
@@ -346,39 +349,6 @@ encoding_change:
}
}
-/** process script node */
-static bool html_process_script(html_content *c, dom_node *node)
-{
- dom_exception exc; /* returned by libdom functions */
- dom_string *script;
-
- bool success = true;
-
- /* ensure javascript context is available */
- if (c->jscontext == NULL) {
- union content_msg_data msg_data;
-
- msg_data.jscontext = &c->jscontext;
- content_broadcast(&c->base, CONTENT_MSG_GETCTX, msg_data);
- LOG(("javascript context %p ", c->jscontext));
- if (c->jscontext == NULL) {
- return false;
- }
- }
-
- exc = dom_node_get_text_content(node, &script);
- if ((exc != DOM_NO_ERR) || (script == NULL)) {
- return false;
- }
-
- js_exec(c->jscontext,
- dom_string_data(script),
- dom_string_byte_length(script)) ;
-
- dom_string_unref(script);
-
- return success;
-}
/** process link node */
static bool html_process_link(html_content *c, dom_node *node)
@@ -581,10 +551,7 @@ static bool html_head(html_content *c, dom_node *head)
} else if (dom_string_caseless_isequal(node_name,
html_dom_string_link)) {
html_process_link(c, node);
- } else if (dom_string_caseless_isequal(node_name,
- html_dom_string_script)) {
- html_process_script(c, node);
- }
+ }
}
}
@@ -958,6 +925,8 @@ html_object_callback(hlcache_handle *object,
case CONTENT_MSG_DONE:
c->base.active--;
+ LOG(("%d fetches active", c->base.active));
+
html_object_done(box, object, o->background);
if (c->base.status != CONTENT_STATUS_LOADING &&
@@ -985,6 +954,7 @@ html_object_callback(hlcache_handle *object,
o->content = NULL;
c->base.active--;
+ LOG(("%d fetches active", c->base.active));
content_add_error(&c->base, "?", 0);
html_set_status(c, event->data.error);
@@ -1107,8 +1077,10 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url)
if (object->content != NULL) {
/* remove existing object */
- if (content_get_status(object->content) != CONTENT_STATUS_DONE)
+ if (content_get_status(object->content) != CONTENT_STATUS_DONE) {
c->base.active--;
+ LOG(("%d fetches active", c->base.active));
+ }
hlcache_handle_release(object->content);
object->content = NULL;
@@ -1128,6 +1100,8 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url)
for (page = c; page != NULL; page = page->page) {
page->base.active++;
+ LOG(("%d fetches active", c->base.active));
+
page->base.status = CONTENT_STATUS_READY;
}
@@ -1375,9 +1349,10 @@ html_convert_css_callback(hlcache_handle *css,
break;
case CONTENT_MSG_DONE:
- LOG(("got stylesheet '%s'",
+ 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:
@@ -1387,6 +1362,7 @@ html_convert_css_callback(hlcache_handle *css,
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;
@@ -1542,11 +1518,13 @@ html_process_style_element(html_content *c,
}
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);
talloc_free(sheet);
sheet = NULL;
@@ -1564,95 +1542,22 @@ no_memory:
return false;
}
-/**
- * Process inline stylesheets and fetch linked stylesheets.
- *
- * Uses STYLE and LINK elements inside and outside HEAD
+
+/* depth-first walk the dom calling callback for each element
*
- * \param c content structure
- * \param html xml node of html element
- * \return true on success, false if an error occurred
+ * @param root the dom node to use as the root of the tree walk
+ * @return true if all nodes were examined, false if the callback terminated
+ * the walk early.
*/
-
-static bool html_find_stylesheets(html_content *c, dom_node *html)
+static bool
+html_treewalk_dom(dom_node *root,
+ bool (*callback)(dom_node *node, dom_string *name, void *ctx),
+ void *ctx)
{
- content_type accept = CONTENT_CSS;
dom_node *node;
- unsigned int i = STYLESHEET_START;
- union content_msg_data msg_data;
- struct html_stylesheet *stylesheets;
- hlcache_child_context child;
- nserror ns_error;
- nsurl *joined;
-
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- /* 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 = talloc_array(c, struct html_stylesheet,
- STYLESHEET_START);
- if (c->stylesheets == NULL)
- goto 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;
-
- c->base.active = 0;
-
- ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0,
- content_get_url(&c->base), NULL,
- html_convert_css_callback, c, &child, accept,
- &c->stylesheets[STYLESHEET_BASE].data.external);
- if (ns_error != NSERROR_OK)
- goto no_memory;
-
- c->base.active++;
-
- if (c->quirks == BINDING_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, accept,
- &c->stylesheets[STYLESHEET_QUIRKS].
- data.external);
- if (ns_error != NSERROR_OK)
- goto no_memory;
-
- c->base.active++;
- }
+ bool result = true;;
- 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, accept,
- &c->stylesheets[STYLESHEET_ADBLOCK].
- data.external);
- if (ns_error != NSERROR_OK)
- goto no_memory;
-
- 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, accept,
- &c->stylesheets[STYLESHEET_USER].data.external);
- if (ns_error != NSERROR_OK)
- goto no_memory;
-
- c->base.active++;
-
- /* depth-first search the tree for link elements */
-
- node = dom_node_ref(html); /* tree root */
+ node = dom_node_ref(root); /* tree root */
while (node != NULL) {
dom_node *next = NULL;
@@ -1723,126 +1628,525 @@ static bool html_find_stylesheets(html_content *c, dom_node *html)
assert(node != NULL);
exc = dom_node_get_node_type(node, &type);
- if (exc != DOM_NO_ERR || type != DOM_ELEMENT_NODE)
+ if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE))
continue;
exc = dom_node_get_node_name(node, &name);
if (exc != DOM_NO_ERR)
continue;
- if (strcmp(dom_string_data(name), "link") == 0) {
- dom_string *rel, *type_attr, *media, *href;
+ result = callback(node, name, ctx);
- dom_string_unref(name);
+ dom_string_unref(name);
- /* rel=<space separated list, including 'stylesheet'> */
- exc = dom_element_get_attribute(node,
- html_dom_string_rel, &rel);
- if (exc != DOM_NO_ERR || rel == NULL)
- continue;
+ if (result == false) {
+ break; /* callback caused early termination */
+ }
+
+ }
+ return result;
+}
- if (strcasestr(dom_string_data(rel),
- "stylesheet") == 0) {
- dom_string_unref(rel);
- continue;
- } else if (strcasestr(dom_string_data(rel),
- "alternate") != 0) {
- /* Ignore alternate stylesheets */
- dom_string_unref(rel);
- continue;
- }
- dom_string_unref(rel);
-
- /* type='text/css' or not present */
- exc = dom_element_get_attribute(node,
- html_dom_string_type, &type_attr);
- if (exc == DOM_NO_ERR && type_attr != NULL) {
- if (strcmp(dom_string_data(type_attr),
- "text/css") != 0) {
- dom_string_unref(type_attr);
- continue;
- }
- dom_string_unref(type_attr);
- }
+/* attempt to progress script execution
+ *
+ * execute scripts using algorithm found in:
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element
+ *
+ */
+static bool html_scripts_exec(html_content *c)
+{
+ unsigned int i;
+ struct html_script *s;
- /* media contains 'screen' or 'all' or not present */
- exc = dom_element_get_attribute(node,
- html_dom_string_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);
- continue;
+ if (c->jscontext == NULL)
+ return false;
+
+ for (i = 0, s = c->scripts; i != c->scripts_count; i++, s++) {
+ if (s->already_started) {
+ continue;
+ }
+
+ assert((s->type == HTML_SCRIPT_EXTERNAL) ||
+ (s->type == HTML_SCRIPT_INTERNAL));
+
+ if (s->type == HTML_SCRIPT_EXTERNAL) {
+ if (s->data.external == NULL)
+ continue; /* script not present - skip */
+
+ if (content_get_status(s->data.external) == CONTENT_STATUS_ERROR)
+ continue; /* script content errored - skip */
+
+ if (content_get_status(s->data.external) == CONTENT_STATUS_DONE) {
+ /* external script is now available
+ * execute it and continue
+ */
+ const char *data;
+ unsigned long size;
+ data = content_get_source_data(s->data.external, &size );
+ js_exec(c->jscontext, data, size);
+ s->already_started = true;
+
+ } else {
+ /* script not yet available */
+ if (!s->defer && !s->async) {
+ break; /* not deferable or async */
}
- dom_string_unref(media);
}
+ } else {
+ js_exec(c->jscontext,
+ dom_string_data(s->data.internal),
+ dom_string_byte_length(s->data.internal));
+ s->already_started = true;
+ }
+ }
- /* href='...' */
- exc = dom_element_get_attribute(node,
- html_dom_string_href, &href);
- if (exc != DOM_NO_ERR || href == NULL)
- continue;
+ return true;
+}
- /* TODO: only the first preferred stylesheets (ie.
- * those with a title attribute) should be loaded
- * (see HTML4 14.3) */
+/* create new html script entry */
+static struct html_script *html_process_new_script(html_content *c, enum html_script_type type)
+{
+ struct html_script *nscript;
+ /* add space for new script entry */
+ nscript = realloc(c->scripts,
+ sizeof(struct html_script) * (c->scripts_count + 1));
+ if (nscript == NULL) {
+ return NULL;
+ }
- ns_error = nsurl_join(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'", i,
- nsurl_access(joined)));
-
- /* start fetch */
- stylesheets = talloc_realloc(c,
- c->stylesheets,
- struct html_stylesheet, i + 1);
- if (stylesheets == NULL) {
- nsurl_unref(joined);
- goto no_memory;
- }
+ c->scripts = nscript;
- c->stylesheets = stylesheets;
- c->stylesheet_count++;
- c->stylesheets[i].type = HTML_STYLESHEET_EXTERNAL;
- ns_error = hlcache_handle_retrieve(joined, 0,
- content_get_url(&c->base), NULL,
- html_convert_css_callback, c, &child,
- accept,
- &c->stylesheets[i].data.external);
+ /* increment script entry count */
+ nscript = &c->scripts[c->scripts_count];
+ c->scripts_count++;
- nsurl_unref(joined);
+ nscript->already_started = false;
+ nscript->parser_inserted = false;
+ nscript->force_async = true;
+ nscript->ready_exec = false;
+ nscript->async = false;
+ nscript->defer = false;
- if (ns_error != NSERROR_OK)
- goto no_memory;
+ nscript->type = type;
- c->base.active++;
+ return nscript;
+}
- i++;
- } else if (strcmp(dom_string_data(name), "style") == 0) {
- dom_string_unref(name);
+/**
+ * Callback for fetchcache() for linked stylesheets.
+ */
- if (!html_process_style_element(c, &i, node))
- return false;
- } else {
- dom_string_unref(name);
+static nserror
+html_convert_script_callback(hlcache_handle *script,
+ const hlcache_event *event,
+ void *pw)
+{
+ html_content *parent = pw;
+ unsigned int i;
+ struct html_script *s;
+
+ /* Find sheet */
+ for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
+ if (s->type == HTML_SCRIPT_EXTERNAL &&
+ s->data.external == script)
+ break;
+ }
+
+ assert(i != parent->scripts_count);
+
+ switch (event->type) {
+ case CONTENT_MSG_LOADING:
+ break;
+
+ case CONTENT_MSG_READY:
+ break;
+
+ case CONTENT_MSG_DONE:
+ LOG(("script %d done '%s'", i,
+ nsurl_access(hlcache_handle_get_url(script))));
+ parent->base.active--;
+ LOG(("%d fetches active", parent->base.active));
+
+ /* script finished loading so try and continue execution */
+ html_scripts_exec(parent);
+ break;
+
+ case CONTENT_MSG_ERROR:
+ LOG(("script %s failed: %s",
+ nsurl_access(hlcache_handle_get_url(script)),
+ event->data.error));
+ hlcache_handle_release(script);
+ s->data.external = NULL;
+ parent->base.active--;
+ LOG(("%d fetches active", parent->base.active));
+ content_add_error(&parent->base, "?", 0);
+
+ /* script failed loading so try and continue execution */
+ html_scripts_exec(parent);
+
+ break;
+
+ case CONTENT_MSG_STATUS:
+ html_set_status(parent, content_get_status_message(script));
+ content_broadcast(&parent->base, CONTENT_MSG_STATUS,
+ event->data);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ if (parent->base.active == 0)
+ html_finish_conversion(parent);
+
+ return NSERROR_OK;
+}
+
+/** process script node
+ *
+ *
+ */
+static bool
+html_process_script(dom_node *node, dom_string *name, void *ctx)
+{
+ html_content *c = (html_content *)ctx;
+ dom_exception exc; /* returned by libdom functions */
+ dom_string *src, *script;
+ struct html_script *nscript;
+ union content_msg_data msg_data;
+
+ if (!dom_string_isequal(name, html_dom_string_script))
+ return true; /* was not a script tag, carry on the walk */
+
+ /* ensure javascript context is available */
+ if (c->jscontext == NULL) {
+ union content_msg_data msg_data;
+
+ msg_data.jscontext = &c->jscontext;
+ content_broadcast(&c->base, CONTENT_MSG_GETCTX, msg_data);
+ LOG(("javascript context %p ", c->jscontext));
+ if (c->jscontext == NULL) {
+ /* no context and it could not be created, abort */
+ return false;
}
}
- assert(c->stylesheet_count == i);
+ exc = dom_element_get_attribute(node, html_dom_string_src, &src);
+ if (exc != DOM_NO_ERR || src == NULL) {
+ /* does not appear to be a src so script is inline content */
+ exc = dom_node_get_text_content(node, &script);
+ if ((exc != DOM_NO_ERR) || (script == NULL)) {
+ return true; /* no contents, skip */
+ }
+
+ nscript = html_process_new_script(c, HTML_STYLESHEET_INTERNAL);
+ if (nscript == NULL) {
+ dom_string_unref(script);
+ goto html_process_script_no_memory;
+ }
+
+ nscript->data.internal = script;
+
+ /* type */
+ /* charset (encoding) */
+ } else {
+ /* script with a src tag */
+ nserror ns_error;
+ nsurl *joined;
+ hlcache_child_context child;
+
+ child.charset = c->encoding;
+ child.quirks = c->base.quirks;
+
+ nscript = html_process_new_script(c, HTML_STYLESHEET_EXTERNAL);
+ if (nscript == NULL) {
+ dom_string_unref(src);
+ goto html_process_script_no_memory;
+ }
+
+ /* type */
+ /* charset (encoding) */
+
+ ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined);
+ dom_string_unref(src);
+ if (ns_error != NSERROR_OK) {
+ goto html_process_script_no_memory;
+ }
+
+ LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined)));
+
+ ns_error = hlcache_handle_retrieve(joined,
+ 0,
+ content_get_url(&c->base),
+ NULL,
+ html_convert_script_callback,
+ c,
+ &child,
+ CONTENT_ANY,
+ &nscript->data.external);
+
+ nsurl_unref(joined);
+
+ if (ns_error != NSERROR_OK)
+ goto html_process_script_no_memory;
+
+ c->base.active++; /* ensure base content knows the fetch is active */
+ LOG(("%d fetches active", c->base.active));
+
+ }
+
+ return true;
+
+html_process_script_no_memory:
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ return false; /* out of memory, abort walk */
+}
+
+/**
+ * Process inline script and fetch linked scripts.
+ *
+ *
+ *
+ * \param c content structure
+ * \param html dom node of html element
+ * \return true on success, false if an error occurred
+ */
+static bool html_find_scripts(html_content *c, dom_node *html)
+{
+ return html_treewalk_dom(html, html_process_script, c);
+}
+
+struct find_stylesheet_ctx {
+ unsigned int count;
+ hlcache_child_context child;
+ 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;
+ union content_msg_data msg_data;
+ dom_exception exc;
+ nserror ns_error;
+
+ /* deal with style nodes */
+ if (strcmp(dom_string_data(name), "style") == 0) {
+ if (!html_process_style_element(ctx->c, &ctx->count, node))
+ return false;
+ return true;
+ }
+
+ /* if it is not a link node skip it */
+ if (strcmp(dom_string_data(name), "link") != 0) {
+ return true;
+ }
+
+ /* rel=<space separated list, including 'stylesheet'> */
+ exc = dom_element_get_attribute(node,
+ html_dom_string_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, html_dom_string_type, &type_attr);
+ if (exc == DOM_NO_ERR && type_attr != NULL) {
+ if (strcmp(dom_string_data(type_attr), "text/css") != 0) {
+ 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, html_dom_string_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, html_dom_string_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 = talloc_realloc(ctx->c,
+ ctx->c->stylesheets,
+ struct html_stylesheet,
+ ctx->count + 1);
+ if (stylesheets == NULL) {
+ nsurl_unref(joined);
+ goto no_memory;
+ }
+
+ ctx->c->stylesheets = stylesheets;
+ ctx->c->stylesheet_count++;
+ ctx->c->stylesheets[ctx->count].type = HTML_STYLESHEET_EXTERNAL;
+ ns_error = hlcache_handle_retrieve(joined,
+ 0,
+ content_get_url(&ctx->c->base),
+ NULL,
+ html_convert_css_callback,
+ ctx->c,
+ &ctx->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:
msg_data.error = messages_get("NoMemory");
+ content_broadcast(&ctx->c->base, CONTENT_MSG_ERROR, msg_data);
+ 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)
+{
+ content_type accept = CONTENT_CSS;
+ union content_msg_data msg_data;
+ nserror ns_error;
+ bool result;
+ struct find_stylesheet_ctx ctx;
+
+ /* setup context */
+ ctx.c = c;
+ ctx.count = STYLESHEET_START;
+
+ ctx.child.charset = c->encoding;
+ ctx.child.quirks = c->base.quirks;
+
+ /* 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 = talloc_array(c, struct html_stylesheet,
+ STYLESHEET_START);
+ if (c->stylesheets == NULL)
+ 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;
+
+ ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0,
+ content_get_url(&c->base), NULL,
+ html_convert_css_callback, c, &ctx.child, accept,
+ &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 == BINDING_QUIRKS_MODE_FULL) {
+ ns_error = hlcache_handle_retrieve(html_quirks_stylesheet_url,
+ 0, content_get_url(&c->base), NULL,
+ html_convert_css_callback, c, &ctx.child, accept,
+ &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, &ctx.child, accept,
+ &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, &ctx.child, accept,
+ &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 = html_treewalk_dom(html, html_process_stylesheet, &ctx);
+
+ assert(c->stylesheet_count == ctx.count);
+
+ return result;
+
+html_find_stylesheets_no_memory:
+ msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return false;
}
@@ -2024,6 +2328,14 @@ static bool html_convert(struct content *c)
}
}
+ /* find script tags */
+ if (nsoption_bool(enable_javascript)) {
+ /* @todo this ought to be done during parse */
+ html_find_scripts(htmlc, html);
+ /* run as far as we can */
+ html_scripts_run(htmlc);
+ }
+
/* get stylesheets */
if (html_find_stylesheets(htmlc, html) == false)
return false;
@@ -2091,6 +2403,7 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
c->num_objects++;
c->base.active++;
+ LOG(("%d fetches active", c->base.active));
return true;
}
@@ -2099,12 +2412,6 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
-
-
-
-
-
-
/**
* Stop loading a CONTENT_HTML.
*/
@@ -2141,6 +2448,8 @@ static void html_stop(struct content *c)
object->content = NULL;
c->active--;
+ LOG(("%d fetches active", c->active));
+
}
}
@@ -2360,6 +2669,20 @@ static void html_destroy(struct content *c)
}
}
+ /* Free scripts */
+ for (i = 0; i != html->scripts_count; i++) {
+ if (html->scripts[i].type == HTML_SCRIPT_EXTERNAL &&
+ html->scripts[i].data.external != NULL) {
+ hlcache_handle_release(
+ html->scripts[i].data.external);
+ } else if (html->scripts[i].type ==
+ HTML_SCRIPT_INTERNAL &&
+ html->scripts[i].data.internal != NULL) {
+ dom_string_unref(html->scripts[i].data.internal);
+ }
+ }
+ free(html->scripts);
+
/* Free objects */
html_destroy_objects(html);
}
@@ -3034,6 +3357,7 @@ static void html_fini(void)
HTML_DOM_STRING_UNREF(sizes);
HTML_DOM_STRING_UNREF(title);
HTML_DOM_STRING_UNREF(base);
+ HTML_DOM_STRING_UNREF(src);
HTML_DOM_STRING_UNREF(script);
HTML_DOM_STRING_UNREF(link);
HTML_DOM_STRING_UNREF(target);
@@ -3164,6 +3488,7 @@ nserror html_init(void)
HTML_DOM_STRING_INTERN(base);
HTML_DOM_STRING_INTERN(link);
HTML_DOM_STRING_INTERN(script);
+ HTML_DOM_STRING_INTERN(src);
HTML_DOM_STRING_INTERN(target);
HTML_DOM_STRING_INTERN(_blank);
HTML_DOM_STRING_INTERN(_self);
diff --git a/render/html.h b/render/html.h
index 7d2ef82cf..f0ab47d51 100644
--- a/render/html.h
+++ b/render/html.h
@@ -58,6 +58,26 @@ struct html_stylesheet {
} data; /**< Sheet data */
};
+/**
+ * Container for scripts used by an HTML document
+ */
+struct html_script {
+ /** Type of script */
+ enum html_script_type { HTML_SCRIPT_EXTERNAL, HTML_SCRIPT_INTERNAL } type;
+ union {
+ struct hlcache_handle *external;
+ struct dom_string *internal;
+ } data; /**< Script data */
+ struct dom_string *script_type;
+ struct dom_string *encoding;
+ bool already_started;
+ bool parser_inserted;
+ bool force_async;
+ bool ready_exec;
+ bool async;
+ bool defer;
+};
+
/** An object (<img>, <object>, etc.) in a CONTENT_HTML document. */
struct content_html_object {
diff --git a/render/html_internal.h b/render/html_internal.h
index 3d9dea389..da3d686bd 100644
--- a/render/html_internal.h
+++ b/render/html_internal.h
@@ -58,6 +58,13 @@ typedef struct html_content {
/** Font callback table */
const struct font_functions *font_func;
+ /** Number of entries in scripts */
+ unsigned int scripts_count;
+ /** Scripts */
+ struct html_script *scripts;
+ /** javascript context */
+ struct jscontext *jscontext;
+
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;
/** Stylesheets. Each may be NULL. */
@@ -105,9 +112,6 @@ typedef struct html_content {
/** Context for free text search, or NULL if none */
struct search_context *search;
- /** javascript context */
- struct jscontext *jscontext;
-
} html_content;