diff options
-rw-r--r-- | javascript/jsapi.h | 1 | ||||
-rw-r--r-- | javascript/jsapi/document.c | 4 | ||||
-rw-r--r-- | javascript/jsapi/window.c | 12 | ||||
-rw-r--r-- | render/html.c | 159 | ||||
-rw-r--r-- | render/html.h | 13 | ||||
-rw-r--r-- | render/html_internal.h | 13 | ||||
-rw-r--r-- | render/html_script.c | 479 | ||||
-rw-r--r-- | test/js/assorted.html | 34 | ||||
-rw-r--r-- | test/js/index.html | 17 | ||||
-rw-r--r-- | test/js/inline-doc-write-simple.html | 11 | ||||
-rw-r--r-- | test/js/inline-doc-write.html | 13 | ||||
-rw-r--r-- | test/js/sync-script.html | 12 | ||||
-rw-r--r-- | test/js/tst.css | 1 | ||||
-rw-r--r-- | test/js/tst.js | 1 | ||||
-rw-r--r-- | utils/corestrings.c | 6 | ||||
-rw-r--r-- | utils/corestrings.h | 2 |
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; |