restructure javascript binding layout to be more explicit

fix html content so it correctly loads all the script tags


svn path=/trunk/netsurf/; revision=13968
This commit is contained in:
Vincent Sanders 2012-06-19 09:35:51 +00:00
parent a229a35767
commit 49effe103a
9 changed files with 597 additions and 244 deletions

View File

@ -29,9 +29,9 @@ S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \
# Javascript sources
ifeq ($(NETSURF_USE_JS),YES)
S_JAVASCRIPT += js.c global.c
S_JAVASCRIPT += jsapi.c jsapi/global.c
else
S_JAVASCRIPT += nojs.c
S_JAVASCRIPT += none.c
endif
# S_COMMON are sources common to all builds

View File

@ -70,7 +70,7 @@
int disc_cache_age; \
/** Whether to block advertisements */ \
bool block_ads; \
/** Disable website tracking, see \
/** Disable website tracking, see \
* http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas */ \
bool do_not_track; \
/** Minimum GIF animation delay */ \
@ -83,6 +83,8 @@
bool background_images; \
/** Whether to animate images */ \
bool animate_images; \
/** Whether to execute javascript */ \
bool enable_javascript; \
/** How many days to retain URL data for */ \
int expire_url; \
/** Default font family */ \
@ -262,7 +264,8 @@
.max_cached_fetch_handles = 6, \
.suppress_curl_debug = true, \
.target_blank = true, \
.button_2_tab = true
.button_2_tab = true, \
.enable_javascript = true
#define NSOPTION_MAIN_SYS_COLOUR_DEFAULTS \
.sys_colour_ActiveBorder = 0x00000000, \
@ -320,6 +323,7 @@
{ "foreground_images", OPTION_BOOL, &nsoptions.foreground_images }, \
{ "background_images", OPTION_BOOL, &nsoptions.background_images }, \
{ "animate_images", OPTION_BOOL, &nsoptions.animate_images }, \
{ "enable_javasctipt", OPTION_BOOL, &nsoptions.enable_javascript}, \
{ "expire_url", OPTION_INTEGER, &nsoptions.expire_url }, \
{ "font_default", OPTION_INTEGER, &nsoptions.font_default }, \
{ "ca_bundle", OPTION_STRING, &nsoptions.ca_bundle }, \

View File

