From 019be7616caf377f5b233c98206bc0c5d45a9793 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 13 Jul 2012 13:19:04 -0600 Subject: split out script handling from html --- Makefile.sources | 3 +- render/html.c | 309 +------------------------------------------- render/html_internal.h | 12 ++ render/html_script.c | 339 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 357 insertions(+), 306 deletions(-) create mode 100644 render/html_script.c diff --git a/Makefile.sources b/Makefile.sources index 3dcec40a3..f76ba0904 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -12,7 +12,8 @@ S_FETCHERS := curl.c data.c file.c about.c resource.c S_CSS := css.c dump.c internal.c select.c utils.c S_RENDER := box.c box_construct.c box_normalise.c \ - font.c form.c html.c html_interaction.c html_redraw.c \ + font.c form.c \ + html.c html_script.c html_interaction.c html_redraw.c \ libdom_binding.c imagemap.c layout.c list.c search.c table.c \ textinput.c textplain.c diff --git a/render/html.c b/render/html.c index 495cd7dab..bb6748a73 100644 --- a/render/html.c +++ b/render/html.c @@ -38,7 +38,6 @@ #include "desktop/options.h" #include "desktop/selection.h" #include "desktop/scrollbar.h" -#include "javascript/js.h" #include "image/bitmap.h" #include "render/box.h" #include "render/font.h" @@ -86,15 +85,15 @@ static dom_string *html_dom_string_head; static dom_string *html_dom_string_rel; dom_string *html_dom_string_href; static dom_string *html_dom_string_hreflang; -static dom_string *html_dom_string_type; +dom_string *html_dom_string_type; static dom_string *html_dom_string_media; static dom_string *html_dom_string_sizes; static dom_string *html_dom_string_title; static dom_string *html_dom_string_base; static dom_string *html_dom_string_link; static dom_string *html_dom_string_script; -static dom_string *html_dom_string_text_javascript; -static dom_string *html_dom_string_src; +dom_string *html_dom_string_text_javascript; +dom_string *html_dom_string_src; dom_string *html_dom_string_target; static dom_string *html_dom_string__parent; static dom_string *html_dom_string__self; @@ -117,107 +116,6 @@ dom_string *html_dom_string_circle; dom_string *html_dom_string_poly; dom_string *html_dom_string_polygon; -typedef bool (script_handler_t)(struct jscontext *jscontext, const char *data, size_t size) ; - - -static script_handler_t *select_script_handler(content_type ctype) -{ - if (ctype == CONTENT_JS) { - return js_exec; - } - return NULL; -} - - -/* attempt to progress script execution - * - * execute scripts using algorithm found in: - * http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element - * - */ -static bool html_scripts_exec(html_content *c) -{ - unsigned int i; - struct html_script *s; - script_handler_t *script_handler; - - if (c->jscontext == NULL) - return false; - - for (i = 0, s = c->scripts; i != c->scripts_count; i++, s++) { - if (s->already_started) { - continue; - } - - assert((s->type == HTML_SCRIPT_EXTERNAL) || - (s->type == HTML_SCRIPT_INTERNAL)); - - if (s->type == HTML_SCRIPT_EXTERNAL) { - /* ensure script content is present */ - if (s->data.external == NULL) - continue; - - /* ensure script content fetch status is not an error */ - if (content_get_status(s->data.external) == CONTENT_STATUS_ERROR) - continue; - - /* ensure script handler for content type */ - script_handler = select_script_handler(content_get_type(s->data.external)); - if (script_handler == NULL) - continue; /* unsupported type */ - - if (content_get_status(s->data.external) == CONTENT_STATUS_DONE) { - /* external script is now available */ - const char *data; - unsigned long size; - data = content_get_source_data(s->data.external, &size ); - script_handler(c->jscontext, data, size); - - s->already_started = true; - - } else { - /* script not yet available */ - - /* check if deferable or asynchronous */ - if (!s->defer && !s->async) { - break; - } - } - } - } - - return true; -} - -/* create new html script entry */ -static struct html_script * -html_process_new_script(html_content *c, enum html_script_type type) -{ - struct html_script *nscript; - /* add space for new script entry */ - nscript = realloc(c->scripts, - sizeof(struct html_script) * (c->scripts_count + 1)); - if (nscript == NULL) { - return NULL; - } - - c->scripts = nscript; - - /* increment script entry count */ - nscript = &c->scripts[c->scripts_count]; - c->scripts_count++; - - nscript->already_started = false; - nscript->parser_inserted = false; - nscript->force_async = true; - nscript->ready_exec = false; - nscript->async = false; - nscript->defer = false; - - nscript->type = type; - - return nscript; -} static void html_destroy_objects(html_content *html) { @@ -309,7 +207,7 @@ static void html_box_convert_done(html_content *c, bool success) * * \param c Content to convert */ -static void html_finish_conversion(html_content *c) +void html_finish_conversion(html_content *c) { union content_msg_data msg_data; dom_exception exc; /* returned by libdom functions */ @@ -400,205 +298,6 @@ static void html_finish_conversion(html_content *c) } -/** - * Callback for fetchcache() for linked stylesheets. - */ - -static nserror -html_convert_script_callback(hlcache_handle *script, - const hlcache_event *event, - void *pw) -{ - html_content *parent = pw; - unsigned int i; - struct html_script *s; - - /* Find script */ - for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) { - if (s->type == HTML_SCRIPT_EXTERNAL && - s->data.external == script) - break; - } - - assert(i != parent->scripts_count); - - switch (event->type) { - case CONTENT_MSG_LOADING: - break; - - case CONTENT_MSG_READY: - break; - - case CONTENT_MSG_DONE: - LOG(("script %d done '%s'", i, - nsurl_access(hlcache_handle_get_url(script)))); - parent->base.active--; - LOG(("%d fetches active", parent->base.active)); - - /* script finished loading so try and continue execution */ - html_scripts_exec(parent); - break; - - case CONTENT_MSG_ERROR: - LOG(("script %s failed: %s", - nsurl_access(hlcache_handle_get_url(script)), - event->data.error)); - hlcache_handle_release(script); - s->data.external = NULL; - parent->base.active--; - LOG(("%d fetches active", parent->base.active)); - content_add_error(&parent->base, "?", 0); - - /* script failed loading so try and continue execution */ - html_scripts_exec(parent); - - break; - - case CONTENT_MSG_STATUS: - html_set_status(parent, content_get_status_message(script)); - content_broadcast(&parent->base, CONTENT_MSG_STATUS, - event->data); - break; - - default: - assert(0); - } - - if (parent->base.active == 0) - html_finish_conversion(parent); - - return NSERROR_OK; -} - -/** process script node - * - * - */ -static dom_hubbub_error -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; - - /* ensure javascript context is available */ - if (c->jscontext == NULL) { - union content_msg_data msg_data; - - msg_data.jscontext = &c->jscontext; - content_broadcast(&c->base, CONTENT_MSG_GETCTX, msg_data); - LOG(("javascript context %p ", c->jscontext)); - if (c->jscontext == NULL) { - /* no context and it could not be created, abort */ - return DOM_HUBBUB_OK; - } - } - - LOG(("content %p parser %p node %p",c,c->parser_binding, node)); - - exc = dom_element_get_attribute(node, html_dom_string_type, &mimetype); - if (exc != DOM_NO_ERR || mimetype == NULL) { - mimetype = dom_string_ref(html_dom_string_text_javascript); - } - - exc = dom_element_get_attribute(node, html_dom_string_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)); - } - - - } else { - /* script with a src tag */ - nserror ns_error; - nsurl *joined; - hlcache_child_context child; - - - 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; - } - - /* charset (encoding) */ - - 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; - } - - nscript->mimetype = mimetype; /* keep reference to mimetype */ - - LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined))); - - child.charset = c->encoding; - child.quirks = c->base.quirks; - - ns_error = hlcache_handle_retrieve(joined, - 0, - content_get_url(&c->base), - NULL, - html_convert_script_callback, - c, - &child, - CONTENT_SCRIPT, - &nscript->data.external); - - nsurl_unref(joined); - - if (ns_error != NSERROR_OK) { - goto html_process_script_no_memory; - } - - c->base.active++; /* ensure base content knows the fetch is active */ - LOG(("%d fetches active", c->base.active)); - - } - 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; -} static nserror html_create_html_data(html_content *c, const http_parameter *params) diff --git a/render/html_internal.h b/render/html_internal.h index da3d686bd..acd7a2cdc 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -127,6 +127,12 @@ 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 + */ +void html_finish_conversion(html_content *c); /* in render/html_redraw.c */ bool html_redraw(struct content *c, struct content_redraw_data *data, @@ -140,6 +146,9 @@ void html_mouse_action(struct content *c, struct browser_window *bw, void html_overflow_scroll_callback(void *client_data, struct scrollbar_msg_data *scrollbar_data); +/* in render/html_script.c */ +dom_hubbub_error html_process_script(void *ctx, dom_node *node); + /* Useful dom_string pointers */ struct dom_string; @@ -159,6 +168,9 @@ extern struct dom_string *html_dom_string_coords; extern struct dom_string *html_dom_string_circle; extern struct dom_string *html_dom_string_poly; extern struct dom_string *html_dom_string_polygon; +extern struct dom_string *html_dom_string_text_javascript; +extern struct dom_string *html_dom_string_type; +extern struct dom_string *html_dom_string_src; #endif diff --git a/render/html_script.c b/render/html_script.c new file mode 100644 index 000000000..f925cfedf --- /dev/null +++ b/render/html_script.c @@ -0,0 +1,339 @@ +/* + * Copyright 2012 Vincent Sanders + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file + * Content for text/html scripts (implementation). + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "utils/config.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "javascript/js.h" +#include "content/content_protected.h" +#include "content/fetch.h" +#include "render/html_internal.h" + +typedef bool (script_handler_t)(struct jscontext *jscontext, const char *data, size_t size) ; + + +static script_handler_t *select_script_handler(content_type ctype) +{ + if (ctype == CONTENT_JS) { + return js_exec; + } + return NULL; +} + + +/* attempt to progress script execution + * + * execute scripts using algorithm found in: + * http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element + * + */ +static bool html_scripts_exec(html_content *c) +{ + unsigned int i; + struct html_script *s; + script_handler_t *script_handler; + + if (c->jscontext == NULL) + return false; + + for (i = 0, s = c->scripts; i != c->scripts_count; i++, s++) { + if (s->already_started) { + continue; + } + + assert((s->type == HTML_SCRIPT_EXTERNAL) || + (s->type == HTML_SCRIPT_INTERNAL)); + + if (s->type == HTML_SCRIPT_EXTERNAL) { + /* ensure script content is present */ + if (s->data.external == NULL) + continue; + + /* ensure script content fetch status is not an error */ + if (content_get_status(s->data.external) == CONTENT_STATUS_ERROR) + continue; + + /* ensure script handler for content type */ + script_handler = select_script_handler(content_get_type(s->data.external)); + if (script_handler == NULL) + continue; /* unsupported type */ + + if (content_get_status(s->data.external) == CONTENT_STATUS_DONE) { + /* external script is now available */ + const char *data; + unsigned long size; + data = content_get_source_data(s->data.external, &size ); + script_handler(c->jscontext, data, size); + + s->already_started = true; + + } else { + /* script not yet available */ + + /* check if deferable or asynchronous */ + if (!s->defer && !s->async) { + break; + } + } + } + } + + return true; +} + +/* create new html script entry */ +static struct html_script * +html_process_new_script(html_content *c, enum html_script_type type) +{ + struct html_script *nscript; + /* add space for new script entry */ + nscript = realloc(c->scripts, + sizeof(struct html_script) * (c->scripts_count + 1)); + if (nscript == NULL) { + return NULL; + } + + c->scripts = nscript; + + /* increment script entry count */ + nscript = &c->scripts[c->scripts_count]; + c->scripts_count++; + + nscript->already_started = false; + nscript->parser_inserted = false; + nscript->force_async = true; + nscript->ready_exec = false; + nscript->async = false; + nscript->defer = false; + + nscript->type = type; + + return nscript; +} + +/** + * Callback for fetchcache() for linked stylesheets. + */ + +static nserror +html_convert_script_callback(hlcache_handle *script, + const hlcache_event *event, + void *pw) +{ + html_content *parent = pw; + unsigned int i; + struct html_script *s; + + /* Find script */ + for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) { + if (s->type == HTML_SCRIPT_EXTERNAL && + s->data.external == script) + break; + } + + assert(i != parent->scripts_count); + + switch (event->type) { + case CONTENT_MSG_LOADING: + break; + + case CONTENT_MSG_READY: + break; + + case CONTENT_MSG_DONE: + LOG(("script %d done '%s'", i, + nsurl_access(hlcache_handle_get_url(script)))); + parent->base.active--; + LOG(("%d fetches active", parent->base.active)); + + /* script finished loading so try and continue execution */ + html_scripts_exec(parent); + break; + + case CONTENT_MSG_ERROR: + LOG(("script %s failed: %s", + nsurl_access(hlcache_handle_get_url(script)), + event->data.error)); + hlcache_handle_release(script); + s->data.external = NULL; + parent->base.active--; + LOG(("%d fetches active", parent->base.active)); + content_add_error(&parent->base, "?", 0); + + /* script failed loading so try and continue execution */ + html_scripts_exec(parent); + + break; + + case CONTENT_MSG_STATUS: + html_set_status(parent, content_get_status_message(script)); + content_broadcast(&parent->base, CONTENT_MSG_STATUS, + event->data); + break; + + default: + assert(0); + } + + if (parent->base.active == 0) + html_finish_conversion(parent); + + return NSERROR_OK; +} + +/** process script node + * + * + */ +dom_hubbub_error +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; + + /* ensure javascript context is available */ + if (c->jscontext == NULL) { + union content_msg_data msg_data; + + msg_data.jscontext = &c->jscontext; + content_broadcast(&c->base, CONTENT_MSG_GETCTX, msg_data); + LOG(("javascript context %p ", c->jscontext)); + if (c->jscontext == NULL) { + /* no context and it could not be created, abort */ + return DOM_HUBBUB_OK; + } + } + + LOG(("content %p parser %p node %p",c,c->parser_binding, node)); + + exc = dom_element_get_attribute(node, html_dom_string_type, &mimetype); + if (exc != DOM_NO_ERR || mimetype == NULL) { + mimetype = dom_string_ref(html_dom_string_text_javascript); + } + + exc = dom_element_get_attribute(node, html_dom_string_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)); + } + + + } else { + /* script with a src tag */ + nserror ns_error; + nsurl *joined; + hlcache_child_context child; + + + 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; + } + + /* charset (encoding) */ + + 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; + } + + nscript->mimetype = mimetype; /* keep reference to mimetype */ + + LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined))); + + child.charset = c->encoding; + child.quirks = c->base.quirks; + + ns_error = hlcache_handle_retrieve(joined, + 0, + content_get_url(&c->base), + NULL, + html_convert_script_callback, + c, + &child, + CONTENT_SCRIPT, + &nscript->data.external); + + nsurl_unref(joined); + + if (ns_error != NSERROR_OK) { + goto html_process_script_no_memory; + } + + c->base.active++; /* ensure base content knows the fetch is active */ + LOG(("%d fetches active", c->base.active)); + + } + 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; +} -- cgit v1.2.3