Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/cbfd887311935675112aa...
...commit
http://git.netsurf-browser.org/netsurf.git/commit/cbfd887311935675112aa7a...
...tree
http://git.netsurf-browser.org/netsurf.git/tree/cbfd887311935675112aa7a79...
The branch, master has been updated
via cbfd887311935675112aa7a79f367d03324536e2 (commit)
via c0aaf31f5a9a65808d8b7af92434608135ccc752 (commit)
via d763e57d30dc8c68309c5b35f556531cb8346da5 (commit)
via 4182685d1e90e082407a8e40a0b1db76cf9fbea2 (commit)
via b0a41606ffe3b2cff04c68e0ae0aec96816cb857 (commit)
via db76dd3b1abd32950971c38b3a8fb915471fb3d2 (commit)
via 06608c1bf0b1046520e184fdc063c83ead2184af (commit)
via 4f0e70b50d2446ed3ba14bd51d61c80088226d91 (commit)
via f207f14be1e95d0c1fa1866decf2c07a119ba8fe (commit)
from 90b0c48bb216cef4f3aafbc14565f203a3f6861c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/netsurf.git/commitdiff/cbfd887311935675112...
commit cbfd887311935675112aa7a79f367d03324536e2
Merge: 90b0c48 c0aaf31
Author: Vincent Sanders <vince(a)netsurf-browser.org>
Commit: Vincent Sanders <vince(a)netsurf-browser.org>
Merge branch 'vince/script-async'
-----------------------------------------------------------------------
Summary of changes:
javascript/jsapi.h | 1 -
javascript/jsapi/document.c | 4 +-
javascript/jsapi/window.c | 12 +-
render/html.c | 159 +++++++-----
render/html.h | 13 +-
render/html_internal.h | 13 +-
render/html_script.c | 479 ++++++++++++++++++++++++++--------
test/js/assorted.html | 34 +++
test/js/index.html | 17 ++
test/js/inline-doc-write-simple.html | 11 +
test/js/inline-doc-write.html | 13 +
test/js/sync-script.html | 12 +
test/js/tst.css | 1 +
test/js/tst.js | 1 +
utils/corestrings.c | 6 +
utils/corestrings.h | 2 +
16 files changed, 599 insertions(+), 179 deletions(-)
create mode 100644 test/js/assorted.html
create mode 100644 test/js/index.html
create mode 100644 test/js/inline-doc-write-simple.html
create mode 100644 test/js/inline-doc-write.html
create mode 100644 test/js/sync-script.html
create mode 100644 test/js/tst.css
create mode 100644 test/js/tst.js
diff --git a/javascript/jsapi.h b/javascript/jsapi.h
index cf099cc..a44323f 100644
--- a/javascript/jsapi.h
+++ b/javascript/jsapi.h
@@ -79,7 +79,6 @@ JS_NewCompartmentAndGlobalObject(JSContext *cx,
if (global == NULL) {
return NULL;
}
- JS_SetGlobalObject(cx, global);
return global;
}
diff --git a/javascript/jsapi/document.c b/javascript/jsapi/document.c
index dfad551..bb5019c 100644
--- a/javascript/jsapi/document.c
+++ b/javascript/jsapi/document.c
@@ -92,8 +92,10 @@ JSObject *jsapi_new_document(JSContext *cx, JSObject *parent, void
*doc_priv)
LOG(("setting content to %p",doc_priv));
/* private pointer to browsing context */
- if (!JS_SetPrivate(cx, doc, doc_priv))
+ if (JS_SetPrivate(cx, doc, doc_priv) != JS_TRUE) {
+ LOG(("failed to set content"));
return NULL;
+ }
return doc;
}
diff --git a/javascript/jsapi/window.c b/javascript/jsapi/window.c
index 06e6cdf..0b7673b 100644
--- a/javascript/jsapi/window.c
+++ b/javascript/jsapi/window.c
@@ -299,8 +299,18 @@ JSObject * jsapi_new_window(JSContext *cx, JSObject *parent, void
*win_priv)
return NULL;
}
+ /** @todo reconsider global object handling. future
+ * editions of spidermonkey appear to be removing the
+ * idea of a global so we probably need to handle
+ * global object references internally
+ */
+
+ /* set the contexts global */
+ JS_SetGlobalObject(cx, window);
+
/* Populate the global object with the standard globals, like
- Object and Array. */
+ * Object and Array.
+ */
if (!JS_InitStandardClasses(cx, window)) {
return NULL;
}
diff --git a/render/html.c b/render/html.c
index 759c244..4263a06 100644
--- a/render/html.c
+++ b/render/html.c
@@ -301,6 +301,8 @@ html_create_html_data(html_content *c, const http_parameter *params)
c->scripts = NULL;
c->jscontext = NULL;
+ c->base.active = 1; /* The html content itself is active */
+
if (lwc_intern_string("*", SLEN("*"), &c->universal) !=
lwc_error_ok) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
@@ -412,12 +414,10 @@ html_create(const content_handler *handler,
-/**
- * Process data for CONTENT_HTML.
- */
-
static bool
-html_process_data(struct content *c, const char *data, unsigned int size)
+html_process_encoding_change(struct content *c,
+ const char *data,
+ unsigned int size)
{
html_content *html = (html_content *) c;
dom_hubbub_error error;
@@ -425,23 +425,6 @@ html_process_data(struct content *c, const char *data, unsigned int
size)
const char *source_data;
unsigned long source_size;
- error = dom_hubbub_parser_parse_chunk(html->parser, (const uint8_t *) data, size);
-
- if (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_ENCODINGCHANGE)) {
- goto encoding_change;
- } else if (error != DOM_HUBBUB_OK) {
- union content_msg_data msg_data;
-
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
-
- return false;
- }
-
- return true;
-
-encoding_change:
-
/* Retrieve new encoding */
encoding = dom_hubbub_parser_get_encoding(html->parser,
&html->encoding_source);
@@ -464,11 +447,11 @@ encoding_change:
/* Create new binding, using the new encoding */
html->parser = dom_hubbub_parser_create(html->encoding,
- true,
- nsoption_bool(enable_javascript),
- NULL,
- html_process_script,
- html);
+ true,
+ nsoption_bool(enable_javascript),
+ NULL,
+ html_process_script,
+ html);
if (html->parser == NULL) {
/* Ok, we don't support the declared encoding. Bailing out
* isn't exactly user-friendly, so fall back to Windows-1252 */
@@ -506,10 +489,50 @@ encoding_change:
source_data = content__get_source_data(c, &source_size);
- /* Recurse to reprocess all the data. This is safe because
+ /* Reprocess all the data. This is safe because
* the encoding is now specified at parser start which means
* it cannot be changed again. */
- return html_process_data(c, source_data, source_size);
+ error = dom_hubbub_parser_parse_chunk(html->parser, (const uint8_t *)source_data,
source_size);
+
+ if ((error == DOM_HUBBUB_OK) ||
+ (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED))) {
+ return true;
+ }
+
+ union content_msg_data msg_data;
+
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+
+ return false;
+
+}
+
+/**
+ * Process data for CONTENT_HTML.
+ */
+
+static bool
+html_process_data(struct content *c, const char *data, unsigned int size)
+{
+ html_content *html = (html_content *) c;
+ dom_hubbub_error error;
+ union content_msg_data msg_data;
+
+ error = dom_hubbub_parser_parse_chunk(html->parser, (const uint8_t *) data, size);
+
+ if ((error == DOM_HUBBUB_OK) ||
+ (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED))) {
+ return true;
+ } else if (error == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_ENCODINGCHANGE)) {
+ return html_process_encoding_change(c, data, size);
+ }
+
+ /** @todo better error handling and reporting */
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+
+ return false;
}
@@ -1912,24 +1935,39 @@ html_find_stylesheets_no_memory:
static bool html_convert(struct content *c)
{
html_content *htmlc = (html_content *) c;
- dom_hubbub_error err;
+
+ htmlc->base.active--; /* the html fetch is no longer active */
+ LOG(("%d fetches active", htmlc->base.active));
+
+
+ /* if there are no active fetches in progress no scripts are
+ * being fetched or they completed already.
+ */
+ if (htmlc->base.active == 0) {
+ return html_begin_conversion(htmlc);
+ }
+ return true;
+
+}
+
+bool
+html_begin_conversion(html_content *htmlc)
+{
dom_node *html, *head;
union content_msg_data msg_data;
- unsigned long size;
struct form *f;
dom_exception exc; /* returned by libdom functions */
dom_string *node_name = NULL;
+ dom_hubbub_error error;
- /* finish parsing */
- content__get_source_data(c, &size);
-
- err = dom_hubbub_parser_completed(htmlc->parser);
- if (err != DOM_HUBBUB_OK) {
+ /* complete parsing */
+ error = dom_hubbub_parser_completed(htmlc->parser);
+ if (error != DOM_HUBBUB_OK) {
union content_msg_data msg_data;
- /** @todo Improve precessing of errors */
+ /** @todo Improve processing of errors */
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
return false;
}
@@ -1939,7 +1977,7 @@ static bool html_convert(struct content *c)
if (htmlc->document == NULL) {
LOG(("Parsing failed"));
msg_data.error = messages_get("ParsingFail");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
return false;
}
@@ -1956,10 +1994,10 @@ static bool html_convert(struct content *c)
encoding = dom_hubbub_parser_get_encoding(htmlc->parser,
&htmlc->encoding_source);
- htmlc->encoding = talloc_strdup(c, encoding);
+ htmlc->encoding = talloc_strdup(&htmlc->base, encoding);
if (htmlc->encoding == NULL) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
return false;
}
}
@@ -1967,7 +2005,7 @@ static bool html_convert(struct content *c)
/* Give up processing if we've been aborted */
if (htmlc->aborted) {
msg_data.error = messages_get("Stopped");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
return false;
}
@@ -1976,7 +2014,7 @@ static bool html_convert(struct content *c)
if ((exc != DOM_NO_ERR) || (html == NULL)) {
LOG(("error retrieving html element from dom"));
msg_data.error = messages_get("ParsingFail");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
return false;
}
@@ -1987,7 +2025,7 @@ static bool html_convert(struct content *c)
corestring_lwc_html))) {
LOG(("root element not html"));
msg_data.error = messages_get("ParsingFail");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
dom_node_unref(html);
return false;
}
@@ -2036,7 +2074,7 @@ static bool html_convert(struct content *c)
if (head != NULL) {
if (html_head(htmlc, head) == false) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
dom_node_unref(html);
dom_node_unref(head);
return false;
@@ -2060,7 +2098,7 @@ static bool html_convert(struct content *c)
/* Make all actions absolute */
if (f->action == NULL || f->action[0] == '\0') {
/* HTML5 4.10.22.3 step 11 */
- res = url_join(nsurl_access(content_get_url(c)),
+ res = url_join(nsurl_access(content_get_url(&htmlc->base)),
nsurl_access(htmlc->base_url), &action);
} else {
res = url_join(f->action, nsurl_access(htmlc->base_url),
@@ -2069,7 +2107,7 @@ static bool html_convert(struct content *c)
if (res != URL_FUNC_OK) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_ERROR, msg_data);
dom_node_unref(html);
dom_node_unref(head);
return false;
@@ -2083,8 +2121,9 @@ static bool html_convert(struct content *c)
f->document_charset = strdup(htmlc->encoding);
if (f->document_charset == NULL) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR,
- msg_data);
+ content_broadcast(&htmlc->base,
+ CONTENT_MSG_ERROR,
+ msg_data);
dom_node_unref(html);
dom_node_unref(head);
return false;
@@ -2093,6 +2132,7 @@ static bool html_convert(struct content *c)
}
dom_node_unref(head);
+
/* get stylesheets */
if (html_find_stylesheets(htmlc, html) == false) {
dom_node_unref(html);
@@ -2100,6 +2140,11 @@ static bool html_convert(struct content *c)
}
dom_node_unref(html);
+
+ if (htmlc->base.active == 0) {
+ html_finish_conversion(htmlc);
+ }
+
return true;
}
@@ -2433,21 +2478,7 @@ static void html_destroy(struct content *c)
}
/* Free scripts */
- for (i = 0; i != html->scripts_count; i++) {
- if (html->scripts[i].mimetype != NULL) {
- dom_string_unref(html->scripts[i].mimetype);
- }
- 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);
+ html_free_scripts(html);
/* Free objects */
html_destroy_objects(html);
diff --git a/render/html.h b/render/html.h
index 64548f8..dcbc1a3 100644
--- a/render/html.h
+++ b/render/html.h
@@ -66,10 +66,13 @@ struct html_stylesheet {
*/
struct html_script {
/** Type of script */
- enum html_script_type { HTML_SCRIPT_EXTERNAL, HTML_SCRIPT_INTERNAL } type;
+ enum html_script_type { HTML_SCRIPT_INLINE,
+ HTML_SCRIPT_SYNC,
+ HTML_SCRIPT_DEFER,
+ HTML_SCRIPT_ASYNC } type;
union {
- struct hlcache_handle *external;
- struct dom_string *internal;
+ struct hlcache_handle *handle;
+ struct dom_string *string;
} data; /**< Script data */
struct dom_string *mimetype;
struct dom_string *encoding;
@@ -175,9 +178,9 @@ struct content_html_frames *html_get_frameset(struct hlcache_handle
*h);
struct content_html_iframe *html_get_iframe(struct hlcache_handle *h);
nsurl *html_get_base_url(struct hlcache_handle *h);
const char *html_get_base_target(struct hlcache_handle *h);
-struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h,
+struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h,
unsigned int *n);
-struct content_html_object *html_get_objects(struct hlcache_handle *h,
+struct content_html_object *html_get_objects(struct hlcache_handle *h,
unsigned int *n);
bool html_get_id_offset(struct hlcache_handle *h, lwc_string *frag_id,
int *x, int *y);
diff --git a/render/html_internal.h b/render/html_internal.h
index ad032f7..0f20cc1 100644
--- a/render/html_internal.h
+++ b/render/html_internal.h
@@ -127,12 +127,20 @@ void html__redraw_a_box(struct content *c, struct box *box);
struct browser_window *html_get_browser_window(struct content *c);
struct search_context *html_get_search(struct content *c);
void html_set_search(struct content *c, struct search_context *s);
+
/**
* Complete conversion of an HTML document
*
- * \param c Content to convert
+ * \param htmlc Content to convert
+ */
+void html_finish_conversion(html_content *htmlc);
+
+/**
+ * Begin conversion of an HTML document
+ *
+ * \param htmlc Content to convert
*/
-void html_finish_conversion(html_content *c);
+bool html_begin_conversion(html_content *htmlc);
/* in render/html_redraw.c */
bool html_redraw(struct content *c, struct content_redraw_data *data,
@@ -149,6 +157,7 @@ void html_overflow_scroll_callback(void *client_data,
/* in render/html_script.c */
dom_hubbub_error html_process_script(void *ctx, dom_node *node);
+void html_free_scripts(html_content *html);
/* in render/html_forms.c */
struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc);
diff --git a/render/html_script.c b/render/html_script.c
index 5fd8c8a..f4d80ab 100644
--- a/render/html_script.c
+++ b/render/html_script.c
@@ -69,32 +69,32 @@ static bool html_scripts_exec(html_content *c)
continue;
}
- assert((s->type == HTML_SCRIPT_EXTERNAL) ||
- (s->type == HTML_SCRIPT_INTERNAL));
+ assert((s->type == HTML_SCRIPT_SYNC) ||
+ (s->type == HTML_SCRIPT_INLINE));
- if (s->type == HTML_SCRIPT_EXTERNAL) {
+ if (s->type == HTML_SCRIPT_SYNC) {
/* ensure script content is present */
- if (s->data.external == NULL)
+ if (s->data.handle == NULL)
continue;
/* ensure script content fetch status is not an error */
- if (content_get_status(s->data.external) ==
+ if (content_get_status(s->data.handle) ==
CONTENT_STATUS_ERROR)
continue;
/* ensure script handler for content type */
script_handler = select_script_handler(
- content_get_type(s->data.external));
+ content_get_type(s->data.handle));
if (script_handler == NULL)
continue; /* unsupported type */
- if (content_get_status(s->data.external) ==
+ if (content_get_status(s->data.handle) ==
CONTENT_STATUS_DONE) {
/* external script is now available */
const char *data;
unsigned long size;
data = content_get_source_data(
- s->data.external, &size );
+ s->data.handle, &size );
script_handler(c->jscontext, data, size);
s->already_started = true;
@@ -115,7 +115,9 @@ static bool html_scripts_exec(html_content *c)
/* create new html script entry */
static struct html_script *
-html_process_new_script(html_content *c, enum html_script_type type)
+html_process_new_script(html_content *c,
+ dom_string *mimetype,
+ enum html_script_type type)
{
struct html_script *nscript;
/* add space for new script entry */
@@ -140,15 +142,78 @@ html_process_new_script(html_content *c, enum html_script_type
type)
nscript->type = type;
+ nscript->mimetype = dom_string_ref(mimetype); /* reference mimetype */
+
return nscript;
}
/**
- * Callback for fetchcache() for linked stylesheets.
+ * Callback for asyncronous scripts
*/
+static nserror
+convert_script_async_cb(hlcache_handle *script,
+ const hlcache_event *event,
+ void *pw)
+{
+ html_content *parent = pw;
+ unsigned int i;
+ struct html_script *s;
+
+ /* Find script */
+ for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
+ if (s->type == HTML_SCRIPT_ASYNC && s->data.handle == 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));
+
+
+
+ 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.handle = NULL;
+ parent->base.active--;
+ LOG(("%d fetches active", parent->base.active));
+ content_add_error(&parent->base, "?", 0);
+
+ 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);
+ }
+ return NSERROR_OK;
+}
+
+/**
+ * Callback for defer scripts
+ */
static nserror
-html_convert_script_callback(hlcache_handle *script,
+convert_script_defer_cb(hlcache_handle *script,
const hlcache_event *event,
void *pw)
{
@@ -158,8 +223,7 @@ html_convert_script_callback(hlcache_handle *script,
/* Find script */
for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
- if (s->type == HTML_SCRIPT_EXTERNAL &&
- s->data.external == script)
+ if (s->type == HTML_SCRIPT_ASYNC && s->data.handle == script)
break;
}
@@ -178,8 +242,6 @@ html_convert_script_callback(hlcache_handle *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:
@@ -187,13 +249,101 @@ html_convert_script_callback(hlcache_handle *script,
nsurl_access(hlcache_handle_get_url(script)),
event->data.error));
hlcache_handle_release(script);
- s->data.external = NULL;
+ s->data.handle = 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 there are no active fetches remaining begin post parse
+ * conversion
+ */
+ if (parent->base.active == 0) {
+ html_begin_conversion(parent);
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Callback for syncronous scripts
+ */
+static nserror
+convert_script_sync_cb(hlcache_handle *script,
+ const hlcache_event *event,
+ void *pw)
+{
+ html_content *parent = pw;
+ unsigned int i;
+ struct html_script *s;
+ script_handler_t *script_handler;
+ dom_hubbub_error err;
+
+ /* Find script */
+ for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
+ if (s->type == HTML_SCRIPT_SYNC && s->data.handle == 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));
+
+ s->already_started = true;
+
+ /* attempt to execute script */
+ script_handler = select_script_handler(content_get_type(s->data.handle));
+ if (script_handler != NULL) {
+ /* script has a handler */
+ const char *data;
+ unsigned long size;
+ data = content_get_source_data(s->data.handle, &size );
+ script_handler(parent->jscontext, data, size);
+ }
+
+ /* continue parse */
+ err = dom_hubbub_parser_pause(parent->parser, false);
+ if (err != DOM_HUBBUB_OK) {
+ LOG(("unpause returned 0x%x", err));
+ }
+
+ 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.handle = NULL;
+ parent->base.active--;
+
+ LOG(("%d fetches active", parent->base.active));
+ content_add_error(&parent->base, "?", 0);
+
+ s->already_started = true;
break;
@@ -207,13 +357,193 @@ html_convert_script_callback(hlcache_handle *script,
assert(0);
}
- if (parent->base.active == 0)
- html_finish_conversion(parent);
+ /* if there are no active fetches remaining begin post parse
+ * conversion
+ */
+ if (parent->base.active == 0) {
+ html_begin_conversion(parent);
+ }
return NSERROR_OK;
}
-/** process script node
+/**
+ * process a script with a src tag
+ */
+static dom_hubbub_error
+exec_src_script(html_content *c,
+ dom_node *node,
+ dom_string *mimetype,
+ dom_string *src)
+{
+ nserror ns_error;
+ nsurl *joined;
+ hlcache_child_context child;
+ struct html_script *nscript;
+ union content_msg_data msg_data;
+ bool async;
+ bool defer;
+ enum html_script_type script_type;
+ hlcache_handle_callback script_cb;
+ dom_hubbub_error ret = DOM_HUBBUB_OK;
+ dom_exception exc; /* returned by libdom functions */
+
+ /* src url */
+ ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined);
+ if (ns_error != NSERROR_OK) {
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ return DOM_HUBBUB_NOMEM;
+ }
+
+ LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined)));
+
+ /* there are three ways to process the script tag at this point:
+ *
+ * Syncronously pause the parent parse and continue after
+ * the script has downloaded and executed. (default)
+ * Async Start the script downloading and execute it when it
+ * becomes available.
+ * Defered Start the script downloading and execute it when
+ * the page has completed parsing, may be set along
+ * with async where it is ignored.
+ */
+
+ /* we interpret the presence of the async and defer attribute
+ * as true and ignore its value, technically only the empty
+ * value or the attribute name itself are valid. However
+ * various browsers interpret this in various ways the most
+ * compatible approach is to be liberal and accept any
+ * value. Note setting the values to "false" still makes them true!
+ */
+ exc = dom_element_has_attribute(node, corestring_dom_async, &async);
+ if (exc != DOM_NO_ERR) {
+ return DOM_HUBBUB_OK; /* dom error */
+ }
+
+ if (async) {
+ /* asyncronous script */
+ script_type = HTML_SCRIPT_ASYNC;
+ script_cb = convert_script_async_cb;
+
+ } else {
+ exc = dom_element_has_attribute(node,
+ corestring_dom_defer, &defer);
+ if (exc != DOM_NO_ERR) {
+ return DOM_HUBBUB_OK; /* dom error */
+ }
+
+ if (defer) {
+ /* defered script */
+ script_type = HTML_SCRIPT_DEFER;
+ script_cb = convert_script_defer_cb;
+ } else {
+ /* syncronous script */
+ script_type = HTML_SCRIPT_SYNC;
+ script_cb = convert_script_sync_cb;
+ }
+ }
+
+ nscript = html_process_new_script(c, mimetype, script_type);
+ if (nscript == NULL) {
+ nsurl_unref(joined);
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ return DOM_HUBBUB_NOMEM;
+ }
+
+ /* set up child fetch encoding and quirks */
+ child.charset = c->encoding;
+ child.quirks = c->base.quirks;
+
+ ns_error = hlcache_handle_retrieve(joined,
+ 0,
+ content_get_url(&c->base),
+ NULL,
+ script_cb,
+ c,
+ &child,
+ CONTENT_SCRIPT,
+ &nscript->data.handle);
+
+
+ nsurl_unref(joined);
+
+ if (ns_error != NSERROR_OK) {
+ /* @todo Deal with fetch error better. currently assume
+ * fetch never became active
+ */
+ /* mark duff script fetch as already started */
+ nscript->already_started = true;
+ LOG(("Fetch failed with error %d",ns_error));
+ } else {
+ /* update base content active fetch count */
+ c->base.active++;
+ LOG(("%d fetches active", c->base.active));
+
+ switch (script_type) {
+ case HTML_SCRIPT_SYNC:
+ ret = DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED;
+
+ case HTML_SCRIPT_ASYNC:
+ break;
+
+ case HTML_SCRIPT_DEFER:
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ return ret;
+}
+
+static dom_hubbub_error
+exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype)
+{
+ union content_msg_data msg_data;
+ dom_string *script;
+ dom_exception exc; /* returned by libdom functions */
+ struct lwc_string_s *lwcmimetype;
+ script_handler_t *script_handler;
+ struct html_script *nscript;
+
+ /* 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 DOM_HUBBUB_OK; /* no contents, skip */
+ }
+
+ nscript = html_process_new_script(c, mimetype, HTML_SCRIPT_INLINE);
+ if (nscript == NULL) {
+ dom_string_unref(script);
+
+ msg_data.error = messages_get("NoMemory");
+ content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ return DOM_HUBBUB_NOMEM;
+
+ }
+
+ nscript->data.string = script;
+ nscript->already_started = true;
+
+ /* ensure script handler for content type */
+ dom_string_intern(mimetype, &lwcmimetype);
+ script_handler =
select_script_handler(content_factory_type_from_mime_type(lwcmimetype));
+ lwc_string_unref(lwcmimetype);
+
+ if (script_handler != NULL) {
+ script_handler(c->jscontext,
+ dom_string_data(script),
+ dom_string_byte_length(script));
+ }
+ return DOM_HUBBUB_OK;
+}
+
+
+/**
+ * process script node parser callback
*
*
*/
@@ -222,9 +552,8 @@ html_process_script(void *ctx, dom_node *node)
{
html_content *c = (html_content *)ctx;
dom_exception exc; /* returned by libdom functions */
- dom_string *src, *script, *mimetype;
- struct html_script *nscript;
- union content_msg_data msg_data;
+ dom_string *src, *mimetype;
+ dom_hubbub_error err = DOM_HUBBUB_OK;
/* ensure javascript context is available */
if (c->jscontext == NULL) {
@@ -239,7 +568,7 @@ html_process_script(void *ctx, dom_node *node)
}
}
- LOG(("content %p parser %p node %p",c,c->parser, node));
+ LOG(("content %p parser %p node %p", c, c->parser, node));
exc = dom_element_get_attribute(node, corestring_dom_type, &mimetype);
if (exc != DOM_NO_ERR || mimetype == NULL) {
@@ -248,97 +577,37 @@ html_process_script(void *ctx, dom_node *node)
exc = dom_element_get_attribute(node, corestring_dom_src, &src);
if (exc != DOM_NO_ERR || src == NULL) {
- struct lwc_string_s *lwcmimetype;
- script_handler_t *script_handler;
-
- /* 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)) {
- dom_string_unref(mimetype);
- return DOM_HUBBUB_OK; /* no contents, skip */
- }
-
- nscript = html_process_new_script(c, HTML_STYLESHEET_INTERNAL);
- if (nscript == NULL) {
- dom_string_unref(mimetype);
- dom_string_unref(script);
- goto html_process_script_no_memory;
- }
-
- nscript->data.internal = script;
- nscript->mimetype = mimetype;
- nscript->already_started = true;
-
- /* charset (encoding) */
-
- /* ensure script handler for content type */
- dom_string_intern(mimetype, &lwcmimetype);
- script_handler =
select_script_handler(content_factory_type_from_mime_type(lwcmimetype));
- lwc_string_unref(lwcmimetype);
-
- if (script_handler != NULL) {
- script_handler(c->jscontext,
- dom_string_data(script),
- dom_string_byte_length(script));
- }
-
-
+ err = exec_inline_script(c, node, mimetype);
} else {
- /* script with a src tag */
- nserror ns_error;
- nsurl *joined;
- hlcache_child_context child;
+ err = exec_src_script(c, node, mimetype, src);
+ dom_string_unref(src);
+ }
+ dom_string_unref(mimetype);
- nscript = html_process_new_script(c, HTML_STYLESHEET_EXTERNAL);
- if (nscript == NULL) {
- dom_string_unref(src);
- dom_string_unref(mimetype);
- goto html_process_script_no_memory;
- }
+ return err;
+}
- /* charset (encoding) */
+void html_free_scripts(html_content *html)
+{
+ unsigned int i;
- ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined);
- dom_string_unref(src);
- if (ns_error != NSERROR_OK) {
- dom_string_unref(mimetype);
- goto html_process_script_no_memory;
+ for (i = 0; i != html->scripts_count; i++) {
+ if (html->scripts[i].mimetype != NULL) {
+ dom_string_unref(html->scripts[i].mimetype);
}
- nscript->mimetype = mimetype; /* keep reference to mimetype */
-
- LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined)));
+ if ((html->scripts[i].type == HTML_SCRIPT_INLINE) &&
+ (html->scripts[i].data.string != NULL)) {
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
+ dom_string_unref(html->scripts[i].data.string);
- ns_error = hlcache_handle_retrieve(joined,
- 0,
- content_get_url(&c->base),
- NULL,
- html_convert_script_callback,
- c,
- &child,
- CONTENT_SCRIPT,
- &nscript->data.external);
+ } else if ((html->scripts[i].type == HTML_SCRIPT_SYNC) &&
+ (html->scripts[i].data.handle != NULL)) {
- nsurl_unref(joined);
+ hlcache_handle_release(html->scripts[i].data.handle);
- 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));
-
}
- html_scripts_exec(c);
-
- return DOM_HUBBUB_OK;
-
-html_process_script_no_memory:
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
- return DOM_HUBBUB_NOMEM;
+ free(html->scripts);
}
diff --git a/test/js/assorted.html b/test/js/assorted.html
new file mode 100644
index 0000000..bb3d477
--- /dev/null
+++ b/test/js/assorted.html
@@ -0,0 +1,34 @@
+<html>
+<head><title>moo</title></head>
+<body>
+<script>
+var tree = (this ===window)
+console.log(tree);
+var string = "50";
+
+console.log(string + 100); // 50100
+console.log(+string + 100); // 150
+
+string = parseInt(string, 10);
+console.log(string + 100); // 150
+var binary = parseInt("110010", 2);
+console.log(binary); // 50
+
+function doSomething(param) {
+ param = param.toUpperCase(); // param is now a local variable
+ console.log(param);
+}
+var string = "test";
+
+/* note that string will be passed in by reference */
+doSomething(string); // TEST
+console.log(string); // test
+
+document.write("<p>Hello World!<p>");
+</script>
+<p>one</p>
+<script>document.write("<scr"
+"ipt>document.write(\"Goodbye Cruel World\");</scri" +
"pt>");</script>
+</script>
+<p>hi</p>
+</body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
new file mode 100644
index 0000000..22f602e
--- /dev/null
+++ b/test/js/index.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<title>Script Tests</title>
+<link rel="stylesheet" type="text/css"
href="tst.css">
+</head>
+<body>
+<h1>Script Tests</h1>
+<ul>
+<li><a href="assorted.html">Assorted</a></li>
+<li><a href="inline-doc-write-simple.html">Simple docuemnt
write</a></li>
+<li><a href="inline-doc-write.html">Script within inline
script</a></li>
+<li><a href="sync-script.html">External syncronous script (with
css)</a></li>
+
+
+</ul>
+</body>
+</html>
diff --git a/test/js/inline-doc-write-simple.html b/test/js/inline-doc-write-simple.html
new file mode 100644
index 0000000..17ad8ee
--- /dev/null
+++ b/test/js/inline-doc-write-simple.html
@@ -0,0 +1,11 @@
+<html>
+<head><title>Inline Script Simple Document Write</title></head>
+<body>
+<h1>Inline Script Simple Document Write</h1>
+<p>Before</p>
+<script>
+document.write("<p>Hello World!<p>");
+</script>
+<p>Afterwards</p>
+</body>
+</html>
diff --git a/test/js/inline-doc-write.html b/test/js/inline-doc-write.html
new file mode 100644
index 0000000..290256d
--- /dev/null
+++ b/test/js/inline-doc-write.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>Inline Docuemnt Write Test</title>
+<link rel="stylesheet" type="text/css"
href="tst.css">
+</head>
+<body>
+<h1>Inline Document Write Test</h1>
+<p>Before</p>
+<script>document.write("<scr"
+"ipt>document.write(\"Goodbye Cruel World\");</scri" +
"pt>");</script>
+</script>
+<p>Afterwards</p>
+</body>
+</html>
diff --git a/test/js/sync-script.html b/test/js/sync-script.html
new file mode 100644
index 0000000..e234fb4
--- /dev/null
+++ b/test/js/sync-script.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>Sync script Test</title>
+<link rel="stylesheet" type="text/css"
href="tst.css">
+</head>
+<body>
+<h1>Sync script Test</h1>
+<p>Before</p>
+<script src="tst.js"></script>
+<p>Afterwards</p>
+</body>
+</html>
diff --git a/test/js/tst.css b/test/js/tst.css
new file mode 100644
index 0000000..6069f24
--- /dev/null
+++ b/test/js/tst.css
@@ -0,0 +1 @@
+h1 { color:red; }
diff --git a/test/js/tst.js b/test/js/tst.js
new file mode 100644
index 0000000..10e3b9c
--- /dev/null
+++ b/test/js/tst.js
@@ -0,0 +1 @@
+document.write("<script>document.write(\"Hello
World\");</script>");
diff --git a/utils/corestrings.c b/utils/corestrings.c
index 396e86e..af87ce2 100644
--- a/utils/corestrings.c
+++ b/utils/corestrings.c
@@ -112,6 +112,7 @@ lwc_string *corestring_lwc__top;
dom_string *corestring_dom_a;
dom_string *corestring_dom_align;
dom_string *corestring_dom_area;
+dom_string *corestring_dom_async;
dom_string *corestring_dom_background;
dom_string *corestring_dom_bgcolor;
dom_string *corestring_dom_border;
@@ -122,6 +123,7 @@ dom_string *corestring_dom_color;
dom_string *corestring_dom_cols;
dom_string *corestring_dom_content;
dom_string *corestring_dom_coords;
+dom_string *corestring_dom_defer;
dom_string *corestring_dom_height;
dom_string *corestring_dom_href;
dom_string *corestring_dom_hreflang;
@@ -258,6 +260,7 @@ void corestrings_fini(void)
CSS_DOM_STRING_UNREF(a);
CSS_DOM_STRING_UNREF(align);
CSS_DOM_STRING_UNREF(area);
+ CSS_DOM_STRING_UNREF(async);
CSS_DOM_STRING_UNREF(background);
CSS_DOM_STRING_UNREF(bgcolor);
CSS_DOM_STRING_UNREF(border);
@@ -268,6 +271,7 @@ void corestrings_fini(void)
CSS_DOM_STRING_UNREF(cols);
CSS_DOM_STRING_UNREF(content);
CSS_DOM_STRING_UNREF(coords);
+ CSS_DOM_STRING_UNREF(defer);
CSS_DOM_STRING_UNREF(height);
CSS_DOM_STRING_UNREF(href);
CSS_DOM_STRING_UNREF(hreflang);
@@ -431,6 +435,7 @@ nserror corestrings_init(void)
CSS_DOM_STRING_INTERN(a);
CSS_DOM_STRING_INTERN(align);
CSS_DOM_STRING_INTERN(area);
+ CSS_DOM_STRING_INTERN(async);
CSS_DOM_STRING_INTERN(background);
CSS_DOM_STRING_INTERN(bgcolor);
CSS_DOM_STRING_INTERN(border);
@@ -441,6 +446,7 @@ nserror corestrings_init(void)
CSS_DOM_STRING_INTERN(cols);
CSS_DOM_STRING_INTERN(content);
CSS_DOM_STRING_INTERN(coords);
+ CSS_DOM_STRING_INTERN(defer);
CSS_DOM_STRING_INTERN(height);
CSS_DOM_STRING_INTERN(href);
CSS_DOM_STRING_INTERN(hreflang);
diff --git a/utils/corestrings.h b/utils/corestrings.h
index a3bda16..1bcf8ae 100644
--- a/utils/corestrings.h
+++ b/utils/corestrings.h
@@ -118,6 +118,7 @@ struct dom_string;
extern struct dom_string *corestring_dom_a;
extern struct dom_string *corestring_dom_align;
extern struct dom_string *corestring_dom_area;
+extern struct dom_string *corestring_dom_async;
extern struct dom_string *corestring_dom_background;
extern struct dom_string *corestring_dom_bgcolor;
extern struct dom_string *corestring_dom_border;
@@ -128,6 +129,7 @@ extern struct dom_string *corestring_dom_color;
extern struct dom_string *corestring_dom_cols;
extern struct dom_string *corestring_dom_content;
extern struct dom_string *corestring_dom_coords;
+extern struct dom_string *corestring_dom_defer;
extern struct dom_string *corestring_dom_height;
extern struct dom_string *corestring_dom_href;
extern struct dom_string *corestring_dom_hreflang;
--
NetSurf Browser