diff options
Diffstat (limited to 'javascript/jsapi/jsapi.c')
-rw-r--r-- | javascript/jsapi/jsapi.c | 613 |
1 files changed, 0 insertions, 613 deletions
diff --git a/javascript/jsapi/jsapi.c b/javascript/jsapi/jsapi.c deleted file mode 100644 index 8724d9be8..000000000 --- a/javascript/jsapi/jsapi.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * 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/>. - */ - -#include <unistd.h> -#include <signal.h> - -#include "javascript/jsapi.h" -#include "render/html_internal.h" -#include "content/content.h" -#include "javascript/content.h" -#include "javascript/js.h" - -#include "utils/log.h" - -#include "window.h" -#include "event.h" - -#define ENABLE_JS_HEARTBEAT 1 - -static JSRuntime *rt; /* global runtime */ - -void js_initialise(void) -{ - /* Create a JS runtime. */ - -#if JS_VERSION >= 180 - JS_SetCStringsAreUTF8(); /* we prefer our runtime to be utf-8 */ -#endif - - rt = JS_NewRuntime(8L * 1024L * 1024L); - JSLOG("New runtime handle %p", rt); - - if (rt != NULL) { - /* register script content handler */ - javascript_init(); - } -} - -void js_finalise(void) -{ - if (rt != NULL) { - JSLOG("destroying runtime handle %p", rt); - JS_DestroyRuntime(rt); - } - JS_ShutDown(); -} - -/* The error reporter callback. */ -static void -js_reportError(JSContext *cx, const char *message, JSErrorReport *report) -{ - JSLOG("%s:%u:%s", - report->filename ? report->filename : "<no filename>", - (unsigned int) report->lineno, - message); -} - -/* heartbeat routines */ -#ifndef ENABLE_JS_HEARTBEAT - -struct heartbeat; - -/* prepares a context with a heartbeat handler */ -static bool -setup_heartbeat(JSContext *cx, int timeout, jscallback *cb, void *cbctx) -{ - return true; -} - -/* enables the heartbeat on a context */ -static struct heartbeat *enable_heartbeat(JSContext *cx) -{ - return NULL; -} - -/* disables heartbeat on a context */ -static bool -disable_heartbeat(struct heartbeat *hb) -{ - return true; -} - -#else - -/* private context for heartbeats */ -struct jscontext_priv { - int timeout; - jscallback *cb; - void *cbctx; - - unsigned int branch_reset; /**< reset value for branch counter */ - unsigned int branch_count; /**< counter for branch callback */ - time_t last; /**< last time heartbeat happened */ - time_t end; /**< end time for the current script execution */ -}; - -/** execution heartbeat */ -static JSBool heartbeat_callback(JSContext *cx) -{ - struct jscontext_priv *priv = JS_GetContextPrivate(cx); - JSBool ret = JS_TRUE; - time_t now = time(NULL); - - /* dynamically update the branch times to ensure we do not get - * called back more than once a second - */ - if (now == priv->last) { - priv->branch_reset = priv->branch_reset * 2; - } - priv->last = now; - - JSLOG("Running heatbeat at %ld end %ld", (long)now, (long)priv->end); - - if ((priv->cb != NULL) && - (now > priv->end)) { - if (priv->cb(priv->cbctx) == false) { - ret = JS_FALSE; /* abort */ - } else { - priv->end = time(NULL) + priv->timeout; - } - } - - return ret; -} - -#if JS_VERSION >= 180 - -struct heartbeat { - JSContext *cx; - struct sigaction sact; /* signal handler action to restore */ - int alm; /* alarm value to restore */ -}; - -static struct heartbeat *cur_hb; - -static bool -setup_heartbeat(JSContext *cx, int timeout, jscallback *cb, void *cbctx) -{ - struct jscontext_priv *priv; - - if (timeout == 0) { - return true; - } - - priv = calloc(1, sizeof(*priv)); - if (priv == NULL) { - return false; - } - - priv->timeout = timeout; - priv->cb = cb; - priv->cbctx = cbctx; - - JS_SetContextPrivate(cx, priv); - - /* if heartbeat is enabled disable JIT or callbacks do not happen */ - JS_SetOptions(cx, JS_GetOptions(cx) & ~JSOPTION_JIT); - - JS_SetOperationCallback(cx, heartbeat_callback); - - return true; -} - -static void sig_alm_handler(int signum) -{ - JS_TriggerOperationCallback(cur_hb->cx); - alarm(1); - JSDBG("alarm signal handler for context %p", cur_hb->cx); -} - -static struct heartbeat *enable_heartbeat(JSContext *cx) -{ - struct jscontext_priv *priv = JS_GetContextPrivate(cx); - struct sigaction sact; - struct heartbeat *hb; - - if (priv == NULL) { - return NULL; - } - - priv->last = time(NULL); - priv->end = priv->last + priv->timeout; - - hb = malloc(sizeof(*hb)); - if (hb != NULL) { - sigemptyset(&sact.sa_mask); - sact.sa_flags = 0; - sact.sa_handler = sig_alm_handler; - if (sigaction(SIGALRM, &sact, &hb->sact) == 0) { - cur_hb = hb; - hb->cx = cx; - hb->alm = alarm(1); - } else { - free(hb); - hb = NULL; - LOG("Unable to set heartbeat"); - } - } - return hb; -} - -/** disable heartbeat - * - * /param hb heartbeat to disable may be NULL - * /return true on success. - */ -static bool -disable_heartbeat(struct heartbeat *hb) -{ - if (hb != NULL) { - sigaction(SIGALRM, &hb->sact, NULL); /* restore old handler */ - alarm(hb->alm); /* restore alarm signal */ - } - return true; -} - -#else - -/* need to setup callback to prevent long running scripts infinite - * hanging. - * - * old method is to use: - * JSBranchCallback JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb); - * which gets called a *lot* and should only do something every 5k calls - * The callback function - * JSBool (*JSBranchCallback)(JSContext *cx, JSScript *script); - * returns JS_TRUE to carry on and JS_FALSE to abort execution - * single thread of execution on the context - * documented in - * https://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JS_SetBranchCallback - * - */ - -#define INITIAL_BRANCH_RESET 5000 - -struct heartbeat; - -static JSBool branch_callback(JSContext *cx, JSScript *script) -{ - struct jscontext_priv *priv = JS_GetContextPrivate(cx); - JSBool ret = JS_TRUE; - - priv->branch_count--; - if (priv->branch_count == 0) { - priv->branch_count = priv->branch_reset; /* reset branch count */ - - ret = heartbeat_callback(cx); - } - return ret; -} - -static bool -setup_heartbeat(JSContext *cx, int timeout, jscallback *cb, void *cbctx) -{ - struct jscontext_priv *priv; - - if (timeout == 0) { - return true; - } - - priv = calloc(1, sizeof(*priv)); - if (priv == NULL) { - return false; - } - - priv->timeout = timeout; - priv->cb = cb; - priv->cbctx = cbctx; - - priv->branch_reset = INITIAL_BRANCH_RESET; - priv->branch_count = priv->branch_reset; - - JS_SetContextPrivate(cx, priv); - - JS_SetBranchCallback(cx, branch_callback); - - return true; -} - -static struct heartbeat *enable_heartbeat(JSContext *cx) -{ - struct jscontext_priv *priv = JS_GetContextPrivate(cx); - - if (priv != NULL) { - priv->last = time(NULL); - priv->end = priv->last + priv->timeout; - } - return NULL; -} - -static bool -disable_heartbeat(struct heartbeat *hb) -{ - return true; -} - -#endif - -#endif - -nserror js_newcontext(int timeout, jscallback *cb, void *cbctx, - jscontext **jsctx) -{ - JSContext *cx; - *jsctx = NULL; - - if (rt == NULL) { - return NSERROR_OK; - } - - cx = JS_NewContext(rt, 8192); - if (cx == NULL) { - return NSERROR_NOMEM; - } - - /* set options on context */ - JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_VAROBJFIX | JSOPTION_JIT); - - JS_SetVersion(cx, JSVERSION_LATEST); - JS_SetErrorReporter(cx, js_reportError); - - /* run a heartbeat */ - setup_heartbeat(cx, timeout, cb, cbctx); - - /*JS_SetGCZeal(cx, 2); */ - - JSLOG("New Context %p", cx); - - *jsctx = (jscontext *)cx; - return NSERROR_OK; -} - -void js_destroycontext(jscontext *ctx) -{ - JSContext *cx = (JSContext *)ctx; - struct jscontext_priv *priv; - - if (cx != NULL) { - JSLOG("Destroying Context %p", cx); - priv = JS_GetContextPrivate(cx); - - JS_DestroyContext(cx); - - free(priv); - } -} - - -/** Create new compartment to run scripts within - * - * This performs the following actions - * 1. constructs a new global object by initialising a window class - * 2. Instantiate the global a window object - */ -jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv) -{ - JSContext *cx = (JSContext *)ctx; - JSObject *window_proto; - JSObject *window; - - if (cx == NULL) { - return NULL; - } - - window_proto = jsapi_InitClass_Window(cx, NULL); - if (window_proto == NULL) { - JSLOG("Unable to initialise window class"); - return NULL; - } - - window = jsapi_new_Window(cx, window_proto, NULL, win_priv, doc_priv); - - return (jsobject *)window; -} - - - -bool js_exec(jscontext *ctx, const char *txt, size_t txtlen) -{ - JSContext *cx = (JSContext *)ctx; - jsval rval; - JSBool eval_res; - struct heartbeat *hb; - - /* JSLOG("%p \"%s\"",cx ,txt); */ - - if (ctx == NULL) { - return false; - } - - if (txt == NULL) { - return false; - } - - if (txtlen == 0) { - return false; - } - - hb = enable_heartbeat(cx); - - eval_res = JS_EvaluateScript(cx, - JS_GetGlobalObject(cx), - txt, txtlen, - "<head>", 0, &rval); - - disable_heartbeat(hb); - - if (eval_res == JS_TRUE) { - - return true; - } - - return false; -} - -dom_exception _dom_event_create(dom_document *doc, dom_event **evt); -#define dom_event_create(d, e) _dom_event_create((dom_document *)(d), (dom_event **) (e)) - -bool js_fire_event(jscontext *ctx, const char *type, dom_document *doc, dom_node *target) -{ - JSContext *cx = (JSContext *)ctx; - dom_node *node = target; - JSObject *jsevent; - jsval rval; - jsval argv[1]; - JSBool ret = JS_TRUE; - dom_exception exc; - dom_event *event; - dom_string *type_dom; - struct heartbeat *hb; - - if (cx == NULL) { - return false; - } - - if (node == NULL) { - /* deliver manufactured event to window */ - JSLOG("Dispatching event %s at window", type); - - /* create and initialise and event object */ - exc = dom_string_create((unsigned char*)type, - strlen(type), - &type_dom); - if (exc != DOM_NO_ERR) { - return false; - } - - exc = dom_event_create(doc, &event); - if (exc != DOM_NO_ERR) { - return false; - } - - exc = dom_event_init(event, type_dom, false, false); - dom_string_unref(type_dom); - if (exc != DOM_NO_ERR) { - return false; - } - - jsevent = jsapi_new_Event(cx, NULL, NULL, event); - if (jsevent == NULL) { - return false; - } - - hb = enable_heartbeat(cx); - - /* dispatch event at the window object */ - argv[0] = OBJECT_TO_JSVAL(jsevent); - - ret = JS_CallFunctionName(cx, - JS_GetGlobalObject(cx), - "dispatchEvent", - 1, - argv, - &rval); - - disable_heartbeat(hb); - - } else { - JSLOG("Dispatching event %s at %p", type, node); - - /* create and initialise and event object */ - exc = dom_string_create((unsigned char*)type, - strlen(type), - &type_dom); - if (exc != DOM_NO_ERR) { - return false; - } - - exc = dom_event_create(doc, &event); - if (exc != DOM_NO_ERR) { - return false; - } - - exc = dom_event_init(event, type_dom, true, true); - dom_string_unref(type_dom); - if (exc != DOM_NO_ERR) { - return false; - } - - dom_event_target_dispatch_event(node, event, &ret); - - } - - if (ret == JS_TRUE) { - return true; - } - return false; -} - -struct js_dom_event_private { - JSContext *cx; /* javascript context */ - jsval funcval; /* javascript function to call */ - struct dom_node *node; /* dom node event listening on */ - dom_string *type; /* event type */ - dom_event_listener *listener; /* the listener containing this */ -}; - -static void -js_dom_event_listener(struct dom_event *event, void *pw) -{ - struct js_dom_event_private *private = pw; - jsval event_argv[1]; - jsval event_rval; - JSObject *jsevent; - - JSLOG("WOOT dom event with %p", private); - - if (!JSVAL_IS_VOID(private->funcval)) { - jsevent = jsapi_new_Event(private->cx, NULL, NULL, event); - if (jsevent != NULL) { - - /* dispatch event at the window object */ - event_argv[0] = OBJECT_TO_JSVAL(jsevent); - - JS_CallFunctionValue(private->cx, - NULL, - private->funcval, - 1, - event_argv, - &event_rval); - } - } -} - -/* add a listener to a dom node - * - * 1. Create a dom_event_listener From a handle_event function pointer - * and a private word In a document context - * - * 2. Register for your events on a target (dom nodes are targets) - * dom_event_target_add_event_listener(node, evt_name, listener, - * capture_or_not) - * - */ - -bool -js_dom_event_add_listener(jscontext *ctx, - struct dom_document *document, - struct dom_node *node, - struct dom_string *event_type_dom, - void *js_funcval) -{ - JSContext *cx = (JSContext *)ctx; - dom_exception exc; - struct js_dom_event_private *private; - - private = malloc(sizeof(struct js_dom_event_private)); - if (private == NULL) { - return false; - } - - exc = dom_event_listener_create(document, - js_dom_event_listener, - private, - &private->listener); - if (exc != DOM_NO_ERR) { - return false; - } - - private->cx = cx; - private->funcval = *(jsval *)js_funcval; - private->node = node; - private->type = event_type_dom; - - JSLOG("adding %p to listener", private); - - JSAPI_ADD_VALUE_ROOT(cx, &private->funcval); - exc = dom_event_target_add_event_listener(private->node, - private->type, - private->listener, - true); - if (exc != DOM_NO_ERR) { - JSLOG("failed to add listener"); - JSAPI_REMOVE_VALUE_ROOT(cx, &private->funcval); - } - - return true; -} |