@ -19,7 +19,7 @@
#include "mozjs/jsapi.h"
#include "content/content.h"
#include "javascript/global.h"
#include "javascript/jsapi.h"
#include "javascript/js.h"
#include "utils/log.h"
@ -50,7 +50,7 @@ void js_finalise(void)
/* The error reporter callback. */
static void js_reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
LOG(("%s:%u:%s\n",
LOG(("%s:%u:%s",
report->filename ? report->filename : "<no filename>",
(unsigned int) report->lineno,
message));
@ -131,7 +131,7 @@ jsobject *js_newcompartment(jscontext *ctx, struct content* c)
JS_SetContextPrivate(cx, c); /* private pointer to content */
js_new_globalfunc(cx, global);
jsapi_new_globalfunc(cx, global);
/* Populate the global object with the standard globals, like
Object and Array. */

View File

@ -17,12 +17,12 @@
*/
/** \file
* spidermonkey engine global functions.
* spidermonkey jsapi bindings.
*/
#ifndef _NETSURF_JAVASCRIPT_GLOBAL_H_
#define _NETSURF_JAVASCRIPT_GLOBAL_H_
#ifndef _NETSURF_JAVASCRIPT_JSAPI_H_
#define _NETSURF_JAVASCRIPT_JSAPI_H_
bool js_new_globalfunc(JSContext *cx, JSObject *global);
bool jsapi_new_globalfunc(JSContext *cx, JSObject *global);
#endif

View File

@ -19,7 +19,7 @@
#include "mozjs/jsapi.h"
#include "content/content.h"
#include "javascript/global.h"
#include "javascript/jsapi.h"
#include "utils/log.h"
static JSBool jsalert(JSContext *cx, uintN argc, jsval *vp)
@ -54,7 +54,7 @@ static JSFunctionSpec global_functions[] =
JS_FS_END
};
bool js_new_globalfunc(JSContext *cx, JSObject *global)
bool jsapi_new_globalfunc(JSContext *cx, JSObject *global)
{
return JS_DefineFunctions(cx, global, global_functions);
}

View File

@ -93,6 +93,7 @@ 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_src;
dom_string *html_dom_string_target;
static dom_string *html_dom_string__parent;
static dom_string *html_dom_string__self;
@ -147,6 +148,8 @@ html_create_html_data(html_content *c, const http_parameter *params)
c->box = NULL;
c->font_func = &nsfont;
c->scrollbar = NULL;
c->scripts_count = 0;
c->scripts = NULL;
c->jscontext = NULL;
if (lwc_intern_string("*", SLEN("*"), &c->universal) != lwc_error_ok) {
@ -346,39 +349,6 @@ encoding_change:
}
}
/** process script node */
static bool html_process_script(html_content *c, dom_node *node)
{
dom_exception exc; /* returned by libdom functions */
dom_string *script;
bool success = true;
/* 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) {
return false;
}
}
exc = dom_node_get_text_content(node, &script);
if ((exc != DOM_NO_ERR) || (script == NULL)) {
return false;
}
js_exec(c->jscontext,
dom_string_data(script),
dom_string_byte_length(script)) ;
dom_string_unref(script);
return success;
}
/** process link node */
static bool html_process_link(html_content *c, dom_node *node)
@ -581,10 +551,7 @@ static bool html_head(html_content *c, dom_node *head)
} else if (dom_string_caseless_isequal(node_name,
html_dom_string_link)) {
html_process_link(c, node);
} else if (dom_string_caseless_isequal(node_name,
html_dom_string_script)) {
html_process_script(c, node);
}
}
}
}
@ -958,6 +925,8 @@ html_object_callback(hlcache_handle *object,
case CONTENT_MSG_DONE:
c->base.active--;
LOG(("%d fetches active", c->base.active));
html_object_done(box, object, o->background);
if (c->base.status != CONTENT_STATUS_LOADING &&
@ -985,6 +954,7 @@ html_object_callback(hlcache_handle *object,
o->content = NULL;
c->base.active--;
LOG(("%d fetches active", c->base.active));
content_add_error(&c->base, "?", 0);
html_set_status(c, event->data.error);
@ -1107,8 +1077,10 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url)
if (object->content != NULL) {
/* remove existing object */
if (content_get_status(object->content) != CONTENT_STATUS_DONE)
if (content_get_status(object->content) != CONTENT_STATUS_DONE) {
c->base.active--;
LOG(("%d fetches active", c->base.active));
}
hlcache_handle_release(object->content);
object->content = NULL;
@ -1128,6 +1100,8 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url)
for (page = c; page != NULL; page = page->page) {
page->base.active++;
LOG(("%d fetches active", c->base.active));
page->base.status = CONTENT_STATUS_READY;
}
@ -1375,9 +1349,10 @@ html_convert_css_callback(hlcache_handle *css,
break;
case CONTENT_MSG_DONE:
LOG(("got stylesheet '%s'",
LOG(("done stylesheet slot %d '%s'", i,
nsurl_access(hlcache_handle_get_url(css))));
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
break;
case CONTENT_MSG_ERROR:
@ -1387,6 +1362,7 @@ html_convert_css_callback(hlcache_handle *css,
hlcache_handle_release(css);
s->data.external = NULL;
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
content_add_error(&parent->base, "?", 0);
break;
@ -1542,11 +1518,13 @@ html_process_style_element(html_content *c,
}
c->base.active++;
LOG(("%d fetches active", c->base.active));
/* Convert the content -- manually, as we want the result */
if (nscss_convert_css_data(sheet) != CSS_OK) {
/* conversion failed */
c->base.active--;
LOG(("%d fetches active", c->base.active));
nscss_destroy_css_data(sheet);
talloc_free(sheet);
sheet = NULL;
@ -1564,95 +1542,22 @@ no_memory:
return false;
}
/**
* Process inline stylesheets and fetch linked stylesheets.
/* depth-first walk the dom calling callback for each element
*
* Uses STYLE and LINK elements inside and outside HEAD
*
* \param c content structure
* \param html xml node of html element
* \return true on success, false if an error occurred
* @param root the dom node to use as the root of the tree walk
* @return true if all nodes were examined, false if the callback terminated
* the walk early.
*/
static bool html_find_stylesheets(html_content *c, dom_node *html)
static bool
html_treewalk_dom(dom_node *root,
bool (*callback)(dom_node *node, dom_string *name, void *ctx),
void *ctx)
{
content_type accept = CONTENT_CSS;
dom_node *node;
unsigned int i = STYLESHEET_START;
union content_msg_data msg_data;
struct html_stylesheet *stylesheets;
hlcache_child_context child;
nserror ns_error;
nsurl *joined;
bool result = true;;
child.charset = c->encoding;
child.quirks = c->base.quirks;
/* stylesheet 0 is the base style sheet,
* stylesheet 1 is the quirks mode style sheet,
* stylesheet 2 is the adblocking stylesheet,
* stylesheet 3 is the user stylesheet */
c->stylesheets = talloc_array(c, struct html_stylesheet,
STYLESHEET_START);
if (c->stylesheets == NULL)
goto no_memory;
c->stylesheets[STYLESHEET_BASE].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_BASE].data.external = NULL;
c->stylesheets[STYLESHEET_QUIRKS].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_QUIRKS].data.external = NULL;
c->stylesheets[STYLESHEET_ADBLOCK].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_ADBLOCK].data.external = NULL;
c->stylesheets[STYLESHEET_USER].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_USER].data.external = NULL;
c->stylesheet_count = STYLESHEET_START;
c->base.active = 0;
ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0,
content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child, accept,
&c->stylesheets[STYLESHEET_BASE].data.external);
if (ns_error != NSERROR_OK)
goto no_memory;
c->base.active++;
if (c->quirks == BINDING_QUIRKS_MODE_FULL) {
ns_error = hlcache_handle_retrieve(html_quirks_stylesheet_url,
0, content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child, accept,
&c->stylesheets[STYLESHEET_QUIRKS].
data.external);
if (ns_error != NSERROR_OK)
goto no_memory;
c->base.active++;
}
if (nsoption_bool(block_ads)) {
ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url,
0, content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child, accept,
&c->stylesheets[STYLESHEET_ADBLOCK].
data.external);
if (ns_error != NSERROR_OK)
goto no_memory;
c->base.active++;
}
ns_error = hlcache_handle_retrieve(html_user_stylesheet_url, 0,
content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child, accept,
&c->stylesheets[STYLESHEET_USER].data.external);
if (ns_error != NSERROR_OK)
goto no_memory;
c->base.active++;
/* depth-first search the tree for link elements */
node = dom_node_ref(html); /* tree root */
node = dom_node_ref(root); /* tree root */
while (node != NULL) {
dom_node *next = NULL;
@ -1723,125 +1628,524 @@ static bool html_find_stylesheets(html_content *c, dom_node *html)
assert(node != NULL);
exc = dom_node_get_node_type(node, &type);
if (exc != DOM_NO_ERR || type != DOM_ELEMENT_NODE)
if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE))
continue;
exc = dom_node_get_node_name(node, &name);
if (exc != DOM_NO_ERR)
continue;
if (strcmp(dom_string_data(name), "link") == 0) {
dom_string *rel, *type_attr, *media, *href;
result = callback(node, name, ctx);
dom_string_unref(name);
dom_string_unref(name);
/* rel=<space separated list, including 'stylesheet'> */
exc = dom_element_get_attribute(node,
html_dom_string_rel, &rel);
if (exc != DOM_NO_ERR || rel == NULL)
continue;
if (result == false) {
break; /* callback caused early termination */
}
}
return result;
}
if (strcasestr(dom_string_data(rel),
"stylesheet") == 0) {
dom_string_unref(rel);
continue;
} else if (strcasestr(dom_string_data(rel),
"alternate") != 0) {
/* Ignore alternate stylesheets */
dom_string_unref(rel);
continue;
}
dom_string_unref(rel);
/* 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;
/* type='text/css' or not present */
exc = dom_element_get_attribute(node,
html_dom_string_type, &type_attr);
if (exc == DOM_NO_ERR && type_attr != NULL) {
if (strcmp(dom_string_data(type_attr),
"text/css") != 0) {
dom_string_unref(type_attr);
continue;
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) {
if (s->data.external == NULL)
continue; /* script not present - skip */
if (content_get_status(s->data.external) == CONTENT_STATUS_ERROR)
continue; /* script content errored - skip */
if (content_get_status(s->data.external) == CONTENT_STATUS_DONE) {
/* external script is now available
* execute it and continue
*/
const char *data;
unsigned long size;
data = content_get_source_data(s->data.external, &size );
js_exec(c->jscontext, data, size);
s->already_started = true;
} else {
/* script not yet available */
if (!s->defer && !s->async) {
break; /* not deferable or async */
}
dom_string_unref(type_attr);
}
/* media contains 'screen' or 'all' or not present */
exc = dom_element_get_attribute(node,
html_dom_string_media, &media);
if (exc == DOM_NO_ERR && media != NULL) {
if (strcasestr(dom_string_data(media),
"screen") == NULL &&
strcasestr(
dom_string_data(media),
"all") == NULL) {
dom_string_unref(media);
continue;
}
dom_string_unref(media);
}
/* href='...' */
exc = dom_element_get_attribute(node,
html_dom_string_href, &href);
if (exc != DOM_NO_ERR || href == NULL)
continue;
/* TODO: only the first preferred stylesheets (ie.
* those with a title attribute) should be loaded
* (see HTML4 14.3) */
ns_error = nsurl_join(c->base_url,
dom_string_data(href), &joined);
if (ns_error != NSERROR_OK) {
dom_string_unref(href);
goto no_memory;
}
dom_string_unref(href);
LOG(("linked stylesheet %i '%s'", i,
nsurl_access(joined)));
/* start fetch */
stylesheets = talloc_realloc(c,
c->stylesheets,
struct html_stylesheet, i + 1);
if (stylesheets == NULL) {
nsurl_unref(joined);
goto no_memory;
}
c->stylesheets = stylesheets;
c->stylesheet_count++;
c->stylesheets[i].type = HTML_STYLESHEET_EXTERNAL;
ns_error = hlcache_handle_retrieve(joined, 0,
content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child,
accept,
&c->stylesheets[i].data.external);
nsurl_unref(joined);
if (ns_error != NSERROR_OK)
goto no_memory;
c->base.active++;
i++;
} else if (strcmp(dom_string_data(name), "style") == 0) {
dom_string_unref(name);
if (!html_process_style_element(c, &i, node))
return false;
} else {
dom_string_unref(name);
js_exec(c->jscontext,
dom_string_data(s->data.internal),
dom_string_byte_length(s->data.internal));
s->already_started = true;
}
}
assert(c->stylesheet_count == i);
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 sheet */
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 bool
html_process_script(dom_node *node, dom_string *name, void *ctx)
{
html_content *c = (html_content *)ctx;
dom_exception exc; /* returned by libdom functions */
dom_string *src, *script;
struct html_script *nscript;
union content_msg_data msg_data;
if (!dom_string_isequal(name, html_dom_string_script))
return true; /* was not a script tag, carry on the walk */
/* 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 false;
}
}
exc = dom_element_get_attribute(node, html_dom_string_src, &src);
if (exc != DOM_NO_ERR || src == NULL) {
/* 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 true; /* no contents, skip */
}
nscript = html_process_new_script(c, HTML_STYLESHEET_INTERNAL);
if (nscript == NULL) {
dom_string_unref(script);
goto html_process_script_no_memory;
}
nscript->data.internal = script;
/* type */
/* charset (encoding) */
} else {
/* script with a src tag */
nserror ns_error;
nsurl *joined;
hlcache_child_context child;
child.charset = c->encoding;
child.quirks = c->base.quirks;
nscript = html_process_new_script(c, HTML_STYLESHEET_EXTERNAL);
if (nscript == NULL) {
dom_string_unref(src);
goto html_process_script_no_memory;
}
/* type */
/* charset (encoding) */
ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined);
dom_string_unref(src);
if (ns_error != NSERROR_OK) {
goto html_process_script_no_memory;
}
LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined)));
ns_error = hlcache_handle_retrieve(joined,
0,
content_get_url(&c->base),
NULL,
html_convert_script_callback,
c,
&child,
CONTENT_ANY,
&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));
}
return true;
html_process_script_no_memory:
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return false; /* out of memory, abort walk */
}
/**
* Process inline script and fetch linked scripts.
*
*
*
* \param c content structure
* \param html dom node of html element
* \return true on success, false if an error occurred
*/
static bool html_find_scripts(html_content *c, dom_node *html)
{
return html_treewalk_dom(html, html_process_script, c);
}
struct find_stylesheet_ctx {
unsigned int count;
hlcache_child_context child;
html_content *c;
};
/** callback to process stylesheet elements
*/
static bool
html_process_stylesheet(dom_node *node, dom_string *name, void *vctx)
{
struct find_stylesheet_ctx *ctx = (struct find_stylesheet_ctx *)vctx;
dom_string *rel, *type_attr, *media, *href;
struct html_stylesheet *stylesheets;
nsurl *joined;
union content_msg_data msg_data;
dom_exception exc;
nserror ns_error;
/* deal with style nodes */
if (strcmp(dom_string_data(name), "style") == 0) {
if (!html_process_style_element(ctx->c, &ctx->count, node))
return false;
return true;
}
/* if it is not a link node skip it */
if (strcmp(dom_string_data(name), "link") != 0) {
return true;
}
/* rel=<space separated list, including 'stylesheet'> */
exc = dom_element_get_attribute(node,
html_dom_string_rel, &rel);
if (exc != DOM_NO_ERR || rel == NULL)
return true;
if (strcasestr(dom_string_data(rel), "stylesheet") == 0) {
dom_string_unref(rel);
return true;
} else if (strcasestr(dom_string_data(rel), "alternate") != 0) {
/* Ignore alternate stylesheets */
dom_string_unref(rel);
return true;
}
dom_string_unref(rel);
/* type='text/css' or not present */
exc = dom_element_get_attribute(node, html_dom_string_type, &type_attr);
if (exc == DOM_NO_ERR && type_attr != NULL) {
if (strcmp(dom_string_data(type_attr), "text/css") != 0) {
dom_string_unref(type_attr);
return true;
}
dom_string_unref(type_attr);
}
/* media contains 'screen' or 'all' or not present */
exc = dom_element_get_attribute(node, html_dom_string_media, &media);
if (exc == DOM_NO_ERR && media != NULL) {
if (strcasestr(dom_string_data(media), "screen") == NULL &&
strcasestr(dom_string_data(media), "all") == NULL) {
dom_string_unref(media);
return true;
}
dom_string_unref(media);
}
/* href='...' */
exc = dom_element_get_attribute(node, html_dom_string_href, &href);
if (exc != DOM_NO_ERR || href == NULL)
return true;
/* TODO: only the first preferred stylesheets (ie.
* those with a title attribute) should be loaded
* (see HTML4 14.3) */
ns_error = nsurl_join(ctx->c->base_url, dom_string_data(href), &joined);
if (ns_error != NSERROR_OK) {
dom_string_unref(href);
goto no_memory;
}
dom_string_unref(href);
LOG(("linked stylesheet %i '%s'", ctx->count, nsurl_access(joined)));
/* start fetch */
stylesheets = talloc_realloc(ctx->c,
ctx->c->stylesheets,
struct html_stylesheet,
ctx->count + 1);
if (stylesheets == NULL) {
nsurl_unref(joined);
goto no_memory;
}
ctx->c->stylesheets = stylesheets;
ctx->c->stylesheet_count++;
ctx->c->stylesheets[ctx->count].type = HTML_STYLESHEET_EXTERNAL;
ns_error = hlcache_handle_retrieve(joined,
0,
content_get_url(&ctx->c->base),
NULL,
html_convert_css_callback,
ctx->c,
&ctx->child,
CONTENT_CSS,
&ctx->c->stylesheets[ctx->count].data.external);
nsurl_unref(joined);
if (ns_error != NSERROR_OK)
goto no_memory;
ctx->c->base.active++;
LOG(("%d fetches active", ctx->c->base.active));
ctx->count++;
return true;
no_memory:
msg_data.error = messages_get("NoMemory");
content_broadcast(&ctx->c->base, CONTENT_MSG_ERROR, msg_data);
return false;
}
/**
* Process inline stylesheets and fetch linked stylesheets.
*
* Uses STYLE and LINK elements inside and outside HEAD
*
* \param c content structure
* \param html dom node of html element
* \return true on success, false if an error occurred
*/
static bool html_find_stylesheets(html_content *c, dom_node *html)
{
content_type accept = CONTENT_CSS;
union content_msg_data msg_data;
nserror ns_error;
bool result;
struct find_stylesheet_ctx ctx;
/* setup context */
ctx.c = c;
ctx.count = STYLESHEET_START;
ctx.child.charset = c->encoding;
ctx.child.quirks = c->base.quirks;
/* stylesheet 0 is the base style sheet,
* stylesheet 1 is the quirks mode style sheet,
* stylesheet 2 is the adblocking stylesheet,
* stylesheet 3 is the user stylesheet */
c->stylesheets = talloc_array(c, struct html_stylesheet,
STYLESHEET_START);
if (c->stylesheets == NULL)
goto html_find_stylesheets_no_memory;
c->stylesheets[STYLESHEET_BASE].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_BASE].data.external = NULL;
c->stylesheets[STYLESHEET_QUIRKS].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_QUIRKS].data.external = NULL;
c->stylesheets[STYLESHEET_ADBLOCK].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_ADBLOCK].data.external = NULL;
c->stylesheets[STYLESHEET_USER].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_USER].data.external = NULL;
c->stylesheet_count = STYLESHEET_START;
ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0,
content_get_url(&c->base), NULL,
html_convert_css_callback, c, &ctx.child, accept,
&c->stylesheets[STYLESHEET_BASE].data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
c->base.active++;
LOG(("%d fetches active", c->base.active));
if (c->quirks == BINDING_QUIRKS_MODE_FULL) {
ns_error = hlcache_handle_retrieve(html_quirks_stylesheet_url,
0, content_get_url(&c->base), NULL,
html_convert_css_callback, c, &ctx.child, accept,
&c->stylesheets[STYLESHEET_QUIRKS].
data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
c->base.active++;
LOG(("%d fetches active", c->base.active));
}
if (nsoption_bool(block_ads)) {
ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url,
0, content_get_url(&c->base), NULL,
html_convert_css_callback, c, &ctx.child, accept,
&c->stylesheets[STYLESHEET_ADBLOCK].
data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
c->base.active++;
LOG(("%d fetches active", c->base.active));
}
ns_error = hlcache_handle_retrieve(html_user_stylesheet_url, 0,
content_get_url(&c->base), NULL,
html_convert_css_callback, c, &ctx.child, accept,
&c->stylesheets[STYLESHEET_USER].data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
c->base.active++;
LOG(("%d fetches active", c->base.active));
result = html_treewalk_dom(html, html_process_stylesheet, &ctx);
assert(c->stylesheet_count == ctx.count);
return result;
html_find_stylesheets_no_memory:
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return false;
@ -2024,6 +2328,14 @@ static bool html_convert(struct content *c)
}
}
/* find script tags */
if (nsoption_bool(enable_javascript)) {
/* @todo this ought to be done during parse */
html_find_scripts(htmlc, html);
/* run as far as we can */
html_scripts_run(htmlc);
}
/* get stylesheets */
if (html_find_stylesheets(htmlc, html) == false)
return false;
@ -2091,6 +2403,7 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
c->num_objects++;
c->base.active++;
LOG(("%d fetches active", c->base.active));
return true;
}
@ -2099,12 +2412,6 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
/**
* Stop loading a CONTENT_HTML.
*/
@ -2141,6 +2448,8 @@ static void html_stop(struct content *c)
object->content = NULL;
c->active--;
LOG(("%d fetches active", c->active));
}
}
@ -2360,6 +2669,20 @@ static void html_destroy(struct content *c)
}
}
/* Free scripts */
for (i = 0; i != html->scripts_count; i++) {
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);
/* Free objects */
html_destroy_objects(html);
}
@ -3034,6 +3357,7 @@ static void html_fini(void)
HTML_DOM_STRING_UNREF(sizes);
HTML_DOM_STRING_UNREF(title);
HTML_DOM_STRING_UNREF(base);
HTML_DOM_STRING_UNREF(src);
HTML_DOM_STRING_UNREF(script);
HTML_DOM_STRING_UNREF(link);
HTML_DOM_STRING_UNREF(target);
@ -3164,6 +3488,7 @@ nserror html_init(void)
HTML_DOM_STRING_INTERN(base);
HTML_DOM_STRING_INTERN(link);
HTML_DOM_STRING_INTERN(script);
HTML_DOM_STRING_INTERN(src);
HTML_DOM_STRING_INTERN(target);
HTML_DOM_STRING_INTERN(_blank);
HTML_DOM_STRING_INTERN(_self);

View File

@ -58,6 +58,26 @@ struct html_stylesheet {
} data; /**< Sheet data */
};
/**
* Container for scripts used by an HTML document
*/
struct html_script {
/** Type of script */
enum html_script_type { HTML_SCRIPT_EXTERNAL, HTML_SCRIPT_INTERNAL } type;
union {
struct hlcache_handle *external;
struct dom_string *internal;
} data; /**< Script data */
struct dom_string *script_type;
struct dom_string *encoding;
bool already_started;
bool parser_inserted;
bool force_async;
bool ready_exec;
bool async;
bool defer;
};
/** An object (<img>, <object>, etc.) in a CONTENT_HTML document. */
struct content_html_object {

View File

@ -58,6 +58,13 @@ typedef struct html_content {
/** Font callback table */
const struct font_functions *font_func;
/** Number of entries in scripts */
unsigned int scripts_count;
/** Scripts */
struct html_script *scripts;
/** javascript context */
struct jscontext *jscontext;
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;
/** Stylesheets. Each may be NULL. */
@ -105,9 +112,6 @@ typedef struct html_content {
/** Context for free text search, or NULL if none */
struct search_context *search;
/** javascript context */
struct jscontext *jscontext;
} html_content;