mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-26 08:19:55 +03:00
split out script handling from html
This commit is contained in:
parent
f2aa118025
commit
019be7616c
@ -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_CSS := css.c dump.c internal.c select.c utils.c
|
||||||
|
|
||||||
S_RENDER := box.c box_construct.c box_normalise.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 \
|
libdom_binding.c imagemap.c layout.c list.c search.c table.c \
|
||||||
textinput.c textplain.c
|
textinput.c textplain.c
|
||||||
|
|
||||||
|
309
render/html.c
309
render/html.c
@ -38,7 +38,6 @@
|
|||||||
#include "desktop/options.h"
|
#include "desktop/options.h"
|
||||||
#include "desktop/selection.h"
|
#include "desktop/selection.h"
|
||||||
#include "desktop/scrollbar.h"
|
#include "desktop/scrollbar.h"
|
||||||
#include "javascript/js.h"
|
|
||||||
#include "image/bitmap.h"
|
#include "image/bitmap.h"
|
||||||
#include "render/box.h"
|
#include "render/box.h"
|
||||||
#include "render/font.h"
|
#include "render/font.h"
|
||||||
@ -86,15 +85,15 @@ static dom_string *html_dom_string_head;
|
|||||||
static dom_string *html_dom_string_rel;
|
static dom_string *html_dom_string_rel;
|
||||||
dom_string *html_dom_string_href;
|
dom_string *html_dom_string_href;
|
||||||
static dom_string *html_dom_string_hreflang;
|
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_media;
|
||||||
static dom_string *html_dom_string_sizes;
|
static dom_string *html_dom_string_sizes;
|
||||||
static dom_string *html_dom_string_title;
|
static dom_string *html_dom_string_title;
|
||||||
static dom_string *html_dom_string_base;
|
static dom_string *html_dom_string_base;
|
||||||
static dom_string *html_dom_string_link;
|
static dom_string *html_dom_string_link;
|
||||||
static dom_string *html_dom_string_script;
|
static dom_string *html_dom_string_script;
|
||||||
static dom_string *html_dom_string_text_javascript;
|
dom_string *html_dom_string_text_javascript;
|
||||||
static dom_string *html_dom_string_src;
|
dom_string *html_dom_string_src;
|
||||||
dom_string *html_dom_string_target;
|
dom_string *html_dom_string_target;
|
||||||
static dom_string *html_dom_string__parent;
|
static dom_string *html_dom_string__parent;
|
||||||
static dom_string *html_dom_string__self;
|
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_poly;
|
||||||
dom_string *html_dom_string_polygon;
|
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)
|
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
|
* \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;
|
union content_msg_data msg_data;
|
||||||
dom_exception exc; /* returned by libdom functions */
|
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
|
static nserror
|
||||||
html_create_html_data(html_content *c, const http_parameter *params)
|
html_create_html_data(html_content *c, const http_parameter *params)
|
||||||
|
@ -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 browser_window *html_get_browser_window(struct content *c);
|
||||||
struct search_context *html_get_search(struct content *c);
|
struct search_context *html_get_search(struct content *c);
|
||||||
void html_set_search(struct content *c, struct search_context *s);
|
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 */
|
/* in render/html_redraw.c */
|
||||||
bool html_redraw(struct content *c, struct content_redraw_data *data,
|
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,
|
void html_overflow_scroll_callback(void *client_data,
|
||||||
struct scrollbar_msg_data *scrollbar_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 */
|
/* Useful dom_string pointers */
|
||||||
struct dom_string;
|
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_circle;
|
||||||
extern struct dom_string *html_dom_string_poly;
|
extern struct dom_string *html_dom_string_poly;
|
||||||
extern struct dom_string *html_dom_string_polygon;
|
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
|
#endif
|
||||||
|
|
||||||
|
339
render/html_script.c
Normal file
339
render/html_script.c
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* Content for text/html scripts (implementation).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user