summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--javascript/jsapi.h1
-rw-r--r--javascript/jsapi/document.c4
-rw-r--r--javascript/jsapi/window.c12
-rw-r--r--render/html.c159
-rw-r--r--render/html.h13
-rw-r--r--render/html_internal.h13
-rw-r--r--render/html_script.c479
-rw-r--r--test/js/assorted.html34
-rw-r--r--test/js/index.html17
-rw-r--r--test/js/inline-doc-write-simple.html11
-rw-r--r--test/js/inline-doc-write.html13
-rw-r--r--test/js/sync-script.html12
-rw-r--r--test/js/tst.css1
-rw-r--r--test/js/tst.js1
-rw-r--r--utils/corestrings.c6
-rw-r--r--utils/corestrings.h2
16 files changed, 599 insertions, 179 deletions
diff --git a/javascript/jsapi.h b/javascript/jsapi.h
index cf099ccf0..a44323f77 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 dfad551d6..bb5019c4b 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 06e6cdfe8..0b7673be3 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 759c24433..4263a064d 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 64548f810..dcbc1a3ba 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 ad032f720..0f20cc1c3 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 5fd8c8acc..f4d80ab54 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 000000000..bb3d477bc
--- /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 000000000..22f602e7f
--- /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 000000000..17ad8eede
--- /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 000000000..290256d20
--- /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 000000000..e234fb480
--- /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 000000000..6069f248a
--- /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 000000000..10e3b9c7f
--- /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 396e86ed0..af87ce206 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 a3bda1632..1bcf8aee7 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;