diff options
Diffstat (limited to 'javascript/jsapi')
-rw-r--r-- | javascript/jsapi/Makefile | 53 | ||||
-rw-r--r-- | javascript/jsapi/jsapi.c | 613 | ||||
-rw-r--r-- | javascript/jsapi/jsapi.h | 396 |
3 files changed, 1062 insertions, 0 deletions
diff --git a/javascript/jsapi/Makefile b/javascript/jsapi/Makefile new file mode 100644 index 000000000..f684287ab --- /dev/null +++ b/javascript/jsapi/Makefile @@ -0,0 +1,53 @@ +# +# NetSurf javascript source file inclusion +# +# Included by javascript/Makefile +# + +# ---------------------------------------------------------------------------- +# JSAPI binding +# ---------------------------------------------------------------------------- + +D_JSAPI_BINDING:= + +JSAPI_BINDING_htmldocument := javascript/jsapi/htmldocument.bnd +JSAPI_BINDING_htmlelement := javascript/jsapi/htmlelement.bnd +JSAPI_BINDING_window := javascript/jsapi/window.bnd +JSAPI_BINDING_navigator := javascript/jsapi/navigator.bnd +JSAPI_BINDING_console := javascript/jsapi/console.bnd +JSAPI_BINDING_location := javascript/jsapi/location.bnd +JSAPI_BINDING_htmlcollection := javascript/jsapi/htmlcollection.bnd +JSAPI_BINDING_nodelist := javascript/jsapi/nodelist.bnd +JSAPI_BINDING_text := javascript/jsapi/text.bnd +JSAPI_BINDING_comment := javascript/jsapi/comment.bnd +JSAPI_BINDING_node := javascript/jsapi/node.bnd +JSAPI_BINDING_event := javascript/jsapi/event.bnd + +# 1: input binding file +# 2: source output file +# 3: header output file +# 4: binding name +define convert_jsapi_binding + +S_JAVASCRIPT_BINDING += $(2) +D_JSAPI_BINDING += $(patsubst %.c,%.d,$(2)) + +$(2): $(1) $(OBJROOT)/created + $$(VQ)echo " GENBIND: $(1)" + $(Q)nsgenbind -g -I javascript/WebIDL -d $(patsubst %.c,%.d,$(2)) -h $(3) -o $(2) $(1) + +$(3): $(2) + +endef + + +S_JSAPI := + +S_JAVASCRIPT += content.c jsapi/jsapi.c $(addprefix jsapi/,$(S_JSAPI)) + +$(eval $(foreach V,$(filter JSAPI_BINDING_%,$(.VARIABLES)),$(call convert_jsapi_binding,$($(V)),$(OBJROOT)/$(patsubst JSAPI_BINDING_%,%,$(V)).c,$(OBJROOT)/$(patsubst JSAPI_BINDING_%,%,$(V)).h,$(patsubst JSAPI_BINDING_%,%,$(V))_jsapi))) + +ifeq ($(filter $(MAKECMDGOALS),clean test coverage),) +-include $(D_JSAPI_BINDING) +endif + diff --git a/javascript/jsapi/jsapi.c b/javascript/jsapi/jsapi.c new file mode 100644 index 000000000..8724d9be8 --- /dev/null +++ b/javascript/jsapi/jsapi.c @@ -0,0 +1,613 @@ +/* + * 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; +} diff --git a/javascript/jsapi/jsapi.h b/javascript/jsapi/jsapi.h new file mode 100644 index 000000000..7ca8351d6 --- /dev/null +++ b/javascript/jsapi/jsapi.h @@ -0,0 +1,396 @@ +/* + * 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 + * spidermonkey jsapi compatability glue. + */ + +#ifndef _NETSURF_JAVASCRIPT_JSAPI_H_ +#define _NETSURF_JAVASCRIPT_JSAPI_H_ + +/* include the correct header */ +#ifdef WITH_MOZJS +#include "js/jsapi.h" +#else +#include "mozjs/jsapi.h" +#endif + +/* logging macros */ +#define JSLOG(args...) LOG(args) +#ifdef ENABLE_VERBOSE_JS_DEBUG +#define JSDBG(args...) LOG(args) +#else +#define JSDBG(args...) +#endif + +#if JS_VERSION < 180 + +/************************** Spidermonkey 1.7.0 **************************/ + +#include <string.h> + +#ifndef JSVERSION_LATEST +#define JSVERSION_LATEST JS_VERSION +#endif + +#ifndef JSOPTION_JIT +#define JSOPTION_JIT 0 +#endif + +/* *CAUTION* these native function macros introduce and use jsapi_this + * and jsapi_rval variables, native function code should not conflict + * with these + */ + +/* native function definition with five parameters */ +#define JSAPI_FUNC(name, cx, argc, vp) \ + jsapi_func_##name(cx, JSObject *jsapi_this, argc, vp, jsval *jsapi_rval) + +/* native function return value - No macro available */ +#define JSAPI_FUNC_RVAL(cx, vp) (jsapi_rval) + +/* native function return value setter - No macro available */ +#define JSAPI_FUNC_SET_RVAL(cx, vp, v) (*jsapi_rval = (v)) + +/* arguments */ +#define JSAPI_FUNC_ARGV(cx, vp) (vp) + +/* check if a jsval is an object */ +#define JSAPI_JSVAL_IS_OBJECT(v) JSVAL_IS_OBJECT(v) + +/* native function specifier with five parameters and no JS_FS macro */ +#define JSAPI_FS(name, nargs, flags) \ + { #name, jsapi_func_##name, nargs, flags, 0 } + +/* native function specifier list end */ +#define JSAPI_FS_END { NULL, NULL, 0, 0, 0 } + + + + +/* native proprty definition */ +#define JSAPI_PROP(name, cx, obj, vp) \ + jsapi_property_##name(cx, obj, jsval jsapi_id, vp) +#define JSAPI_STRICTPROP JSAPI_PROP + +/* native property return value */ +#define JSAPI_PROP_RVAL(cx, vp) (*(vp)) + +/* native property getter return value */ +#define JSAPI_PROP_SET_RVAL(cx, vp, v) (*(vp) = (v)) + +/* native property ID value as a jsval */ +#define JSAPI_PROP_IDVAL(cx, vp) (*(vp) = jsapi_id) + +/* native property specifier */ +#define JSAPI_PS(name, fnname, tinyid, flags) \ + { name , tinyid , flags , jsapi_property_##fnname##_get , jsapi_property_##fnname##_set } + +/* native property specifier with no setter */ +#define JSAPI_PS_RO(name, fnname, tinyid, flags) \ + { name , tinyid , flags | JSPROP_READONLY, jsapi_property_##fnname##_get , NULL } + +/* native property specifier list end */ +#define JSAPI_PS_END { NULL, 0, 0, NULL, NULL } + +#define JS_StrictPropertyStub JS_PropertyStub + + + + +/* The object instance in a native call */ +/* "this" JSObject getter */ +JSObject * js_ComputeThis(JSContext *cx, JSObject *thisp, void *argv); +#define JSAPI_THIS_OBJECT(cx, vp) \ + js_ComputeThis(cx, JSVAL_TO_OBJECT(vp[-1]), vp) + +static inline JSObject * +JS_NewCompartmentAndGlobalObject(JSContext *cx, + JSClass *jsclass, + JSPrincipals *principals) +{ + JSObject *global; + global = JS_NewObject(cx, jsclass, NULL, NULL); + if (global == NULL) { + return NULL; + } + return global; +} + + +#define JSString_to_char(injsstring, outchar, outlen) \ + outchar = JS_GetStringBytes(injsstring); \ + outlen = strlen(outchar) + +/* string type cast */ +#define JSAPI_STRING_TO_JSVAL(str) ((str == NULL)?JSVAL_NULL:STRING_TO_JSVAL(str)) + +#define JSAPI_CLASS_NO_INTERNAL_MEMBERS NULL + +/* Garbage Collector */ + +/* macros for GC marking */ +#define JSAPI_JSCLASS_MARK_IS_TRACE 0 + +#define JSAPI_JSCLASS_MARKOP(x) (x) + +#define JSAPI_MARKOP(name) uint32_t name(JSContext *cx, JSObject *obj, void *arg) + +#define JSAPI_MARKCX cx + +#define JSAPI_GCMARK(thing) JS_MarkGCThing(cx, thing, "object", arg) + +#define JSAPI_MARKOP_RETURN(value) return value + + +/* Macros for manipulating GC root */ +#define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddRoot(cx, obj) +#define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveRoot(cx, obj) + +#define JSAPI_ADD_VALUE_ROOT(cx, obj) JS_AddRoot(cx, obj) +#define JSAPI_REMOVE_VALUE_ROOT(cx, obj) JS_RemoveRoot(cx, obj) + +#elif JS_VERSION == 180 + +/************************** Spidermonkey 1.8.0 **************************/ + +#include <string.h> + +/* *CAUTION* these macros introduce and use jsapi_this and jsapi_rval + * parameters, native function code should not conflict with these + */ + +/* five parameter jsapi native call */ +#define JSAPI_FUNC(name, cx, argc, vp) \ + jsapi_func_##name(cx, JSObject *jsapi_this, argc, vp, jsval *jsapi_rval) + +/* five parameter function descriptor */ +#define JSAPI_FS(name, nargs, flags) \ + JS_FS(#name, jsapi_func_##name, nargs, flags, 0) + +/* function descriptor end */ +#define JSAPI_FS_END JS_FS_END + +/* return value */ +#define JSAPI_RVAL(cx, vp) JS_RVAL(cx, jsapi_rval) + +/* return value setter */ +#define JSAPI_FUNC_SET_RVAL(cx, vp, v) JS_SET_RVAL(cx, jsapi_rval, v) + +/* arguments */ +#define JSAPI_FUNC_ARGV(cx, vp) (vp) + +/* check if a jsval is an object */ +#define JSAPI_JSVAL_IS_OBJECT(v) JSVAL_IS_OBJECT(v) + +/* The object instance in a native call */ +#define JSAPI_THIS_OBJECT(cx,vp) jsapi_this + + + +/* proprty native calls */ +#define JSAPI_PROP(name, cx, obj, vp) \ + jsapi_property_##name(cx, obj, jsval jsapi_id, vp) +#define JSAPI_STRICTPROP JSAPI_PROP + +/* native property return value */ +#define JSAPI_PROP_RVAL JS_RVAL + +/* native property return value setter */ +#define JSAPI_PROP_SET_RVAL JS_SET_RVAL + +/* native property ID value as a jsval */ +#define JSAPI_PROP_IDVAL(cx, vp) (*(vp) = jsapi_id) + +/* property specifier */ +#define JSAPI_PS(name, fnname, tinyid, flags) \ + { name , tinyid , flags , jsapi_property_##fnname##_get , jsapi_property_##fnname##_set } + +#define JSAPI_PS_RO(name, fnname, tinyid, flags) \ + { name , tinyid , flags | JSPROP_READONLY, jsapi_property_##fnname##_get , NULL } + +#define JSAPI_PS_END { NULL, 0, 0, NULL, NULL } + + + + +static inline JSObject * +JS_NewCompartmentAndGlobalObject(JSContext *cx, + JSClass *jsclass, + JSPrincipals *principals) +{ + JSObject *global; + global = JS_NewObject(cx, jsclass, NULL, NULL); + if (global == NULL) { + return NULL; + } + return global; +} + +#define JS_StrictPropertyStub JS_PropertyStub + +#define JSString_to_char(injsstring, outchar, outlen) \ + outchar = JS_GetStringBytes(injsstring); \ + outlen = strlen(outchar) + +/* string type cast */ +#define JSAPI_STRING_TO_JSVAL(str) ((str == NULL)?JSVAL_NULL:STRING_TO_JSVAL(str)) + +#define JSAPI_CLASS_NO_INTERNAL_MEMBERS NULL + +/* Garbage Collector */ + +/* GC marking */ +#ifdef JSCLASS_MARK_IS_TRACE +/* mark function pointer requires casting */ +#define JSAPI_JSCLASS_MARK_IS_TRACE JSCLASS_MARK_IS_TRACE +#define JSAPI_JSCLASS_MARKOP(x) ((JSMarkOp)x) +#else +/* mark function pointer does not require casting */ +#define JSAPI_JSCLASS_MARK_IS_TRACE 0 +#define JSAPI_JSCLASS_MARKOP(x) (x) +#endif + +#define JSAPI_MARKOP(name) JSBool name(JSTracer *trc, JSObject *obj) + +#define JSAPI_MARKCX trc->context + +#define JSAPI_GCMARK(thing) JS_CallTracer(trc, thing, JSTRACE_OBJECT); + +#define JSAPI_MARKOP_RETURN(value) return value + +/* Macros for manipulating GC root */ +#define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddRoot(cx, obj) +#define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveRoot(cx, obj) + +#define JSAPI_ADD_VALUE_ROOT(cx, obj) JS_AddRoot(cx, obj) +#define JSAPI_REMOVE_VALUE_ROOT(cx, obj) JS_RemoveRoot(cx, obj) + + +#else /* #if JS_VERSION == 180 */ + +/************************** Spidermonkey 1.8.5 **************************/ + +/* three parameter jsapi native call */ +#define JSAPI_FUNC(name, cx, argc, vp) jsapi_func_##name(cx, argc, vp) + +/* three parameter function descriptor */ +#define JSAPI_FS(name, nargs, flags) \ + JS_FS(#name, jsapi_func_##name, nargs, flags) + +/* function descriptor end */ +#define JSAPI_FS_END JS_FS_END + +/* return value */ +#define JSAPI_RVAL JS_RVAL + +/* return value setter */ +#define JSAPI_FUNC_SET_RVAL JS_SET_RVAL + +/* arguments */ +#define JSAPI_FUNC_ARGV(cx, vp) JS_ARGV(cx,vp) + +/* check if a jsval is an object */ +#define JSAPI_JSVAL_IS_OBJECT(v) JSVAL_IS_OBJECT(v) +/* The docuemntation says this is obsolete and should be + * ((JSVAL_IS_NULL(v)) || (JSVAL_IS_PRIMITIVE(v))) + * which doesnt work + */ + + +/* The object instance in a native call */ +#define JSAPI_THIS_OBJECT(cx,vp) JS_THIS_OBJECT(cx,vp) + +/* proprty native calls */ +#define JSAPI_PROP(name, cx, obj, vp) \ + jsapi_property_##name(cx, obj, jsid jsapi_id, vp) +#define JSAPI_STRICTPROP(name, cx, obj, vp) \ + jsapi_property_##name(cx, obj, jsid jsapi_id, JSBool strict, vp) + +/* native property return value */ +#define JSAPI_PROP_RVAL JS_RVAL + +/* native property getter return value */ +#define JSAPI_PROP_SET_RVAL JS_SET_RVAL + +/* native property ID value as a jsval */ +#define JSAPI_PROP_IDVAL(cx, vp) JS_IdToValue(cx, jsapi_id, vp) + +/* property specifier */ +#define JSAPI_PS(name, fnname, tinyid, flags) { \ + name, \ + tinyid, \ + flags, \ + jsapi_property_##fnname##_get, \ + jsapi_property_##fnname##_set \ + } + +#define JSAPI_PS_RO(name, fnname, tinyid, flags) { \ + name, \ + tinyid, \ + flags | JSPROP_READONLY, \ + jsapi_property_##fnname##_get, \ + NULL \ + } + +#define JSAPI_PS_END { NULL, 0, 0, NULL, NULL } + + +#define JSString_to_char(injsstring, outchar, outlen) \ + outlen = JS_GetStringLength(injsstring); \ + outchar = alloca(sizeof(char)*(outlen+1)); \ + JS_EncodeStringToBuffer(injsstring, outchar, outlen); \ + outchar[outlen] = '\0' + +/* string type cast */ +#define JSAPI_STRING_TO_JSVAL(str) ((str == NULL)?JSVAL_NULL:STRING_TO_JSVAL(str)) + +#define JSAPI_CLASS_NO_INTERNAL_MEMBERS JSCLASS_NO_INTERNAL_MEMBERS + +/* GC marking */ +#ifdef JSCLASS_MARK_IS_TRACE +/* mark function pointer requires casting */ +#define JSAPI_JSCLASS_MARK_IS_TRACE JSCLASS_MARK_IS_TRACE +#define JSAPI_JSCLASS_MARKOP(x) ((JSMarkOp)x) +#else +/* mark function pointer does not require casting */ +#define JSAPI_JSCLASS_MARK_IS_TRACE 0 +#define JSAPI_JSCLASS_MARKOP(x) (x) +#endif + +#define JSAPI_MARKOP(name) void name(JSTracer *trc, JSObject *obj) + +#define JSAPI_MARKCX trc->context + +#define JSAPI_GCMARK(thing) JS_CallTracer(trc, thing, JSTRACE_OBJECT); + +#define JSAPI_MARKOP_RETURN(value) + + +/* Macros for manipulating GC root */ +#define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddObjectRoot(cx, obj) +#define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveObjectRoot(cx, obj) + +#define JSAPI_ADD_VALUE_ROOT(cx, val) JS_AddValueRoot(cx, val) +#define JSAPI_REMOVE_VALUE_ROOT(cx, val) JS_RemoveValueRoot(cx, val) + +#endif + +/************************** **************************/ + +#endif |