diff --git a/configure.ac b/configure.ac index 15b3f363..946984b5 100644 --- a/configure.ac +++ b/configure.ac @@ -608,21 +608,11 @@ case "$with_spidermonkey" in ;; esac -# The SpiderMonkey 1.8.5 standalone sources install mozjs185.pc, -# but the Debian libmozjs-dev package installs mozilla-js.pc. -# Check mozjs185 first, because it has the version number in the name -# and therefore is less likely to be a newer incompatible version. -# (This configure script rejects older incompatible versions -# but can let newer ones through.) -for package in mozjs185 mozilla-js; do +for package in mozjs-17.0; do if test -n "$CONFIG_SPIDERMONKEY"; then break else - AC_MSG_CHECKING([for SpiderMonkey (1.8.5 or later) in pkg-config $package]) - # In pkg-config 0.25, pkg-config --exists mozjs185 - # returns 0 (success) even if mozjs185 depends on - # nspr, which has not been installed. However, - # pkg-config --cflags mozjs185 returns 1 then. + AC_MSG_CHECKING([for SpiderMonkey (mozjs-17.0) in pkg-config $package]) if $PKG_CONFIG --cflags --libs $package > /dev/null 2>&AS_MESSAGE_LOG_FD; then SPIDERMONKEY_LIBS="$($PKG_CONFIG --libs $package)" SPIDERMONKEY_CFLAGS="$($PKG_CONFIG --cflags $package)" @@ -637,11 +627,7 @@ for package in mozjs185 mozilla-js; do # define XP_UNIX 1 #endif #include - #ifndef JS_VERSION - # error did not define JS_VERSION - #elif JS_VERSION < 185 - # error too old - #endif]], [])], + ]], [])], [CONFIG_SPIDERMONKEY=yes AC_MSG_RESULT([yes])], [# Leave CONFIG_SPIDERMONKEY blank, to continue the search. diff --git a/src/ecmascript/spidermonkey-shared.c b/src/ecmascript/spidermonkey-shared.c index bb7f3cae..61b22e69 100644 --- a/src/ecmascript/spidermonkey-shared.c +++ b/src/ecmascript/spidermonkey-shared.c @@ -110,7 +110,7 @@ spidermonkey_DefineFunctions(JSContext *cx, JSObject *obj, JSObject * spidermonkey_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JSClass *clasp, - JSNative constructor, uintN nargs, + JSNative constructor, unsigned int nargs, JSPropertySpec *ps, const spidermonkeyFunctionSpec *fs, JSPropertySpec *static_ps, diff --git a/src/ecmascript/spidermonkey-shared.h b/src/ecmascript/spidermonkey-shared.h index 8154ea8e..72ea1049 100644 --- a/src/ecmascript/spidermonkey-shared.h +++ b/src/ecmascript/spidermonkey-shared.h @@ -39,7 +39,7 @@ void spidermonkey_runtime_release(void); typedef struct spidermonkeyFunctionSpec { const char *name; JSNative call; - uint8 nargs; + uint8_t nargs; /* ELinks does not use "flags" and "extra" so omit them here. */ } spidermonkeyFunctionSpec; @@ -47,7 +47,7 @@ JSBool spidermonkey_DefineFunctions(JSContext *cx, JSObject *obj, const spidermonkeyFunctionSpec *fs); JSObject *spidermonkey_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JSClass *clasp, - JSNative constructor, uintN nargs, + JSNative constructor, unsigned int nargs, JSPropertySpec *ps, const spidermonkeyFunctionSpec *fs, JSPropertySpec *static_ps, @@ -87,4 +87,7 @@ jsid_to_string(JSContext *ctx, jsid *id) return jsval_to_string(ctx, &v); } +#define ELINKS_CAST_PROP_PARAMS JSObject *obj = *(hobj._); \ + jsval *vp = (hvp._); + #endif diff --git a/src/ecmascript/spidermonkey.c b/src/ecmascript/spidermonkey.c index bf96ecd7..2c8ba385 100644 --- a/src/ecmascript/spidermonkey.c +++ b/src/ecmascript/spidermonkey.c @@ -169,72 +169,91 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter) return NULL; interpreter->backend_data = ctx; JS_SetContextPrivate(ctx, interpreter); - JS_SetOptions(ctx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT); + JS_SetOptions(ctx, JSOPTION_VAROBJFIX | JSOPTION_METHODJIT); JS_SetVersion(ctx, JSVERSION_LATEST); JS_SetErrorReporter(ctx, error_reporter); #if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) JS_SetOperationCallback(ctx, heartbeat_callback); #endif - window_obj = JS_NewCompartmentAndGlobalObject(ctx, (JSClass *) &window_class, NULL); + window_obj = JS_NewGlobalObject(ctx, &window_class, NULL); + if (!window_obj) goto release_and_fail; - if (!JS_InitStandardClasses(ctx, window_obj)) goto release_and_fail; - if (!JS_DefineProperties(ctx, window_obj, (JSPropertySpec *) window_props)) + + if (!JS_InitStandardClasses(ctx, window_obj)) { goto release_and_fail; - if (!spidermonkey_DefineFunctions(ctx, window_obj, window_funcs)) + } + + if (!JS_DefineProperties(ctx, window_obj, window_props)) { goto release_and_fail; - if (!JS_SetPrivate(ctx, window_obj, interpreter->vs)) /* to @window_class */ + } + + if (!spidermonkey_DefineFunctions(ctx, window_obj, window_funcs)) { goto release_and_fail; + } + JS_SetPrivate(window_obj, interpreter->vs); /* to @window_class */ document_obj = spidermonkey_InitClass(ctx, window_obj, NULL, - (JSClass *) &document_class, NULL, 0, - (JSPropertySpec *) document_props, + &document_class, NULL, 0, + document_props, document_funcs, NULL, NULL); - if (!document_obj) goto release_and_fail; + if (!document_obj) { + goto release_and_fail; + } forms_obj = spidermonkey_InitClass(ctx, document_obj, NULL, - (JSClass *) &forms_class, NULL, 0, - (JSPropertySpec *) forms_props, + &forms_class, NULL, 0, + forms_props, forms_funcs, NULL, NULL); - if (!forms_obj) goto release_and_fail; + if (!forms_obj) { + goto release_and_fail; + } history_obj = spidermonkey_InitClass(ctx, window_obj, NULL, - (JSClass *) &history_class, NULL, 0, + &history_class, NULL, 0, (JSPropertySpec *) NULL, history_funcs, NULL, NULL); - if (!history_obj) goto release_and_fail; + if (!history_obj) { + goto release_and_fail; + } location_obj = spidermonkey_InitClass(ctx, window_obj, NULL, - (JSClass *) &location_class, NULL, 0, - (JSPropertySpec *) location_props, + &location_class, NULL, 0, + location_props, location_funcs, NULL, NULL); - if (!location_obj) goto release_and_fail; + if (!location_obj) { + goto release_and_fail; + } menubar_obj = JS_InitClass(ctx, window_obj, NULL, - (JSClass *) &menubar_class, NULL, 0, - (JSPropertySpec *) unibar_props, NULL, + &menubar_class, NULL, 0, + unibar_props, NULL, NULL, NULL); - if (!menubar_obj) goto release_and_fail; - if (!JS_SetPrivate(ctx, menubar_obj, "t")) /* to @menubar_class */ + if (!menubar_obj) { goto release_and_fail; + } + JS_SetPrivate(menubar_obj, "t"); /* to @menubar_class */ statusbar_obj = JS_InitClass(ctx, window_obj, NULL, - (JSClass *) &statusbar_class, NULL, 0, - (JSPropertySpec *) unibar_props, NULL, + &statusbar_class, NULL, 0, + unibar_props, NULL, NULL, NULL); - if (!statusbar_obj) goto release_and_fail; - if (!JS_SetPrivate(ctx, statusbar_obj, "s")) /* to @statusbar_class */ + if (!statusbar_obj) { goto release_and_fail; + } + JS_SetPrivate(statusbar_obj, "s"); /* to @statusbar_class */ navigator_obj = JS_InitClass(ctx, window_obj, NULL, - (JSClass *) &navigator_class, NULL, 0, - (JSPropertySpec *) navigator_props, NULL, + &navigator_class, NULL, 0, + navigator_props, NULL, NULL, NULL); - if (!navigator_obj) goto release_and_fail; + if (!navigator_obj) { + goto release_and_fail; + } return ctx; @@ -264,14 +283,18 @@ spidermonkey_eval(struct ecmascript_interpreter *interpreter, jsval rval; assert(interpreter); - if (!js_module_init_ok) return; + if (!js_module_init_ok) { + return; + } ctx = interpreter->backend_data; + #if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) interpreter->heartbeat = add_heartbeat(interpreter); #elif defined(HAVE_JS_SETBRANCHCALLBACK) setup_safeguard(interpreter, ctx); #endif interpreter->ret = ret; + JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx), code->source, code->length, "", 0, &rval); #if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) @@ -297,6 +320,7 @@ spidermonkey_eval_stringback(struct ecmascript_interpreter *interpreter, #elif defined(HAVE_JS_SETBRANCHCALLBACK) setup_safeguard(interpreter, ctx); #endif + ret = JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx), code->source, code->length, "", 0, &rval); #if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) @@ -327,7 +351,8 @@ spidermonkey_eval_boolback(struct ecmascript_interpreter *interpreter, if (!js_module_init_ok) return 0; ctx = interpreter->backend_data; interpreter->ret = NULL; - fun = JS_CompileFunction(ctx, NULL, "", 0, NULL, code->source, + + fun = JS_CompileFunction(ctx, JS_GetGlobalObject(ctx), "", 0, NULL, code->source, code->length, "", 0); if (!fun) return -1; @@ -337,7 +362,8 @@ spidermonkey_eval_boolback(struct ecmascript_interpreter *interpreter, #elif defined(HAVE_JS_SETBRANCHCALLBACK) setup_safeguard(interpreter, ctx); #endif - ret = JS_CallFunction(ctx, NULL, fun, 0, NULL, &rval); + ret = JS_CallFunction(ctx, JS_GetGlobalObject(ctx), fun, 0, NULL, &rval); + #if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) done_heartbeat(interpreter->heartbeat); #endif diff --git a/src/ecmascript/spidermonkey/document.c b/src/ecmascript/spidermonkey/document.c index b26c284e..96f583dc 100644 --- a/src/ecmascript/spidermonkey/document.c +++ b/src/ecmascript/spidermonkey/document.c @@ -47,149 +47,210 @@ #include "viewer/text/vs.h" -static JSBool document_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); -static JSBool document_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp); +static JSBool document_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); /* Each @document_class object must have a @window_class parent. */ -const JSClass document_class = { +JSClass document_class = { "document", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - document_get_property, document_set_property, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + document_get_property, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; -/* Tinyids of properties. Use negative values to distinguish these - * from array indexes (even though this object has no array elements). - * ECMAScript code should not use these directly as in document[-1]; - * future versions of ELinks may change the numbers. */ -enum document_prop { - JSP_DOC_LOC = -1, - JSP_DOC_REF = -2, - JSP_DOC_TITLE = -3, - JSP_DOC_URL = -4, -}; -/* "cookie" is special; it isn't a regular property but we channel it to the - * cookie-module. XXX: Would it work if "cookie" was defined in this array? */ -const JSPropertySpec document_props[] = { - { "location", JSP_DOC_LOC, JSPROP_ENUMERATE }, - { "referrer", JSP_DOC_REF, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "title", JSP_DOC_TITLE, JSPROP_ENUMERATE }, /* TODO: Charset? */ - { "url", JSP_DOC_URL, JSPROP_ENUMERATE }, - { NULL } -}; - -/* @document_class.getProperty */ +#ifdef CONFIG_COOKIES static JSBool -document_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +document_get_property_cookie(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct string *cookies; + JSClass* classPtr = JS_GetClass(obj); + + if (classPtr != &document_class) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + cookies = send_cookies_js(vs->uri); + + if (cookies) { + static unsigned char cookiestr[1024]; + + strncpy(cookiestr, cookies->source, 1024); + done_string(cookies); + string_to_jsval(ctx, vp, cookiestr); + } else { + string_to_jsval(ctx, vp, ""); + } + + return JS_TRUE; +} + +static JSBool +document_set_property_cookie(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &document_class, NULL)) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + set_cookie(vs->uri, jsval_to_string(ctx, vp)); + + return JS_TRUE; +} + +#endif + +static JSBool +document_get_property_location(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_win; /* instance of @window_class */ + JSClass* classPtr = JS_GetClass(obj); + + if (classPtr != &document_class) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + JS_GetProperty(ctx, parent_win, "location", vp); + + return JS_TRUE; +} + +static JSBool +document_set_property_location(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &document_class, NULL)) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + location_goto(doc_view, jsval_to_string(ctx, vp)); + + return JS_TRUE; +} + + +static JSBool +document_get_property_referrer(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; struct document_view *doc_view; struct document *document; struct session *ses; + JSClass* classPtr = JS_GetClass(obj); - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &document_class, NULL)) + if (classPtr != &document_class) return JS_FALSE; - parent_win = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; ses = doc_view->session; - if (JSID_IS_STRING(id)) { - struct form *form; - unsigned char *string = jsid_to_string(ctx, &id); - -#ifdef CONFIG_COOKIES - if (!strcmp(string, "cookie")) { - struct string *cookies = send_cookies_js(vs->uri); - - if (cookies) { - static unsigned char cookiestr[1024]; - - strncpy(cookiestr, cookies->source, 1024); - done_string(cookies); - - string_to_jsval(ctx, vp, cookiestr); - } else { - string_to_jsval(ctx, vp, ""); - } - return JS_TRUE; - } -#endif - foreach (form, document->forms) { - if (!form->name || c_strcasecmp(string, form->name)) - continue; - - object_to_jsval(ctx, vp, get_form_object(ctx, obj, find_form_view(doc_view, form))); - break; - } - return JS_TRUE; - } - - if (!JSID_IS_INT(id)) - return JS_TRUE; - - undef_to_jsval(ctx, vp); - - switch (JSID_TO_INT(id)) { - case JSP_DOC_LOC: - JS_GetProperty(ctx, parent_win, "location", vp); + switch (get_opt_int("protocol.http.referer.policy", NULL)) { + case REFERER_NONE: + /* oh well */ + undef_to_jsval(ctx, vp); break; - case JSP_DOC_REF: - switch (get_opt_int("protocol.http.referer.policy", NULL)) { - case REFERER_NONE: - /* oh well */ - undef_to_jsval(ctx, vp); - break; - case REFERER_FAKE: - string_to_jsval(ctx, vp, get_opt_str("protocol.http.referer.fake", NULL)); - break; + case REFERER_FAKE: + string_to_jsval(ctx, vp, get_opt_str("protocol.http.referer.fake", NULL)); + break; - case REFERER_TRUE: - /* XXX: Encode as in add_url_to_httset_prop_string(&prop, ) ? --pasky */ - if (ses->referrer) { - astring_to_jsval(ctx, vp, get_uri_string(ses->referrer, URI_HTTP_REFERRER)); - } - break; - - case REFERER_SAME_URL: - astring_to_jsval(ctx, vp, get_uri_string(document->uri, URI_HTTP_REFERRER)); - break; + case REFERER_TRUE: + /* XXX: Encode as in add_url_to_httset_prop_string(&prop, ) ? --pasky */ + if (ses->referrer) { + astring_to_jsval(ctx, vp, get_uri_string(ses->referrer, URI_HTTP_REFERRER)); } break; - case JSP_DOC_TITLE: - string_to_jsval(ctx, vp, document->title); - break; - case JSP_DOC_URL: - astring_to_jsval(ctx, vp, get_uri_string(document->uri, URI_ORIGINAL)); - break; - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case - * and leave *@vp unchanged. Do the same here. - * (Actually not quite the same, as we already used - * @undef_to_jsval.) */ + + case REFERER_SAME_URL: + astring_to_jsval(ctx, vp, get_uri_string(document->uri, URI_HTTP_REFERRER)); break; } return JS_TRUE; } -/* @document_class.setProperty */ + static JSBool -document_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +document_get_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + JSClass* classPtr = JS_GetClass(obj); + + if (classPtr != &document_class) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + string_to_jsval(ctx, vp, document->title); + + return JS_TRUE; +} + +static JSBool +document_set_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; struct document_view *doc_view; @@ -198,52 +259,134 @@ document_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsv /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &document_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &document_class, NULL)) return JS_FALSE; - parent_win = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; + mem_free_set(&document->title, stracpy(jsval_to_string(ctx, vp))); + print_screen_status(doc_view->session); - if (JSID_IS_STRING(id)) { + return JS_TRUE; +} + +static JSBool +document_get_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + JSClass* classPtr = JS_GetClass(obj); + + if (classPtr != &document_class) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + astring_to_jsval(ctx, vp, get_uri_string(document->uri, URI_ORIGINAL)); + + return JS_TRUE; +} + +static JSBool +document_set_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &document_class, NULL)) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + location_goto(doc_view, jsval_to_string(ctx, vp)); + + return JS_TRUE; +} + + +/* "cookie" is special; it isn't a regular property but we channel it to the + * cookie-module. XXX: Would it work if "cookie" was defined in this array? */ +JSPropertySpec document_props[] = { #ifdef CONFIG_COOKIES - if (!strcmp(jsid_to_string(ctx, &id), "cookie")) { - set_cookie(vs->uri, jsval_to_string(ctx, vp)); - /* Do NOT touch our .cookie property, evil - * SpiderMonkey!! */ - return JS_FALSE; - } + { "cookie", 0, JSPROP_ENUMERATE | JSPROP_SHARED, JSOP_WRAPPER(document_get_property_cookie), JSOP_WRAPPER(document_set_property_cookie) }, #endif - return JS_TRUE; - } + { "location", 0, JSPROP_ENUMERATE | JSPROP_SHARED, JSOP_WRAPPER(document_get_property_location), JSOP_WRAPPER(document_set_property_location) }, + { "referrer", 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_SHARED, JSOP_WRAPPER(document_get_property_referrer), JSOP_NULLWRAPPER }, + { "title", 0, JSPROP_ENUMERATE | JSPROP_SHARED, JSOP_WRAPPER(document_get_property_title), JSOP_WRAPPER(document_set_property_title) }, /* TODO: Charset? */ + { "url", 0, JSPROP_ENUMERATE | JSPROP_SHARED, JSOP_WRAPPER(document_get_property_url), JSOP_WRAPPER(document_set_property_url) }, + { NULL } +}; - if (!JSID_IS_INT(id)) - return JS_TRUE; - switch (JSID_TO_INT(id)) { - case JSP_DOC_TITLE: - mem_free_set(&document->title, stracpy(jsval_to_string(ctx, vp))); - print_screen_status(doc_view->session); - break; - case JSP_DOC_LOC: - case JSP_DOC_URL: - /* According to the specs this should be readonly but some - * broken sites still assign to it (i.e. - * http://www.e-handelsfonden.dk/validering.asp?URL=www.polyteknisk.dk). - * So emulate window.location. */ - location_goto(doc_view, jsval_to_string(ctx, vp)); +/* @document_class.getProperty */ +static JSBool +document_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form *form; + unsigned char *string; + + JSClass* classPtr = JS_GetClass(obj); + + if (classPtr != &document_class) + return JS_FALSE; + + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + string = jsid_to_string(ctx, &id); + + foreach (form, document->forms) { + if (!form->name || c_strcasecmp(string, form->name)) + continue; + + object_to_jsval(ctx, vp, get_form_object(ctx, obj, find_form_view(doc_view, form))); break; } return JS_TRUE; } -static JSBool document_write(JSContext *ctx, uintN argc, jsval *rval); -static JSBool document_writeln(JSContext *ctx, uintN argc, jsval *rval); +static JSBool document_write(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool document_writeln(JSContext *ctx, unsigned int argc, jsval *rval); const spidermonkeyFunctionSpec document_funcs[] = { { "write", document_write, 1 }, @@ -252,7 +395,7 @@ const spidermonkeyFunctionSpec document_funcs[] = { }; static JSBool -document_write_do(JSContext *ctx, uintN argc, jsval *rval, int newline) +document_write_do(JSContext *ctx, unsigned int argc, jsval *rval, int newline) { jsval val; struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx); @@ -290,7 +433,7 @@ document_write_do(JSContext *ctx, uintN argc, jsval *rval, int newline) /* @document_funcs{"write"} */ static JSBool -document_write(JSContext *ctx, uintN argc, jsval *rval) +document_write(JSContext *ctx, unsigned int argc, jsval *rval) { return document_write_do(ctx, argc, rval, 0); @@ -298,7 +441,7 @@ document_write(JSContext *ctx, uintN argc, jsval *rval) /* @document_funcs{"writeln"} */ static JSBool -document_writeln(JSContext *ctx, uintN argc, jsval *rval) +document_writeln(JSContext *ctx, unsigned int argc, jsval *rval) { return document_write_do(ctx, argc, rval, 1); } diff --git a/src/ecmascript/spidermonkey/document.h b/src/ecmascript/spidermonkey/document.h index 9cb80f31..d5d52f70 100644 --- a/src/ecmascript/spidermonkey/document.h +++ b/src/ecmascript/spidermonkey/document.h @@ -4,8 +4,8 @@ #include "ecmascript/spidermonkey/util.h" -extern const JSClass document_class; +extern JSClass document_class; extern const spidermonkeyFunctionSpec document_funcs[]; -extern const JSPropertySpec document_props[]; +extern JSPropertySpec document_props[]; #endif diff --git a/src/ecmascript/spidermonkey/form.c b/src/ecmascript/spidermonkey/form.c index fcbc78d7..736f75b4 100644 --- a/src/ecmascript/spidermonkey/form.c +++ b/src/ecmascript/spidermonkey/form.c @@ -47,7 +47,7 @@ #include "viewer/text/vs.h" -static const JSClass form_class; /* defined below */ +static JSClass form_class; /* defined below */ /* Accordingly to the JS specs, each input type should own object. That'd be a @@ -55,12 +55,12 @@ static const JSClass form_class; /* defined below */ * HTMLInputElement. The difference could be spotted only by some clever tricky * JS code, but I hope it doesn't matter anywhere. --pasky */ -static JSBool input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); -static JSBool input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp); -static void input_finalize(JSContext *ctx, JSObject *obj); +static JSBool input_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool input_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static void input_finalize(JSFreeOp *op, JSObject *obj); /* Each @input_class object must have a @form_class parent. */ -static const JSClass input_class = { +static JSClass input_class = { "input", /* here, we unleash ourselves */ JSCLASS_HAS_PRIVATE, /* struct form_state *, or NULL if detached */ JS_PropertyStub, JS_PropertyStub, @@ -91,67 +91,956 @@ enum input_prop { JSP_INPUT_VALUE = -16, }; -/* XXX: Some of those are marked readonly just because we can't change them - * safely now. Changing default* values would affect all open instances of the - * document, leading to a potential security risk. Changing size and type would - * require re-rendering the document (TODO), tabindex would require renumbering - * of all links and whatnot. --pasky */ -static const JSPropertySpec input_props[] = { - { "accessKey", JSP_INPUT_ACCESSKEY, JSPROP_ENUMERATE }, - { "alt", JSP_INPUT_ALT, JSPROP_ENUMERATE }, - { "checked", JSP_INPUT_CHECKED, JSPROP_ENUMERATE }, - { "defaultChecked",JSP_INPUT_DEFAULT_CHECKED,JSPROP_ENUMERATE }, - { "defaultValue",JSP_INPUT_DEFAULT_VALUE,JSPROP_ENUMERATE }, - { "disabled", JSP_INPUT_DISABLED, JSPROP_ENUMERATE }, - { "form", JSP_INPUT_FORM, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "maxLength", JSP_INPUT_MAX_LENGTH, JSPROP_ENUMERATE }, - { "name", JSP_INPUT_NAME, JSPROP_ENUMERATE }, - { "readonly", JSP_INPUT_READONLY, JSPROP_ENUMERATE }, - { "selectedIndex",JSP_INPUT_SELECTED_INDEX,JSPROP_ENUMERATE }, - { "size", JSP_INPUT_SIZE, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "src", JSP_INPUT_SRC, JSPROP_ENUMERATE }, - { "tabindex", JSP_INPUT_TABINDEX, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "type", JSP_INPUT_TYPE, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "value", JSP_INPUT_VALUE, JSPROP_ENUMERATE }, - { NULL } -}; - -static JSBool input_blur(JSContext *ctx, uintN argc, jsval *rval); -static JSBool input_click(JSContext *ctx, uintN argc, jsval *rval); -static JSBool input_focus(JSContext *ctx, uintN argc, jsval *rval); -static JSBool input_select(JSContext *ctx, uintN argc, jsval *rval); - -static const spidermonkeyFunctionSpec input_funcs[] = { - { "blur", input_blur, 0 }, - { "click", input_click, 0 }, - { "focus", input_focus, 0 }, - { "select", input_select, 0 }, - { NULL } -}; - static JSString *unicode_to_jsstring(JSContext *ctx, unicode_val_T u); static unicode_val_T jsval_to_accesskey(JSContext *ctx, jsval *vp); +static struct form_state *input_get_form_state(JSContext *ctx, JSObject *jsinput); -static struct form_state * -input_get_form_state(JSContext *ctx, JSObject *jsinput) +static JSBool +input_get_property_accessKey(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { - struct form_state *fs = JS_GetInstancePrivate(ctx, jsinput, - (JSClass *) &input_class, - NULL); + ELINKS_CAST_PROP_PARAMS - if (!fs) return NULL; /* detached */ + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + JSString *keystr; - assert(fs->ecmascript_obj == jsinput); - if_assert_failed return NULL; + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; - return fs; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + undef_to_jsval(ctx, vp); + + if (!link) return JS_TRUE; + + if (!link->accesskey) { + *vp = JS_GetEmptyStringValue(ctx); + } else { + keystr = unicode_to_jsstring(ctx, link->accesskey); + if (keystr) + *vp = STRING_TO_JSVAL(keystr); + else + return JS_FALSE; + } + return JS_TRUE; } -/* @input_class.getProperty */ static JSBool -input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +input_set_property_accessKey(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + unicode_val_T accesskey; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + accesskey = jsval_to_accesskey(ctx, vp); + + if (accesskey == UCS_NO_CHAR) + return JS_FALSE; + else if (link) + link->accesskey = accesskey; + + return JS_TRUE; +} + +static JSBool +input_get_property_alt(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + string_to_jsval(ctx, vp, fc->alt); + + return JS_TRUE; +} + +static JSBool +input_set_property_alt(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + mem_free_set(&fc->alt, stracpy(jsval_to_string(ctx, vp))); + + return JS_TRUE; +} + +static JSBool +input_get_property_checked(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct form_state *fs; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + + boolean_to_jsval(ctx, vp, fs->state); + + return JS_TRUE; +} + +static JSBool +input_set_property_checked(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (fc->type != FC_CHECKBOX && fc->type != FC_RADIO) + return JS_TRUE; + fs->state = jsval_to_boolean(ctx, vp); + + return JS_TRUE; +} + +static JSBool +input_get_property_defaultChecked(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + boolean_to_jsval(ctx, vp, fc->default_state); + + return JS_TRUE; +} + +static JSBool +input_get_property_defaultValue(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME (bug 805): convert from the charset of the document */ + string_to_jsval(ctx, vp, fc->default_value); + + return JS_TRUE; +} + +static JSBool +input_get_property_disabled(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + boolean_to_jsval(ctx, vp, fc->mode == FORM_MODE_DISABLED); + + return JS_TRUE; +} + +static JSBool +input_set_property_disabled(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + fc->mode = (jsval_to_boolean(ctx, vp) ? FORM_MODE_DISABLED + : fc->mode == FORM_MODE_READONLY ? FORM_MODE_READONLY + : FORM_MODE_NORMAL); + + return JS_TRUE; +} + +static JSBool +input_get_property_form(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + object_to_jsval(ctx, vp, parent_form); + + return JS_TRUE; +} + +static JSBool +input_get_property_maxLength(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + int_to_jsval(ctx, vp, fc->maxlength); + + return JS_TRUE; +} + +static JSBool +input_set_property_maxLength(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (!JS_ValueToInt32(ctx, *vp, &fc->maxlength)) + return JS_FALSE; + + return JS_TRUE; +} + +static JSBool +input_get_property_name(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + string_to_jsval(ctx, vp, fc->name); + + return JS_TRUE; +} + +/* @input_class.setProperty */ +static JSBool +input_set_property_name(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + mem_free_set(&fc->name, stracpy(jsval_to_string(ctx, vp))); + + return JS_TRUE; +} + +static JSBool +input_get_property_readonly(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + boolean_to_jsval(ctx, vp, fc->mode == FORM_MODE_READONLY); + + return JS_TRUE; +} + +/* @input_class.setProperty */ +static JSBool +input_set_property_readonly(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + fc->mode = (jsval_to_boolean(ctx, vp) ? FORM_MODE_READONLY + : fc->mode == FORM_MODE_DISABLED ? FORM_MODE_DISABLED + : FORM_MODE_NORMAL); + + return JS_TRUE; +} + +static JSBool +input_get_property_selectedIndex(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + undef_to_jsval(ctx, vp); + + if (fc->type == FC_SELECT) int_to_jsval(ctx, vp, fs->state); + + return JS_TRUE; +} + +/* @input_class.setProperty */ +static JSBool +input_set_property_selectedIndex(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (fc->type == FC_SELECT) { + int item; + + if (!JS_ValueToInt32(ctx, *vp, &item)) + return JS_FALSE; + + if (item >= 0 && item < fc->nvalues) { + fs->state = item; + mem_free_set(&fs->value, stracpy(fc->values[item])); + } + } + + return JS_TRUE; +} + +static JSBool +input_get_property_size(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + int_to_jsval(ctx, vp, fc->size); + + return JS_TRUE; +} + +static JSBool +input_get_property_src(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + JSObject *parent_form; /* instance of @form_class */ JSObject *parent_doc; /* instance of @document_class */ JSObject *parent_win; /* instance of @window_class */ @@ -166,20 +1055,377 @@ input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) return JS_FALSE; - parent_form = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL)); + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); if_assert_failed return JS_FALSE; - parent_doc = JS_GetParent(ctx, parent_form); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + undef_to_jsval(ctx, vp); + + if (link && link->where_img) + string_to_jsval(ctx, vp, link->where_img); + + return JS_TRUE; +} + +static JSBool +input_set_property_src(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + if (link) { + mem_free_set(&link->where_img, stracpy(jsval_to_string(ctx, vp))); + } + + return JS_TRUE; +} + +static JSBool +input_get_property_tabIndex(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + undef_to_jsval(ctx, vp); + + if (link) + /* FIXME: This is WRONG. --pasky */ + int_to_jsval(ctx, vp, link->number); + + return JS_TRUE; +} + +static JSBool +input_get_property_type(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + unsigned char *s = NULL; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + switch (fc->type) { + case FC_TEXT: s = "text"; break; + case FC_PASSWORD: s = "password"; break; + case FC_FILE: s = "file"; break; + case FC_CHECKBOX: s = "checkbox"; break; + case FC_RADIO: s = "radio"; break; + case FC_SUBMIT: s = "submit"; break; + case FC_IMAGE: s = "image"; break; + case FC_RESET: s = "reset"; break; + case FC_BUTTON: s = "button"; break; + case FC_HIDDEN: s = "hidden"; break; + case FC_SELECT: s = "select"; break; + default: INTERNAL("input_get_property() upon a non-input item."); break; + } + string_to_jsval(ctx, vp, s); + + return JS_TRUE; +} + +static JSBool +input_get_property_value(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct form_state *fs; + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + + string_to_jsval(ctx, vp, fs->value); + + return JS_TRUE; +} + +static JSBool +input_set_property_value(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, obj); + if (!fs) return JS_FALSE; /* detached */ + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (fc->type != FC_FILE) { + mem_free_set(&fs->value, stracpy(jsval_to_string(ctx, vp))); + if (fc->type == FC_TEXT || fc->type == FC_PASSWORD) + fs->state = strlen(fs->value); + } + + return JS_TRUE; +} + +/* XXX: Some of those are marked readonly just because we can't change them + * safely now. Changing default* values would affect all open instances of the + * document, leading to a potential security risk. Changing size and type would + * require re-rendering the document (TODO), tabindex would require renumbering + * of all links and whatnot. --pasky */ +static JSPropertySpec input_props[] = { + { "accessKey", 0, JSPROP_ENUMERATE | JSPROP_SHARED, JSOP_WRAPPER(input_get_property_accessKey), JSOP_WRAPPER(input_set_property_accessKey) }, + { "alt", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_alt), JSOP_WRAPPER(input_set_property_alt) }, + { "checked", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_checked), JSOP_WRAPPER(input_set_property_checked) }, + { "defaultChecked",0,JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY, JSOP_WRAPPER(input_get_property_defaultChecked), JSOP_NULLWRAPPER }, + { "defaultValue",0,JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY, JSOP_WRAPPER(input_get_property_defaultValue), JSOP_NULLWRAPPER }, + { "disabled", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_disabled), JSOP_WRAPPER(input_set_property_disabled) }, + { "form", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_form), JSOP_NULLWRAPPER }, + { "maxLength", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_maxLength), JSOP_WRAPPER(input_set_property_maxLength) }, + { "name", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_name), JSOP_WRAPPER(input_set_property_name) }, + { "readonly", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_readonly), JSOP_WRAPPER(input_set_property_readonly) }, + { "selectedIndex", 0,JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_selectedIndex), JSOP_WRAPPER(input_set_property_selectedIndex) }, + { "size", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_size), JSOP_NULLWRAPPER }, + { "src", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_src), JSOP_WRAPPER(input_set_property_src) }, + { "tabindex", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_tabIndex), JSOP_NULLWRAPPER }, + { "type", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_type), JSOP_NULLWRAPPER }, + { "value", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(input_get_property_value), JSOP_WRAPPER(input_set_property_value)}, + { NULL } +}; + +static JSBool input_blur(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool input_click(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool input_focus(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool input_select(JSContext *ctx, unsigned int argc, jsval *rval); + +static const spidermonkeyFunctionSpec input_funcs[] = { + { "blur", input_blur, 0 }, + { "click", input_click, 0 }, + { "focus", input_focus, 0 }, + { "select", input_select, 0 }, + { NULL } +}; + +static struct form_state * +input_get_form_state(JSContext *ctx, JSObject *jsinput) +{ + struct form_state *fs = JS_GetInstancePrivate(ctx, jsinput, + &input_class, + NULL); + + if (!fs) return NULL; /* detached */ + + assert(fs->ecmascript_obj == jsinput); + if_assert_failed return NULL; + + return fs; +} + +/* @input_class.getProperty */ +static JSBool +input_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) + return JS_FALSE; + + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; fs = input_get_form_state(ctx, obj); @@ -301,8 +1547,11 @@ input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) /* @input_class.setProperty */ static JSBool -input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +input_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + JSObject *parent_form; /* instance of @form_class */ JSObject *parent_doc; /* instance of @document_class */ JSObject *parent_win; /* instance of @window_class */ @@ -318,20 +1567,20 @@ input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &input_class, NULL)) return JS_FALSE; - parent_form = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL)); + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); if_assert_failed return JS_FALSE; - parent_doc = JS_GetParent(ctx, parent_form); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; fs = input_get_form_state(ctx, obj); @@ -422,7 +1671,7 @@ input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval /* @input_funcs{"blur"} */ static JSBool -input_blur(JSContext *ctx, uintN argc, jsval *rval) +input_blur(JSContext *ctx, unsigned int argc, jsval *rval) { /* We are a text-mode browser and there *always* has to be something * selected. So we do nothing for now. (That was easy.) */ @@ -431,7 +1680,7 @@ input_blur(JSContext *ctx, uintN argc, jsval *rval) /* @input_funcs{"click"} */ static JSBool -input_click(JSContext *ctx, uintN argc, jsval *rval) +input_click(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *parent_form; /* instance of @form_class */ @@ -447,19 +1696,19 @@ input_click(JSContext *ctx, uintN argc, jsval *rval) struct el_form_control *fc; int linknum; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, argv)) return JS_FALSE; - parent_form = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &input_class, argv)) return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); if_assert_failed return JS_FALSE; - parent_doc = JS_GetParent(ctx, parent_form); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; ses = doc_view->session; @@ -489,7 +1738,7 @@ input_click(JSContext *ctx, uintN argc, jsval *rval) /* @input_funcs{"focus"} */ static JSBool -input_focus(JSContext *ctx, uintN argc, jsval *rval) +input_focus(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *parent_form; /* instance of @form_class */ @@ -505,19 +1754,19 @@ input_focus(JSContext *ctx, uintN argc, jsval *rval) struct el_form_control *fc; int linknum; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, argv)) return JS_FALSE; - parent_form = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &input_class, argv)) return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); if_assert_failed return JS_FALSE; - parent_doc = JS_GetParent(ctx, parent_form); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; ses = doc_view->session; @@ -542,7 +1791,7 @@ input_focus(JSContext *ctx, uintN argc, jsval *rval) /* @input_funcs{"select"} */ static JSBool -input_select(JSContext *ctx, uintN argc, jsval *rval) +input_select(JSContext *ctx, unsigned int argc, jsval *rval) { /* We support no text selecting yet. So we do nothing for now. * (That was easy, too.) */ @@ -557,7 +1806,7 @@ get_input_object(JSContext *ctx, JSObject *jsform, struct form_state *fs) if (jsinput) { /* This assumes JS_GetInstancePrivate cannot GC. */ assert(JS_GetInstancePrivate(ctx, jsinput, - (JSClass *) &input_class, NULL) + &input_class, NULL) == fs); if_assert_failed return NULL; @@ -567,24 +1816,21 @@ get_input_object(JSContext *ctx, JSObject *jsform, struct form_state *fs) /* jsform ('form') is input's parent */ /* FIXME: That is NOT correct since the real containing element * should be its parent, but gimme DOM first. --pasky */ - jsinput = JS_NewObject(ctx, (JSClass *) &input_class, NULL, jsform); + jsinput = JS_NewObject(ctx, &input_class, NULL, jsform); if (!jsinput) return NULL; JS_DefineProperties(ctx, jsinput, (JSPropertySpec *) input_props); spidermonkey_DefineFunctions(ctx, jsinput, input_funcs); - if (!JS_SetPrivate(ctx, jsinput, fs)) /* to @input_class */ - return NULL; + JS_SetPrivate(jsinput, fs); /* to @input_class */ fs->ecmascript_obj = jsinput; return jsinput; } static void -input_finalize(JSContext *ctx, JSObject *jsinput) +input_finalize(JSFreeOp *op, JSObject *jsinput) { - struct form_state *fs = JS_GetInstancePrivate(ctx, jsinput, - (JSClass *) &input_class, - NULL); + struct form_state *fs = JS_GetPrivate(jsinput); if (fs) { /* If this assertion fails, leave fs->ecmascript_obj @@ -615,11 +1861,11 @@ spidermonkey_detach_form_state(struct form_state *fs) * easiest. */ assert(JS_GetInstancePrivate(spidermonkey_empty_context, jsinput, - (JSClass *) &input_class, NULL) + &input_class, NULL) == fs); if_assert_failed {} - JS_SetPrivate(spidermonkey_empty_context, jsinput, NULL); + JS_SetPrivate(jsinput, NULL); fs->ecmascript_obj = NULL; } } @@ -635,7 +1881,7 @@ spidermonkey_moved_form_state(struct form_state *fs) * other object whose struct form_state has also been * reallocated, and an assertion would fail in * input_finalize. */ - JS_SetPrivate(spidermonkey_empty_context, jsinput, fs); + JS_SetPrivate(jsinput, fs); } } @@ -670,21 +1916,21 @@ get_form_control_object(JSContext *ctx, JSObject *jsform, static struct form_view *form_get_form_view(JSContext *ctx, JSObject *jsform, jsval *argv); -static JSBool form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); +static JSBool form_elements_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); /* Each @form_elements_class object must have a @form_class parent. */ -static const JSClass form_elements_class = { +static JSClass form_elements_class = { "elements", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, form_elements_get_property, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; -static JSBool form_elements_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); -static JSBool form_elements_namedItem2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); -static JSBool form_elements_item(JSContext *ctx, uintN argc, jsval *rval); -static JSBool form_elements_namedItem(JSContext *ctx, uintN argc, jsval *rval); +static JSBool form_elements_item2(JSContext *ctx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval); +static JSBool form_elements_namedItem2(JSContext *ctx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval); +static JSBool form_elements_item(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool form_elements_namedItem(JSContext *ctx, unsigned int argc, jsval *rval); static const spidermonkeyFunctionSpec form_elements_funcs[] = { @@ -693,6 +1939,8 @@ static const spidermonkeyFunctionSpec form_elements_funcs[] = { { NULL } }; +static JSBool form_elements_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); + /* Tinyids of properties. Use negative values to distinguish these * from array indexes (elements[INT] for INT>=0 is equivalent to * elements.item(INT)). ECMAScript code should not use these directly @@ -700,15 +1948,17 @@ static const spidermonkeyFunctionSpec form_elements_funcs[] = { enum form_elements_prop { JSP_FORM_ELEMENTS_LENGTH = -1, }; -static const JSPropertySpec form_elements_props[] = { - { "length", JSP_FORM_ELEMENTS_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY}, +static JSPropertySpec form_elements_props[] = { + { "length", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(form_elements_get_property_length), JSOP_NULLWRAPPER}, { NULL } }; -/* @form_elements_class.getProperty */ static JSBool -form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +form_elements_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + jsval idval; JSObject *parent_form; /* instance of @form_class */ JSObject *parent_doc; /* instance of @document_class */ @@ -722,20 +1972,20 @@ form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_elements_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &form_elements_class, NULL)) return JS_FALSE; - parent_form = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL)); + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); if_assert_failed return JS_FALSE; - parent_doc = JS_GetParent(ctx, parent_form); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; form_view = form_get_form_view(ctx, parent_form, NULL); @@ -767,9 +2017,52 @@ form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) return JS_TRUE; } +static JSBool +form_elements_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_form; /* instance of @form_class */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_view *form_view; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_elements_class, NULL)) + return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed return JS_FALSE; + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + document = doc_view->document; + form_view = form_get_form_view(ctx, parent_form, NULL); + if (!form_view) return JS_FALSE; /* detached */ + form = find_form_by_form_view(document, form_view); + + int_to_jsval(ctx, vp, list_size(&form->items)); + + return JS_TRUE; +} + + /* @form_elements_funcs{"item"} */ static JSBool -form_elements_item(JSContext *ctx, uintN argc, jsval *rval) +form_elements_item(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val = JSVAL_VOID; JSObject *obj = JS_THIS_OBJECT(ctx, rval); @@ -781,7 +2074,7 @@ form_elements_item(JSContext *ctx, uintN argc, jsval *rval) } static JSBool -form_elements_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +form_elements_item2(JSContext *ctx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval) { JSObject *parent_form; /* instance of @form_class */ JSObject *parent_doc; /* instance of @document_class */ @@ -795,19 +2088,19 @@ form_elements_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsva int counter = -1; int index; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_elements_class, argv)) return JS_FALSE; - parent_form = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &form_elements_class, argv)) return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); if_assert_failed return JS_FALSE; - parent_doc = JS_GetParent(ctx, parent_form); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; form_view = form_get_form_view(ctx, parent_form, NULL); @@ -841,19 +2134,18 @@ form_elements_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsva /* @form_elements_funcs{"namedItem"} */ static JSBool -form_elements_namedItem(JSContext *ctx, uintN argc, jsval *rval) +form_elements_namedItem(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val = JSVAL_VOID; JSObject *obj = JS_THIS_OBJECT(ctx, rval); jsval *argv = JS_ARGV(ctx, rval); JSBool ret = form_elements_namedItem2(ctx, obj, argc, argv, &val); - JS_SET_RVAL(ctx, rval, val); return ret; } static JSBool -form_elements_namedItem2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +form_elements_namedItem2(JSContext *ctx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval) { JSObject *parent_form; /* instance of @form_class */ JSObject *parent_doc; /* instance of @document_class */ @@ -866,19 +2158,19 @@ form_elements_namedItem2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, struct el_form_control *fc; unsigned char *string; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_elements_class, argv)) return JS_FALSE; - parent_form = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &form_elements_class, argv)) return JS_FALSE; + parent_form = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); if_assert_failed return JS_FALSE; - parent_doc = JS_GetParent(ctx, parent_form); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(parent_form); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; form_view = form_get_form_view(ctx, parent_form, NULL); @@ -914,16 +2206,28 @@ form_elements_namedItem2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, -static JSBool form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); -static JSBool form_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp); -static void form_finalize(JSContext *ctx, JSObject *obj); +static JSBool form_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_get_property_action(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_set_property_action(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool form_get_property_elements(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_get_property_encoding(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_set_property_encoding(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool form_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_get_property_method(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_set_property_method(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool form_get_property_name(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_set_property_name(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool form_get_property_target(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool form_set_property_target(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); + +static void form_finalize(JSFreeOp *op, JSObject *obj); /* Each @form_class object must have a @document_class parent. */ -static const JSClass form_class = { +static JSClass form_class = { "form", JSCLASS_HAS_PRIVATE, /* struct form_view *, or NULL if detached */ JS_PropertyStub, JS_PropertyStub, - form_get_property, form_set_property, + form_get_property, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, form_finalize }; @@ -941,19 +2245,19 @@ enum form_prop { JSP_FORM_TARGET = -7, }; -static const JSPropertySpec form_props[] = { - { "action", JSP_FORM_ACTION, JSPROP_ENUMERATE }, - { "elements", JSP_FORM_ELEMENTS, JSPROP_ENUMERATE }, - { "encoding", JSP_FORM_ENCODING, JSPROP_ENUMERATE }, - { "length", JSP_FORM_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "method", JSP_FORM_METHOD, JSPROP_ENUMERATE }, - { "name", JSP_FORM_NAME, JSPROP_ENUMERATE }, - { "target", JSP_FORM_TARGET, JSPROP_ENUMERATE }, +static JSPropertySpec form_props[] = { + { "action", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(form_get_property_action), JSOP_WRAPPER(form_set_property_action) }, + { "elements", 0, JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY, JSOP_WRAPPER(form_get_property_elements), JSOP_NULLWRAPPER }, + { "encoding", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(form_get_property_encoding), JSOP_WRAPPER(form_set_property_encoding) }, + { "length", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(form_get_property_length), JSOP_NULLWRAPPER }, + { "method", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(form_get_property_method), JSOP_WRAPPER(form_set_property_method) }, + { "name", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(form_get_property_name), JSOP_WRAPPER(form_set_property_name) }, + { "target", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(form_get_property_target), JSOP_WRAPPER(form_set_property_target) }, { NULL } }; -static JSBool form_reset(JSContext *ctx, uintN argc, jsval *rval); -static JSBool form_submit(JSContext *ctx, uintN argc, jsval *rval); +static JSBool form_reset(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool form_submit(JSContext *ctx, unsigned int argc, jsval *rval); static const spidermonkeyFunctionSpec form_funcs[] = { { "reset", form_reset, 0 }, @@ -965,7 +2269,7 @@ static struct form_view * form_get_form_view(JSContext *ctx, JSObject *jsform, jsval *argv) { struct form_view *fv = JS_GetInstancePrivate(ctx, jsform, - (JSClass *) &form_class, + &form_class, argv); if (!fv) return NULL; /* detached */ @@ -978,8 +2282,10 @@ form_get_form_view(JSContext *ctx, JSObject *jsform, jsval *argv) /* @form_class.getProperty */ static JSBool -form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +form_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ JSObject *parent_doc; /* instance of @document_class */ JSObject *parent_win; /* instance of @window_class */ @@ -991,17 +2297,17 @@ form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) return JS_FALSE; - parent_doc = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; fv = form_get_form_view(ctx, obj, NULL); if (!fv) return JS_FALSE; /* detached */ @@ -1011,9 +2317,8 @@ form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) if (JSID_IS_STRING(id)) { struct el_form_control *fc; - unsigned char *string; + unsigned char *string = jsid_to_string(ctx, &id); - string = jsid_to_string(ctx, &id); foreach (fc, form->items) { JSObject *fcobj = NULL; struct form_state *fs; @@ -1047,7 +2352,7 @@ form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) case JSP_FORM_ELEMENTS: { /* jsform ('form') is form_elements' parent; who knows is that's correct */ - JSObject *jsform_elems = JS_NewObject(ctx, (JSClass *) &form_elements_class, NULL, obj); + JSObject *jsform_elems = JS_NewObject(ctx, &form_elements_class, NULL, obj); JS_DefineProperties(ctx, jsform_elems, (JSPropertySpec *) form_elements_props); spidermonkey_DefineFunctions(ctx, jsform_elems, @@ -1112,10 +2417,49 @@ form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) return JS_TRUE; } -/* @form_class.setProperty */ + static JSBool -form_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +form_get_property_action(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + string_to_jsval(ctx, vp, form->action); + + return JS_TRUE; +} + +static JSBool +form_set_property_action(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + JSObject *parent_doc; /* instance of @document_class */ JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; @@ -1127,17 +2471,17 @@ form_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval * /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) return JS_FALSE; - parent_doc = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; fv = form_get_form_view(ctx, obj, NULL); if (!fv) return JS_FALSE; /* detached */ @@ -1145,62 +2489,428 @@ form_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval * assert(form); - if (!JSID_IS_INT(id)) - return JS_TRUE; + string = stracpy(jsval_to_string(ctx, vp)); + if (form->action) { + ecmascript_set_action(&form->action, string); + } else { + mem_free_set(&form->action, string); + } - switch (JSID_TO_INT(id)) { - case JSP_FORM_ACTION: - string = stracpy(jsval_to_string(ctx, vp)); - if (form->action) { - ecmascript_set_action(&form->action, string); - } else { - mem_free_set(&form->action, string); - } + return JS_TRUE; +} + +static JSBool +form_get_property_elements(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ + struct form_view *fv; + JSObject *jsform_elems; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + + /* jsform ('form') is form_elements' parent; who knows is that's correct */ + jsform_elems = JS_NewObject(ctx, &form_elements_class, NULL, obj); + + JS_DefineProperties(ctx, jsform_elems, (JSPropertySpec *) form_elements_props); + spidermonkey_DefineFunctions(ctx, jsform_elems, + form_elements_funcs); + object_to_jsval(ctx, vp, jsform_elems); + /* SM will cache this property value for us so we create this + * just once per form. */ + + return JS_TRUE; +} + +static JSBool +form_get_property_encoding(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + + switch (form->method) { + case FORM_METHOD_GET: + case FORM_METHOD_POST: + string_to_jsval(ctx, vp, "application/x-www-form-urlencoded"); break; - - case JSP_FORM_ENCODING: - string = jsval_to_string(ctx, vp); - if (!c_strcasecmp(string, "application/x-www-form-urlencoded")) { - form->method = form->method == FORM_METHOD_GET ? FORM_METHOD_GET - : FORM_METHOD_POST; - } else if (!c_strcasecmp(string, "multipart/form-data")) { - form->method = FORM_METHOD_POST_MP; - } else if (!c_strcasecmp(string, "text/plain")) { - form->method = FORM_METHOD_POST_TEXT_PLAIN; - } + case FORM_METHOD_POST_MP: + string_to_jsval(ctx, vp, "multipart/form-data"); break; - - case JSP_FORM_METHOD: - string = jsval_to_string(ctx, vp); - if (!c_strcasecmp(string, "GET")) { - form->method = FORM_METHOD_GET; - } else if (!c_strcasecmp(string, "POST")) { - form->method = FORM_METHOD_POST; - } - break; - - case JSP_FORM_NAME: - mem_free_set(&form->name, stracpy(jsval_to_string(ctx, vp))); - break; - - case JSP_FORM_TARGET: - mem_free_set(&form->target, stracpy(jsval_to_string(ctx, vp))); - break; - - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case. - * Do the same here. */ + case FORM_METHOD_POST_TEXT_PLAIN: + string_to_jsval(ctx, vp, "text/plain"); break; } return JS_TRUE; } +/* @form_class.setProperty */ +static JSBool +form_set_property_encoding(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + unsigned char *string; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + + string = jsval_to_string(ctx, vp); + if (!c_strcasecmp(string, "application/x-www-form-urlencoded")) { + form->method = form->method == FORM_METHOD_GET ? FORM_METHOD_GET + : FORM_METHOD_POST; + } else if (!c_strcasecmp(string, "multipart/form-data")) { + form->method = FORM_METHOD_POST_MP; + } else if (!c_strcasecmp(string, "text/plain")) { + form->method = FORM_METHOD_POST_TEXT_PLAIN; + } + + return JS_TRUE; +} + +static JSBool +form_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + + int_to_jsval(ctx, vp, list_size(&form->items)); + + return JS_TRUE; +} + +static JSBool +form_get_property_method(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + + switch (form->method) { + case FORM_METHOD_GET: + string_to_jsval(ctx, vp, "GET"); + break; + + case FORM_METHOD_POST: + case FORM_METHOD_POST_MP: + case FORM_METHOD_POST_TEXT_PLAIN: + string_to_jsval(ctx, vp, "POST"); + break; + } + + return JS_TRUE; +} + +/* @form_class.setProperty */ +static JSBool +form_set_property_method(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + unsigned char *string; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + + string = jsval_to_string(ctx, vp); + if (!c_strcasecmp(string, "GET")) { + form->method = FORM_METHOD_GET; + } else if (!c_strcasecmp(string, "POST")) { + form->method = FORM_METHOD_POST; + } + + return JS_TRUE; +} + +static JSBool +form_get_property_name(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + + string_to_jsval(ctx, vp, form->name); + + return JS_TRUE; +} + +/* @form_class.setProperty */ +static JSBool +form_set_property_name(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + mem_free_set(&form->name, stracpy(jsval_to_string(ctx, vp))); + + return JS_TRUE; +} + +static JSBool +form_get_property_target(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */ + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + string_to_jsval(ctx, vp, form->target); + + return JS_TRUE; +} + +static JSBool +form_set_property_target(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + struct form_view *fv; + struct form *form; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &form_class, NULL)) + return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + fv = form_get_form_view(ctx, obj, NULL); + if (!fv) return JS_FALSE; /* detached */ + form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + mem_free_set(&form->target, stracpy(jsval_to_string(ctx, vp))); + + return JS_TRUE; +} + + /* @form_funcs{"reset"} */ static JSBool -form_reset(JSContext *ctx, uintN argc, jsval *rval) +form_reset(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *parent_doc; /* instance of @document_class */ @@ -1212,16 +2922,16 @@ form_reset(JSContext *ctx, uintN argc, jsval *rval) struct form_view *fv; struct form *form; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, argv)) return JS_FALSE; - parent_doc = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &form_class, argv)) return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; fv = form_get_form_view(ctx, obj, argv); if (!fv) return JS_FALSE; /* detached */ @@ -1240,7 +2950,7 @@ form_reset(JSContext *ctx, uintN argc, jsval *rval) /* @form_funcs{"submit"} */ static JSBool -form_submit(JSContext *ctx, uintN argc, jsval *rval) +form_submit(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *parent_doc; /* instance of @document_class */ @@ -1253,16 +2963,16 @@ form_submit(JSContext *ctx, uintN argc, jsval *rval) struct form_view *fv; struct form *form; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, argv)) return JS_FALSE; - parent_doc = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &form_class, argv)) return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; ses = doc_view->session; fv = form_get_form_view(ctx, obj, argv); @@ -1286,7 +2996,7 @@ get_form_object(JSContext *ctx, JSObject *jsdoc, struct form_view *fv) if (jsform) { /* This assumes JS_GetInstancePrivate cannot GC. */ assert(JS_GetInstancePrivate(ctx, jsform, - (JSClass *) &form_class, NULL) + &form_class, NULL) == fv); if_assert_failed return NULL; @@ -1296,24 +3006,22 @@ get_form_object(JSContext *ctx, JSObject *jsdoc, struct form_view *fv) /* jsdoc ('document') is fv's parent */ /* FIXME: That is NOT correct since the real containing element * should be its parent, but gimme DOM first. --pasky */ - jsform = JS_NewObject(ctx, (JSClass *) &form_class, NULL, jsdoc); + jsform = JS_NewObject(ctx, &form_class, NULL, jsdoc); if (jsform == NULL) return NULL; - JS_DefineProperties(ctx, jsform, (JSPropertySpec *) form_props); + JS_DefineProperties(ctx, jsform, form_props); spidermonkey_DefineFunctions(ctx, jsform, form_funcs); - if (!JS_SetPrivate(ctx, jsform, fv)) /* to @form_class */ - return NULL; + JS_SetPrivate(jsform, fv); /* to @form_class */ fv->ecmascript_obj = jsform; + return jsform; } static void -form_finalize(JSContext *ctx, JSObject *jsform) +form_finalize(JSFreeOp *op, JSObject *jsform) { - struct form_view *fv = JS_GetInstancePrivate(ctx, jsform, - (JSClass *) &form_class, - NULL); + struct form_view *fv = JS_GetPrivate(jsform); if (fv) { /* If this assertion fails, leave fv->ecmascript_obj @@ -1344,30 +3052,31 @@ spidermonkey_detach_form_view(struct form_view *fv) * easiest. */ assert(JS_GetInstancePrivate(spidermonkey_empty_context, jsform, - (JSClass *) &form_class, NULL) + &form_class, NULL) == fv); if_assert_failed {} - JS_SetPrivate(spidermonkey_empty_context, jsform, NULL); + JS_SetPrivate(jsform, NULL); fv->ecmascript_obj = NULL; } } -static JSBool forms_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); +static JSBool forms_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool forms_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); /* Each @forms_class object must have a @document_class parent. */ -const JSClass forms_class = { +JSClass forms_class = { "forms", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, forms_get_property, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; -static JSBool forms_item(JSContext *ctx, uintN argc, jsval *rval); -static JSBool forms_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); -static JSBool forms_namedItem(JSContext *ctx, uintN argc, jsval *rval); +static JSBool forms_item(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool forms_item2(JSContext *ctx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval); +static JSBool forms_namedItem(JSContext *ctx, unsigned int argc, jsval *rval); const spidermonkeyFunctionSpec forms_funcs[] = { { "item", forms_item, 1 }, @@ -1382,8 +3091,8 @@ const spidermonkeyFunctionSpec forms_funcs[] = { enum forms_prop { JSP_FORMS_LENGTH = -1, }; -const JSPropertySpec forms_props[] = { - { "length", JSP_FORMS_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY}, +JSPropertySpec forms_props[] = { + { "length", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(forms_get_property_length), JSOP_NULLWRAPPER}, { NULL } }; @@ -1412,9 +3121,66 @@ find_form_by_name(JSContext *ctx, JSObject *jsdoc, /* @forms_class.getProperty */ static JSBool -forms_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +forms_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + jsval idval; + JSObject *parent_doc; /* instance of @document_class */ + JSObject *parent_win; /* instance of @window_class */ + struct view_state *vs; + struct document_view *doc_view; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &forms_class, NULL)) + return JS_FALSE; + + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); + if_assert_failed return JS_FALSE; + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, parent_win, + &window_class, NULL); + doc_view = vs->doc_view; + + if (JSID_IS_STRING(id)) { + unsigned char *string = jsid_to_string(ctx, &id); + char *end; + + strtoll(string, &end, 10); + + if (end) { + /* When SMJS evaluates forms.namedItem("foo"), it first + * calls forms_get_property with id = JSString "namedItem" + * and *vp = JSObject JSFunction forms_namedItem. + * If we don't find a form whose name is id, + * we must leave *vp unchanged here, to avoid + * "TypeError: forms.namedItem is not a function". */ + JS_IdToValue(ctx, id, &idval); + find_form_by_name(ctx, parent_doc, doc_view, idval, vp); + + return JS_TRUE; + } + } + /* Array index. */ + JS_IdToValue(ctx, id, &idval); + forms_item2(ctx, obj, 1, &idval, vp); + + return JS_TRUE; +} + +static JSBool +forms_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + JSObject *parent_doc; /* instance of @document_class */ JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; @@ -1424,52 +3190,29 @@ forms_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &forms_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &forms_class, NULL)) return JS_FALSE; - parent_doc = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; document = doc_view->document; - - if (JSID_IS_STRING(id)) { - /* When SMJS evaluates forms.namedItem("foo"), it first - * calls forms_get_property with id = JSString "namedItem" - * and *vp = JSObject JSFunction forms_namedItem. - * If we don't find a form whose name is id, - * we must leave *vp unchanged here, to avoid - * "TypeError: forms.namedItem is not a function". */ - JS_IdToValue(ctx, id, &idval); - find_form_by_name(ctx, parent_doc, doc_view, idval, vp); - return JS_TRUE; - } - - if (!JSID_IS_INT(id)) - return JS_TRUE; - - switch (JSID_TO_INT(id)) { - case JSP_FORMS_LENGTH: - int_to_jsval(ctx, vp, list_size(&document->forms)); - break; - default: - /* Array index. */ - JS_IdToValue(ctx, id, &idval); - forms_item2(ctx, obj, 1, &idval, vp); - break; - } + int_to_jsval(ctx, vp, list_size(&document->forms)); return JS_TRUE; } /* @forms_funcs{"item"} */ static JSBool -forms_item(JSContext *ctx, uintN argc, jsval *rval) +forms_item(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val = JSVAL_VOID; JSObject *obj = JS_THIS_OBJECT(ctx, rval); @@ -1481,7 +3224,7 @@ forms_item(JSContext *ctx, uintN argc, jsval *rval) } static JSBool -forms_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +forms_item2(JSContext *ctx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval) { JSObject *parent_doc; /* instance of @document_class */ JSObject *parent_win; /* instance of @window_class */ @@ -1490,22 +3233,26 @@ forms_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) int counter = -1; int index; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &forms_class, argv)) return JS_FALSE; - parent_doc = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &forms_class, argv)) + return JS_FALSE; + + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); if (argc != 1) return JS_TRUE; if (!JS_ValueToInt32(ctx, argv[0], &index)) return JS_FALSE; + undef_to_jsval(ctx, rval); foreach (fv, vs->forms) { @@ -1521,7 +3268,7 @@ forms_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) /* @forms_funcs{"namedItem"} */ static JSBool -forms_namedItem(JSContext *ctx, uintN argc, jsval *rval) +forms_namedItem(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *parent_doc; /* instance of @document_class */ @@ -1531,16 +3278,16 @@ forms_namedItem(JSContext *ctx, uintN argc, jsval *rval) struct view_state *vs; struct document_view *doc_view; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &forms_class, argv)) return JS_FALSE; - parent_doc = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL)); + if (!JS_InstanceOf(ctx, obj, &forms_class, argv)) return JS_FALSE; + parent_doc = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_doc, &document_class, NULL)); if_assert_failed return JS_FALSE; - parent_win = JS_GetParent(ctx, parent_doc); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(parent_doc); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; if (argc != 1) diff --git a/src/ecmascript/spidermonkey/form.h b/src/ecmascript/spidermonkey/form.h index eaa4d391..45917ff8 100644 --- a/src/ecmascript/spidermonkey/form.h +++ b/src/ecmascript/spidermonkey/form.h @@ -6,9 +6,9 @@ struct form_view; -extern const JSClass forms_class; +extern JSClass forms_class; extern const spidermonkeyFunctionSpec forms_funcs[]; -extern const JSPropertySpec forms_props[]; +extern JSPropertySpec forms_props[]; JSObject *get_form_object(JSContext *ctx, JSObject *jsdoc, struct form_view *fv); diff --git a/src/ecmascript/spidermonkey/heartbeat.c b/src/ecmascript/spidermonkey/heartbeat.c index 4eaed4db..5eb2830b 100644 --- a/src/ecmascript/spidermonkey/heartbeat.c +++ b/src/ecmascript/spidermonkey/heartbeat.c @@ -36,7 +36,7 @@ static struct itimerval heartbeat_timer = { { 1, 0 }, { 1, 0 } }; JSBool heartbeat_callback(JSContext *ctx) { - return JS_FALSE; + return JS_FALSE; } /* Callback for SIGVTALRM. Go through all heartbeats, decrease each @@ -45,31 +45,28 @@ heartbeat_callback(JSContext *ctx) static void check_heartbeats(void *data) { - struct heartbeat *hb; + struct heartbeat *hb; - foreach (hb, heartbeats) { + foreach (hb, heartbeats) { assert(hb->interpreter); + --hb->ttl; - --hb->ttl; - - if (hb->ttl <= 0) { + if (hb->ttl <= 0) { if (hb->interpreter->vs - && hb->interpreter->vs->doc_view - && hb->interpreter->vs->doc_view->session - && hb->interpreter->vs->doc_view->session->tab - && hb->interpreter->vs->doc_view->session->tab->term) { + && hb->interpreter->vs->doc_view + && hb->interpreter->vs->doc_view->session + && hb->interpreter->vs->doc_view->session->tab + && hb->interpreter->vs->doc_view->session->tab->term) { struct session *ses = hb->interpreter->vs->doc_view->session; struct terminal *term = ses->tab->term; int max_exec_time = get_opt_int("ecmascript.max_exec_time", ses); ecmascript_timeout_dialog(term, max_exec_time); } - - JS_TriggerOperationCallback(hb->interpreter->backend_data); - } - } - - install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); + JS_TriggerOperationCallback(JS_GetRuntime(hb->interpreter->backend_data)); + } + } + install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); } /* Create a new heartbeat for the given interpreter. */ @@ -77,7 +74,7 @@ struct heartbeat * add_heartbeat(struct ecmascript_interpreter *interpreter) { struct session *ses; - struct heartbeat *hb; + struct heartbeat *hb; assert(interpreter); @@ -85,27 +82,26 @@ add_heartbeat(struct ecmascript_interpreter *interpreter) ses = NULL; else ses = interpreter->vs->doc_view->session; + hb = mem_alloc(sizeof(struct heartbeat)); - hb = mem_alloc(sizeof(struct heartbeat)); - if (!hb) return NULL; + if (!hb) return NULL; - hb->ttl = get_opt_int("ecmascript.max_exec_time", ses); - hb->interpreter = interpreter; + hb->ttl = get_opt_int("ecmascript.max_exec_time", ses); + hb->interpreter = interpreter; + add_to_list(heartbeats, hb); - add_to_list(heartbeats, hb); + /* Update the heartbeat timer. */ + if (list_is_singleton(*hb)) { + heartbeat_timer.it_value.tv_sec = 1; + setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL); + } - /* Update the heartbeat timer. */ - if (list_is_singleton(*hb)) { - heartbeat_timer.it_value.tv_sec = 1; - setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL); - } + /* We install the handler every call to add_heartbeat instead of only on + * module initialisation because other code may set other handlers for + * the signal. */ + install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); - /* We install the handler every call to add_heartbeat instead of only on - * module initialisation because other code may set other handlers for - * the signal. */ - install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); - - return hb; + return hb; } /* Destroy the given heartbeat. */ @@ -115,13 +111,13 @@ done_heartbeat(struct heartbeat *hb) if (!hb) return; /* add_heartbeat returned NULL */ assert(hb->interpreter); - /* Stop the heartbeat timer if this heartbeat is the only one. */ - if (list_is_singleton(*hb)) { - heartbeat_timer.it_value.tv_sec = 0; - setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL); - } + /* Stop the heartbeat timer if this heartbeat is the only one. */ + if (list_is_singleton(*hb)) { + heartbeat_timer.it_value.tv_sec = 0; + setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL); + } - del_from_list(hb); - hb->interpreter->heartbeat = NULL; - mem_free(hb); + del_from_list(hb); + hb->interpreter->heartbeat = NULL; + mem_free(hb); } diff --git a/src/ecmascript/spidermonkey/location.c b/src/ecmascript/spidermonkey/location.c index d1fbdfb0..a5a44bf5 100644 --- a/src/ecmascript/spidermonkey/location.c +++ b/src/ecmascript/spidermonkey/location.c @@ -45,16 +45,16 @@ #include "viewer/text/vs.h" -static JSBool history_back(JSContext *ctx, uintN argc, jsval *rval); -static JSBool history_forward(JSContext *ctx, uintN argc, jsval *rval); -static JSBool history_go(JSContext *ctx, uintN argc, jsval *rval); +static JSBool history_back(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool history_forward(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool history_go(JSContext *ctx, unsigned int argc, jsval *rval); -const JSClass history_class = { +JSClass history_class = { "history", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; const spidermonkeyFunctionSpec history_funcs[] = { @@ -66,7 +66,7 @@ const spidermonkeyFunctionSpec history_funcs[] = { /* @history_funcs{"back"} */ static JSBool -history_back(JSContext *ctx, uintN argc, jsval *rval) +history_back(JSContext *ctx, unsigned int argc, jsval *rval) { struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx); struct document_view *doc_view = interpreter->vs->doc_view; @@ -84,7 +84,7 @@ history_back(JSContext *ctx, uintN argc, jsval *rval) /* @history_funcs{"forward"} */ static JSBool -history_forward(JSContext *ctx, uintN argc, jsval *rval) +history_forward(JSContext *ctx, unsigned int argc, jsval *rval) { struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx); struct document_view *doc_view = interpreter->vs->doc_view; @@ -98,7 +98,7 @@ history_forward(JSContext *ctx, uintN argc, jsval *rval) /* @history_funcs{"go"} */ static JSBool -history_go(JSContext *ctx, uintN argc, jsval *rval) +history_go(JSContext *ctx, unsigned int argc, jsval *rval) { struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx); struct document_view *doc_view = interpreter->vs->doc_view; @@ -128,16 +128,16 @@ history_go(JSContext *ctx, uintN argc, jsval *rval) } -static JSBool location_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); -static JSBool location_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp); +static JSBool location_get_property_href(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool location_set_property_href(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); /* Each @location_class object must have a @window_class parent. */ -const JSClass location_class = { +JSClass location_class = { "location", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - location_get_property, location_set_property, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; /* Tinyids of properties. Use negative values to distinguish these @@ -147,56 +147,41 @@ const JSClass location_class = { enum location_prop { JSP_LOC_HREF = -1, }; -const JSPropertySpec location_props[] = { - { "href", JSP_LOC_HREF, JSPROP_ENUMERATE }, +JSPropertySpec location_props[] = { + { "href", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(location_get_property_href), JSOP_WRAPPER(location_set_property_href) }, { NULL } }; -/* @location_class.getProperty */ + static JSBool -location_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +location_get_property_href(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &location_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &location_class, NULL)) return JS_FALSE; - parent_win = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); - if (!JSID_IS_INT(id)) - return JS_TRUE; - - undef_to_jsval(ctx, vp); - - switch (JSID_TO_INT(id)) { - case JSP_LOC_HREF: - astring_to_jsval(ctx, vp, get_uri_string(vs->uri, URI_ORIGINAL)); - break; - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case - * and leave *@vp unchanged. Do the same here. - * (Actually not quite the same, as we already used - * @undef_to_jsval.) */ - break; - } + astring_to_jsval(ctx, vp, get_uri_string(vs->uri, URI_ORIGINAL)); return JS_TRUE; } -/* @location_class.setProperty */ static JSBool -location_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +location_set_property_href(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; struct document_view *doc_view; @@ -204,29 +189,22 @@ location_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsv /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &location_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &location_class, NULL)) return JS_FALSE; - parent_win = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; - - if (!JSID_IS_INT(id)) - return JS_TRUE; - - switch (JSID_TO_INT(id)) { - case JSP_LOC_HREF: - location_goto(doc_view, jsval_to_string(ctx, vp)); - break; - } + location_goto(doc_view, jsval_to_string(ctx, vp)); return JS_TRUE; } -static JSBool location_toString(JSContext *ctx, uintN argc, jsval *rval); + +static JSBool location_toString(JSContext *ctx, unsigned int argc, jsval *rval); const spidermonkeyFunctionSpec location_funcs[] = { { "toString", location_toString, 0 }, @@ -236,7 +214,7 @@ const spidermonkeyFunctionSpec location_funcs[] = { /* @location_funcs{"toString"}, @location_funcs{"toLocaleString"} */ static JSBool -location_toString(JSContext *ctx, uintN argc, jsval *rval) +location_toString(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *obj = JS_THIS_OBJECT(ctx, rval); diff --git a/src/ecmascript/spidermonkey/location.h b/src/ecmascript/spidermonkey/location.h index 864eca38..c9b7bb88 100644 --- a/src/ecmascript/spidermonkey/location.h +++ b/src/ecmascript/spidermonkey/location.h @@ -6,12 +6,12 @@ struct document_view; -extern const JSClass history_class; +extern JSClass history_class; extern const spidermonkeyFunctionSpec history_funcs[]; -extern const JSClass location_class; +extern JSClass location_class; extern const spidermonkeyFunctionSpec location_funcs[]; -extern const JSPropertySpec location_props[]; +extern JSPropertySpec location_props[]; void location_goto(struct document_view *doc_view, unsigned char *url); diff --git a/src/ecmascript/spidermonkey/navigator.c b/src/ecmascript/spidermonkey/navigator.c index f898ec9a..e253af46 100644 --- a/src/ecmascript/spidermonkey/navigator.c +++ b/src/ecmascript/spidermonkey/navigator.c @@ -44,14 +44,19 @@ #include "viewer/text/vs.h" -static JSBool navigator_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); +static JSBool navigator_get_property_appCodeName(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool navigator_get_property_appName(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool navigator_get_property_appVersion(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool navigator_get_property_language(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool navigator_get_property_platform(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool navigator_get_property_userAgent(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); -const JSClass navigator_class = { +JSClass navigator_class = { "navigator", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - navigator_get_property, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; /* Tinyids of properties. Use negative values to distinguish these @@ -61,94 +66,119 @@ const JSClass navigator_class = { enum navigator_prop { JSP_NAVIGATOR_APP_CODENAME = -1, JSP_NAVIGATOR_APP_NAME = -2, - JSP_NAVIGATOR_APP_VERSION = -3, + JSP_NAVIGATOR_APP_VERSION = -3, JSP_NAVIGATOR_LANGUAGE = -4, /* JSP_NAVIGATOR_MIME_TYPES = -5, */ JSP_NAVIGATOR_PLATFORM = -6, /* JSP_NAVIGATOR_PLUGINS = -7, */ JSP_NAVIGATOR_USER_AGENT = -8, }; -const JSPropertySpec navigator_props[] = { - { "appCodeName", JSP_NAVIGATOR_APP_CODENAME, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "appName", JSP_NAVIGATOR_APP_NAME, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "appVersion", JSP_NAVIGATOR_APP_VERSION, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "language", JSP_NAVIGATOR_LANGUAGE, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "platform", JSP_NAVIGATOR_PLATFORM, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "userAgent", JSP_NAVIGATOR_USER_AGENT, JSPROP_ENUMERATE | JSPROP_READONLY }, +JSPropertySpec navigator_props[] = { + { "appCodeName",0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(navigator_get_property_appCodeName), JSOP_NULLWRAPPER }, + { "appName", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(navigator_get_property_appName), JSOP_NULLWRAPPER }, + { "appVersion", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(navigator_get_property_appVersion), JSOP_NULLWRAPPER }, + { "language", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(navigator_get_property_language), JSOP_NULLWRAPPER }, + { "platform", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(navigator_get_property_platform), JSOP_NULLWRAPPER }, + { "userAgent", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(navigator_get_property_userAgent), JSOP_NULLWRAPPER }, { NULL } }; /* @navigator_class.getProperty */ + static JSBool -navigator_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +navigator_get_property_appCodeName(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { - if (!JSID_IS_INT(id)) - return JS_TRUE; + ELINKS_CAST_PROP_PARAMS + (void)obj; - undef_to_jsval(ctx, vp); - - switch (JSID_TO_INT(id)) { - case JSP_NAVIGATOR_APP_CODENAME: - string_to_jsval(ctx, vp, "Mozilla"); /* More like a constant nowadays. */ - break; - case JSP_NAVIGATOR_APP_NAME: - /* This evil hack makes the compatibility checking .indexOf() - * code find what it's looking for. */ - string_to_jsval(ctx, vp, "ELinks (roughly compatible with Netscape Navigator, Mozilla and Microsoft Internet Explorer)"); - break; - case JSP_NAVIGATOR_APP_VERSION: - string_to_jsval(ctx, vp, VERSION); - break; - case JSP_NAVIGATOR_LANGUAGE: -#ifdef CONFIG_NLS - if (get_opt_bool("protocol.http.accept_ui_language", NULL)) - string_to_jsval(ctx, vp, language_to_iso639(current_language)); - -#endif - break; - case JSP_NAVIGATOR_PLATFORM: - string_to_jsval(ctx, vp, system_name); - break; - case JSP_NAVIGATOR_USER_AGENT: - { - /* FIXME: Code duplication. */ - unsigned char *optstr = get_opt_str("protocol.http.user_agent", - NULL); - - if (*optstr && strcmp(optstr, " ")) { - unsigned char *ustr, ts[64] = ""; - static unsigned char custr[256]; - /* TODO: Somehow get the terminal in which the - * document is actually being displayed. */ - struct terminal *term = get_default_terminal(); - - if (term) { - unsigned int tslen = 0; - - ulongcat(ts, &tslen, term->width, 3, 0); - ts[tslen++] = 'x'; - ulongcat(ts, &tslen, term->height, 3, 0); - } - ustr = subst_user_agent(optstr, VERSION_STRING, system_name, ts); - - if (ustr) { - safe_strncpy(custr, ustr, 256); - mem_free(ustr); - string_to_jsval(ctx, vp, custr); - } - } - } - break; - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case - * and leave *@vp unchanged. Do the same here. - * (Actually not quite the same, as we already used - * @undef_to_jsval.) */ - break; - } + string_to_jsval(ctx, vp, "Mozilla"); /* More like a constant nowadays. */ + + return JS_TRUE; +} + +static JSBool +navigator_get_property_appName(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + (void)obj; + + string_to_jsval(ctx, vp, "ELinks (roughly compatible with Netscape Navigator, Mozilla and Microsoft Internet Explorer)"); + + return JS_TRUE; +} + +static JSBool +navigator_get_property_appVersion(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + (void)obj; + + string_to_jsval(ctx, vp, VERSION); + + return JS_TRUE; +} + +static JSBool +navigator_get_property_language(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + (void)obj; + + undef_to_jsval(ctx, vp); +#ifdef CONFIG_NLS + if (get_opt_bool("protocol.http.accept_ui_language", NULL)) + string_to_jsval(ctx, vp, language_to_iso639(current_language)); + +#endif + return JS_TRUE; +} + +static JSBool +navigator_get_property_platform(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + (void)obj; + + string_to_jsval(ctx, vp, system_name); + + return JS_TRUE; +} + +static JSBool +navigator_get_property_userAgent(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + unsigned char *optstr; + (void)obj; + + optstr = get_opt_str("protocol.http.user_agent", NULL); + + if (*optstr && strcmp(optstr, " ")) { + unsigned char *ustr, ts[64] = ""; + static unsigned char custr[256]; + /* TODO: Somehow get the terminal in which the + * document is actually being displayed. */ + struct terminal *term = get_default_terminal(); + + if (term) { + unsigned int tslen = 0; + + ulongcat(ts, &tslen, term->width, 3, 0); + ts[tslen++] = 'x'; + ulongcat(ts, &tslen, term->height, 3, 0); + } + ustr = subst_user_agent(optstr, VERSION_STRING, system_name, ts); + + if (ustr) { + safe_strncpy(custr, ustr, 256); + mem_free(ustr); + string_to_jsval(ctx, vp, custr); + + return JS_TRUE; + } + } + string_to_jsval(ctx, vp, system_name); return JS_TRUE; } diff --git a/src/ecmascript/spidermonkey/navigator.h b/src/ecmascript/spidermonkey/navigator.h index 6dc40017..ac602fe9 100644 --- a/src/ecmascript/spidermonkey/navigator.h +++ b/src/ecmascript/spidermonkey/navigator.h @@ -4,7 +4,7 @@ #include "ecmascript/spidermonkey/util.h" -extern const JSClass navigator_class; -extern const JSPropertySpec navigator_props[]; +extern JSClass navigator_class; +extern JSPropertySpec navigator_props[]; #endif diff --git a/src/ecmascript/spidermonkey/unibar.c b/src/ecmascript/spidermonkey/unibar.c index 576c0a7a..f26cb180 100644 --- a/src/ecmascript/spidermonkey/unibar.c +++ b/src/ecmascript/spidermonkey/unibar.c @@ -44,25 +44,24 @@ #include "viewer/text/link.h" #include "viewer/text/vs.h" - -static JSBool unibar_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); -static JSBool unibar_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp); +static JSBool unibar_get_property_visible(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool unibar_set_property_visible(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); /* Each @menubar_class object must have a @window_class parent. */ -const JSClass menubar_class = { +JSClass menubar_class = { "menubar", JSCLASS_HAS_PRIVATE, /* const char * "t" */ JS_PropertyStub, JS_PropertyStub, - unibar_get_property, unibar_set_property, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; /* Each @statusbar_class object must have a @window_class parent. */ -const JSClass statusbar_class = { +JSClass statusbar_class = { "statusbar", JSCLASS_HAS_PRIVATE, /* const char * "s" */ JS_PropertyStub, JS_PropertyStub, - unibar_get_property, unibar_set_property, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; /* Tinyids of properties. Use negative values to distinguish these @@ -72,16 +71,18 @@ const JSClass statusbar_class = { enum unibar_prop { JSP_UNIBAR_VISIBLE = -1, }; -const JSPropertySpec unibar_props[] = { - { "visible", JSP_UNIBAR_VISIBLE, JSPROP_ENUMERATE }, +JSPropertySpec unibar_props[] = { + { "visible", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(unibar_get_property_visible), JSOP_WRAPPER(unibar_set_property_visible) }, { NULL } }; -/* @menubar_class.getProperty, @statusbar_class.getProperty */ + static JSBool -unibar_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +unibar_get_property_visible(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; struct document_view *doc_view; @@ -91,56 +92,44 @@ unibar_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) /* This can be called if @obj if not itself an instance of either * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &menubar_class, NULL) - && !JS_InstanceOf(ctx, obj, (JSClass *) &statusbar_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &menubar_class, NULL) + && !JS_InstanceOf(ctx, obj, &statusbar_class, NULL)) return JS_FALSE; - parent_win = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; status = &doc_view->session->status; - bar = JS_GetPrivate(ctx, obj); /* from @menubar_class or @statusbar_class */ + bar = JS_GetPrivate(obj); /* from @menubar_class or @statusbar_class */ - if (!JSID_IS_INT(id)) - return JS_TRUE; - - switch (JSID_TO_INT(id)) { - case JSP_UNIBAR_VISIBLE: #define unibar_fetch(bar) \ boolean_to_jsval(ctx, vp, status->force_show_##bar##_bar >= 0 \ ? status->force_show_##bar##_bar \ : status->show_##bar##_bar) - switch (*bar) { - case 's': - unibar_fetch(status); - break; - case 't': - unibar_fetch(title); - break; - default: - boolean_to_jsval(ctx, vp, 0); - break; - } -#undef unibar_fetch + switch (*bar) { + case 's': + unibar_fetch(status); + break; + case 't': + unibar_fetch(title); break; default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case - * and leave *@vp unchanged. Do the same here. */ + boolean_to_jsval(ctx, vp, 0); break; } +#undef unibar_fetch return JS_TRUE; } -/* @menubar_class.setProperty, @statusbar_class.setProperty */ static JSBool -unibar_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +unibar_set_property_visible(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; struct document_view *doc_view; @@ -150,43 +139,30 @@ unibar_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval /* This can be called if @obj if not itself an instance of either * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &menubar_class, NULL) - && !JS_InstanceOf(ctx, obj, (JSClass *) &statusbar_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &menubar_class, NULL) + && !JS_InstanceOf(ctx, obj, &statusbar_class, NULL)) return JS_FALSE; - parent_win = JS_GetParent(ctx, obj); - assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); + parent_win = JS_GetParent(obj); + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); if_assert_failed return JS_FALSE; vs = JS_GetInstancePrivate(ctx, parent_win, - (JSClass *) &window_class, NULL); + &window_class, NULL); doc_view = vs->doc_view; status = &doc_view->session->status; - bar = JS_GetPrivate(ctx, obj); /* from @menubar_class or @statusbar_class */ + bar = JS_GetPrivate(obj); /* from @menubar_class or @statusbar_class */ - if (!JSID_IS_INT(id)) - return JS_TRUE; - - switch (JSID_TO_INT(id)) { - case JSP_UNIBAR_VISIBLE: - switch (*bar) { - case 's': - status->force_show_status_bar = jsval_to_boolean(ctx, vp); - break; - case 't': - status->force_show_title_bar = jsval_to_boolean(ctx, vp); - break; - default: - break; - } - register_bottom_half(update_status, NULL); + switch (*bar) { + case 's': + status->force_show_status_bar = jsval_to_boolean(ctx, vp); + break; + case 't': + status->force_show_title_bar = jsval_to_boolean(ctx, vp); break; default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case. - * Do the same here. */ - return JS_TRUE; + break; } + register_bottom_half(update_status, NULL); return JS_TRUE; } diff --git a/src/ecmascript/spidermonkey/unibar.h b/src/ecmascript/spidermonkey/unibar.h index e21e0876..766be9a4 100644 --- a/src/ecmascript/spidermonkey/unibar.h +++ b/src/ecmascript/spidermonkey/unibar.h @@ -4,8 +4,8 @@ #include "ecmascript/spidermonkey/util.h" -extern const JSClass menubar_class; -extern const JSClass statusbar_class; -extern const JSPropertySpec unibar_props[]; +extern JSClass menubar_class; +extern JSClass statusbar_class; +extern JSPropertySpec unibar_props[]; #endif diff --git a/src/ecmascript/spidermonkey/window.c b/src/ecmascript/spidermonkey/window.c index 93cba2b8..bee163ab 100644 --- a/src/ecmascript/spidermonkey/window.c +++ b/src/ecmascript/spidermonkey/window.c @@ -44,15 +44,21 @@ #include "viewer/text/vs.h" -static JSBool window_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp); -static JSBool window_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp); +static JSBool window_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool window_get_property_closed(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool window_get_property_parent(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool window_get_property_self(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool window_get_property_status(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool window_set_property_status(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool window_get_property_top(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool window_get_property_window(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); -const JSClass window_class = { +JSClass window_class = { "window", JSCLASS_HAS_PRIVATE | JSCLASS_GLOBAL_FLAGS, /* struct view_state * */ JS_PropertyStub, JS_PropertyStub, - window_get_property, window_set_property, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + window_get_property, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; @@ -73,13 +79,13 @@ enum window_prop { * (SpiderMonkey was still asking us about the "location" string after * assigning to it once), instead we do just a little string * comparing. */ -const JSPropertySpec window_props[] = { - { "closed", JSP_WIN_CLOSED, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "parent", JSP_WIN_PARENT, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "self", JSP_WIN_SELF, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "status", JSP_WIN_STATUS, JSPROP_ENUMERATE }, - { "top", JSP_WIN_TOP, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "window", JSP_WIN_SELF, JSPROP_ENUMERATE | JSPROP_READONLY }, +JSPropertySpec window_props[] = { + { "closed", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(window_get_property_closed), JSOP_NULLWRAPPER }, + { "parent", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(window_get_property_parent), JSOP_NULLWRAPPER }, + { "self", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(window_get_property_self), JSOP_NULLWRAPPER }, + { "status", 0, JSPROP_ENUMERATE|JSPROP_SHARED, JSOP_WRAPPER(window_get_property_status), JSOP_WRAPPER(window_set_property_status) }, + { "top", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(window_get_property_top), JSOP_NULLWRAPPER }, + { "window", 0, JSPROP_ENUMERATE | JSPROP_READONLY|JSPROP_SHARED, JSOP_WRAPPER(window_get_property_window), JSOP_NULLWRAPPER }, { NULL } }; @@ -122,17 +128,20 @@ find_child_frame(struct document_view *doc_view, struct frame_desc *tframe) /* @window_class.getProperty */ static JSBool -window_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +window_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct view_state *vs; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &window_class, NULL)) + if (!JS_InstanceOf(ctx, obj, &window_class, NULL)) return JS_FALSE; - vs = JS_GetInstancePrivate(ctx, obj, (JSClass *) &window_class, NULL); + vs = JS_GetInstancePrivate(ctx, obj, &window_class, NULL); /* No need for special window.location measurements - when * location is then evaluated in string context, toString() @@ -140,9 +149,7 @@ window_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) * everything's fine. */ if (JSID_IS_STRING(id)) { struct document_view *doc_view = vs->doc_view; - JSObject *obj; - - obj = try_resolve_frame(doc_view, jsid_to_string(ctx, &id)); + JSObject *obj = try_resolve_frame(doc_view, jsid_to_string(ctx, &id)); /* TODO: Try other lookups (mainly element lookup) until * something yields data. */ if (obj) { @@ -252,55 +259,9 @@ found_parent: void location_goto(struct document_view *doc_view, unsigned char *url); -/* @window_class.setProperty */ -static JSBool -window_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) -{ - struct view_state *vs; - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, obj, (JSClass *) &window_class, NULL)) - return JS_FALSE; - - vs = JS_GetInstancePrivate(ctx, obj, (JSClass *) &window_class, NULL); - - if (JSID_IS_STRING(id)) { - if (!strcmp(jsid_to_string(ctx, &id), "location")) { - struct document_view *doc_view = vs->doc_view; - - location_goto(doc_view, jsval_to_string(ctx, vp)); - /* Do NOT touch our .location property, evil - * SpiderMonkey!! */ - return JS_FALSE; - } - return JS_TRUE; - } - - if (!JSID_IS_INT(id)) - return JS_TRUE; - - switch (JSID_TO_INT(id)) { - case JSP_WIN_STATUS: - mem_free_set(&vs->doc_view->session->status.window_status, stracpy(jsval_to_string(ctx, vp))); - print_screen_status(vs->doc_view->session); - return JS_TRUE; - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case. - * Do the same here. */ - return JS_TRUE; - } - - return JS_TRUE; -} - - -static JSBool window_alert(JSContext *ctx, uintN argc, jsval *rval); -static JSBool window_open(JSContext *ctx, uintN argc, jsval *rval); -static JSBool window_setTimeout(JSContext *ctx, uintN argc, jsval *rval); +static JSBool window_alert(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool window_open(JSContext *ctx, unsigned int argc, jsval *rval); +static JSBool window_setTimeout(JSContext *ctx, unsigned int argc, jsval *rval); const spidermonkeyFunctionSpec window_funcs[] = { { "alert", window_alert, 1 }, @@ -311,7 +272,7 @@ const spidermonkeyFunctionSpec window_funcs[] = { /* @window_funcs{"alert"} */ static JSBool -window_alert(JSContext *ctx, uintN argc, jsval *rval) +window_alert(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *obj = JS_THIS_OBJECT(ctx, rval); @@ -319,9 +280,9 @@ window_alert(JSContext *ctx, uintN argc, jsval *rval) struct view_state *vs; unsigned char *string; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &window_class, argv)) return JS_FALSE; + if (!JS_InstanceOf(ctx, obj, &window_class, argv)) return JS_FALSE; - vs = JS_GetInstancePrivate(ctx, obj, (JSClass *) &window_class, argv); + vs = JS_GetInstancePrivate(ctx, obj, &window_class, argv); if (argc != 1) return JS_TRUE; @@ -340,7 +301,7 @@ window_alert(JSContext *ctx, uintN argc, jsval *rval) /* @window_funcs{"open"} */ static JSBool -window_open(JSContext *ctx, uintN argc, jsval *rval) +window_open(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; JSObject *obj = JS_THIS_OBJECT(ctx, rval); @@ -354,9 +315,9 @@ window_open(JSContext *ctx, uintN argc, jsval *rval) static time_t ratelimit_start; static int ratelimit_count; - if (!JS_InstanceOf(ctx, obj, (JSClass *) &window_class, argv)) return JS_FALSE; + if (!JS_InstanceOf(ctx, obj, &window_class, argv)) return JS_FALSE; - vs = JS_GetInstancePrivate(ctx, obj, (JSClass *) &window_class, argv); + vs = JS_GetInstancePrivate(ctx, obj, &window_class, argv); doc_view = vs->doc_view; ses = doc_view->session; @@ -451,7 +412,7 @@ end: /* @window_funcs{"setTimeout"} */ static JSBool -window_setTimeout(JSContext *ctx, uintN argc, jsval *rval) +window_setTimeout(JSContext *ctx, unsigned int argc, jsval *rval) { jsval *argv = JS_ARGV(ctx, rval); struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx); @@ -476,3 +437,150 @@ window_setTimeout(JSContext *ctx, uintN argc, jsval *rval) ecmascript_set_timeout(interpreter, code, timeout); return JS_TRUE; } + +static JSBool +window_get_property_closed(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &window_class, NULL)) + return JS_FALSE; + + boolean_to_jsval(ctx, vp, 0); + + return JS_TRUE; +} + +static JSBool +window_get_property_parent(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &window_class, NULL)) + return JS_FALSE; + + /* XXX: It would be nice if the following worked, yes. + * The problem is that we get called at the point where + * document.frame properties are going to be mostly NULL. + * But the problem is deeper because at that time we are + * yet building scrn_frames so our parent might not be there + * yet (XXX: is this true?). The true solution will be to just + * have struct document_view *(document_view.parent). --pasky */ + /* FIXME: So now we alias window.parent to window.top, which is + * INCORRECT but works for the most common cases of just two + * frames. Better something than nothing. */ + + undef_to_jsval(ctx, vp); + + return JS_TRUE; +} + +static JSBool +window_get_property_self(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &window_class, NULL)) + return JS_FALSE; + + object_to_jsval(ctx, vp, obj); + + return JS_TRUE; +} + +static JSBool +window_get_property_status(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &window_class, NULL)) + return JS_FALSE; + + undef_to_jsval(ctx, vp); + + return JS_TRUE; +} + +static JSBool +window_set_property_status(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct view_state *vs; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &window_class, NULL)) + return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, obj, &window_class, NULL); + + mem_free_set(&vs->doc_view->session->status.window_status, stracpy(jsval_to_string(ctx, vp))); + print_screen_status(vs->doc_view->session); + + return JS_TRUE; +} + +static JSBool +window_get_property_top(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct view_state *vs; + struct document_view *doc_view; + struct document_view *top_view; + JSObject *newjsframe; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, &window_class, NULL)) + return JS_FALSE; + + vs = JS_GetInstancePrivate(ctx, obj, &window_class, NULL); + doc_view = vs->doc_view; + top_view = doc_view->session->doc_view; + + undef_to_jsval(ctx, vp); + + assert(top_view && top_view->vs); + if (top_view->vs->ecmascript_fragile) + ecmascript_reset_state(top_view->vs); + if (!top_view->vs->ecmascript) + return JS_TRUE; + newjsframe = JS_GetGlobalObject(top_view->vs->ecmascript->backend_data); + + /* Keep this unrolled this way. Will have to check document.domain + * JS property. */ + /* Note that this check is perhaps overparanoid. If top windows + * is alien but some other child window is not, we should still + * let the script walk thru. That'd mean moving the check to + * other individual properties in this switch. */ + if (compare_uri(vs->uri, top_view->vs->uri, URI_HOST)) + object_to_jsval(ctx, vp, newjsframe); + /* else */ + /****X*X*X*** SECURITY VIOLATION! RED ALERT, SHIELDS UP! ***X*X*X****\ + |* (Pasky was apparently looking at the Links2 JS code . ___ ^.^ *| + \* for too long.) `.(,_,)\o/ */ + + return JS_TRUE; +} + +static JSBool +window_get_property_window(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + return window_get_property_self(ctx, hobj, hid, hvp); +} diff --git a/src/ecmascript/spidermonkey/window.h b/src/ecmascript/spidermonkey/window.h index 283dc495..e927b833 100644 --- a/src/ecmascript/spidermonkey/window.h +++ b/src/ecmascript/spidermonkey/window.h @@ -4,8 +4,8 @@ #include "ecmascript/spidermonkey/util.h" -extern const JSClass window_class; -extern const JSPropertySpec window_props[]; +extern JSClass window_class; +extern JSPropertySpec window_props[]; extern const spidermonkeyFunctionSpec window_funcs[]; #endif diff --git a/src/scripting/smjs/action_object.c b/src/scripting/smjs/action_object.c index 113d132a..86e9ed79 100644 --- a/src/scripting/smjs/action_object.c +++ b/src/scripting/smjs/action_object.c @@ -27,22 +27,26 @@ static const JSClass action_fn_class; /* defined below */ /* @action_fn_class.finalize */ static void -smjs_action_fn_finalize(JSContext *ctx, JSObject *obj) +smjs_action_fn_finalize(JSFreeOp *op, JSObject *obj) { struct smjs_action_fn_callback_hop *hop; +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &action_fn_class, NULL)); if_assert_failed return; hop = JS_GetInstancePrivate(ctx, obj, (JSClass *) &action_fn_class, NULL); +#endif + + hop = JS_GetPrivate(obj); mem_free_if(hop); } /* @action_fn_class.call */ static JSBool -smjs_action_fn_callback(JSContext *ctx, uintN argc, jsval *rval) +smjs_action_fn_callback(JSContext *ctx, unsigned int argc, jsval *rval) { jsval value; jsval *argv = JS_ARGV(ctx, rval); @@ -95,7 +99,7 @@ smjs_action_fn_callback(JSContext *ctx, uintN argc, jsval *rval) } if (argc >= 1) { - int32 val; + int32_t val; if (JS_TRUE == JS_ValueToInt32(smjs_ctx, argv[0], &val)) { set_kbd_repeat_count(hop->ses, val); @@ -117,7 +121,7 @@ static const JSClass action_fn_class = { JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, smjs_action_fn_finalize, - NULL, NULL, + NULL, smjs_action_fn_callback, }; @@ -145,9 +149,9 @@ smjs_get_action_fn_object(unsigned char *action_str) hop->action_id = get_action_from_string(KEYMAP_MAIN, action_str); - if (-1 != hop->action_id - && JS_TRUE == JS_SetPrivate(smjs_ctx, obj, hop)) { /* to @action_fn_class */ - return obj; + if (-1 != hop->action_id) { + JS_SetPrivate(obj, hop); /* to @action_fn_class */ + return obj; } mem_free(hop); @@ -159,8 +163,12 @@ smjs_get_action_fn_object(unsigned char *action_str) /* @action_class.getProperty */ static JSBool -action_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +action_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + (void)obj; + jsval val; JSObject *action_fn; unsigned char *action_str; @@ -184,7 +192,7 @@ static const JSClass action_class = { 0, JS_PropertyStub, JS_PropertyStub, action_get_property, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, }; static JSObject * diff --git a/src/scripting/smjs/bookmarks.c b/src/scripting/smjs/bookmarks.c index dd1f46d7..057fbd56 100644 --- a/src/scripting/smjs/bookmarks.c +++ b/src/scripting/smjs/bookmarks.c @@ -33,26 +33,24 @@ smjs_get_bookmark_generic_object(struct bookmark *bookmark, JSClass *clasp) if (!bookmark) return jsobj; - if (JS_TRUE == JS_SetPrivate(smjs_ctx, jsobj, bookmark)) { /* to @bookmark_class or @bookmark_folder_class */ - object_lock(bookmark); + JS_SetPrivate(jsobj, bookmark); /* to @bookmark_class or @bookmark_folder_class */ + object_lock(bookmark); - return jsobj; - } - - return NULL; + return jsobj; }; /* @bookmark_class.finalize, @bookmark_folder_class.finalize */ static void -bookmark_finalize(JSContext *ctx, JSObject *obj) +bookmark_finalize(JSFreeOp *op, JSObject *obj) { struct bookmark *bookmark; - +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL) || JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_folder_class, NULL)); if_assert_failed return; +#endif - bookmark = JS_GetPrivate(ctx, obj); /* from @bookmark_class or @bookmark_folder_class */ + bookmark = JS_GetPrivate(obj); /* from @bookmark_class or @bookmark_folder_class */ if (bookmark) object_unlock(bookmark); } @@ -70,10 +68,16 @@ enum bookmark_prop { BOOKMARK_CHILDREN = -3, }; +static JSBool bookmark_get_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool bookmark_set_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool bookmark_get_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool bookmark_set_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool bookmark_get_property_children(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); + static const JSPropertySpec bookmark_props[] = { - { "title", BOOKMARK_TITLE, JSPROP_ENUMERATE }, - { "url", BOOKMARK_URL, JSPROP_ENUMERATE }, - { "children", BOOKMARK_CHILDREN, JSPROP_ENUMERATE | JSPROP_READONLY }, + { "title", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(bookmark_get_property_title), JSOP_WRAPPER(bookmark_set_property_title) }, + { "url", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(bookmark_get_property_url), JSOP_WRAPPER(bookmark_set_property_url) }, + { "children", 0, JSPROP_ENUMERATE | JSPROP_READONLY, JSOP_WRAPPER(bookmark_get_property_children), JSOP_NULLWRAPPER }, { NULL } }; @@ -145,10 +149,11 @@ jsval_to_bookmark_string(JSContext *ctx, jsval val, unsigned char **result) return JS_TRUE; } -/* @bookmark_class.getProperty */ static JSBool -bookmark_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +bookmark_get_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + struct bookmark *bookmark; /* This can be called if @obj if not itself an instance of the @@ -162,35 +167,14 @@ bookmark_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) if (!bookmark) return JS_FALSE; - undef_to_jsval(ctx, vp); - - if (!JSID_IS_INT(id)) - return JS_FALSE; - - switch (JSID_TO_INT(id)) { - case BOOKMARK_TITLE: - return bookmark_string_to_jsval(ctx, bookmark->title, vp); - case BOOKMARK_URL: - return bookmark_string_to_jsval(ctx, bookmark->url, vp); - case BOOKMARK_CHILDREN: - *vp = OBJECT_TO_JSVAL(smjs_get_bookmark_folder_object(bookmark)); - - return JS_TRUE; - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case - * and leave *@vp unchanged. Do the same here. - * (Actually not quite the same, as we already used - * @undef_to_jsval.) */ - return JS_TRUE; - } + return bookmark_string_to_jsval(ctx, bookmark->title, vp); } -/* @bookmark_class.setProperty */ static JSBool -bookmark_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +bookmark_set_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + struct bookmark *bookmark; unsigned char *title = NULL; unsigned char *url = NULL; @@ -207,37 +191,94 @@ bookmark_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsv if (!bookmark) return JS_FALSE; - if (!JSID_IS_INT(id)) + if (!jsval_to_bookmark_string(ctx, *vp, &title)) return JS_FALSE; - switch (JSID_TO_INT(id)) { - case BOOKMARK_TITLE: - if (!jsval_to_bookmark_string(ctx, *vp, &title)) - return JS_FALSE; - break; - case BOOKMARK_URL: - if (!jsval_to_bookmark_string(ctx, *vp, &url)) - return JS_FALSE; - break; - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case. - * Do the same here. */ - return JS_TRUE; - } - ok = update_bookmark(bookmark, get_cp_index("UTF-8"), title, url); mem_free_if(title); mem_free_if(url); return ok ? JS_TRUE : JS_FALSE; } +static JSBool +bookmark_get_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct bookmark *bookmark; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL)) + return JS_FALSE; + + bookmark = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &bookmark_class, NULL); + + if (!bookmark) return JS_FALSE; + + return bookmark_string_to_jsval(ctx, bookmark->url, vp); +} + +static JSBool +bookmark_set_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct bookmark *bookmark; + unsigned char *title = NULL; + unsigned char *url = NULL; + int ok; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL)) + return JS_FALSE; + + bookmark = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &bookmark_class, NULL); + + if (!bookmark) return JS_FALSE; + + if (!jsval_to_bookmark_string(ctx, *vp, &url)) + return JS_FALSE; + + ok = update_bookmark(bookmark, get_cp_index("UTF-8"), title, url); + mem_free_if(title); + mem_free_if(url); + return ok ? JS_TRUE : JS_FALSE; +} + +static JSBool +bookmark_get_property_children(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct bookmark *bookmark; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL)) + return JS_FALSE; + + bookmark = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &bookmark_class, NULL); + + if (!bookmark) return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(smjs_get_bookmark_folder_object(bookmark)); + + return JS_TRUE; +} + static const JSClass bookmark_class = { "bookmark", JSCLASS_HAS_PRIVATE, /* struct bookmark * */ JS_PropertyStub, JS_PropertyStub, - bookmark_get_property, bookmark_set_property, + JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, bookmark_finalize, }; @@ -262,8 +303,11 @@ smjs_get_bookmark_object(struct bookmark *bookmark) /* @bookmark_folder_class.getProperty */ static JSBool -bookmark_folder_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +bookmark_folder_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct bookmark *bookmark; struct bookmark *folder; jsval title_jsval = JSVAL_VOID; diff --git a/src/scripting/smjs/cache_object.c b/src/scripting/smjs/cache_object.c index 8b69ae99..9995370d 100644 --- a/src/scripting/smjs/cache_object.c +++ b/src/scripting/smjs/cache_object.c @@ -29,20 +29,31 @@ enum cache_entry_prop { CACHE_ENTRY_URI = -5, }; +static JSBool cache_entry_get_property_content(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool cache_entry_set_property_content(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool cache_entry_get_property_type(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool cache_entry_set_property_type(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool cache_entry_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool cache_entry_get_property_head(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool cache_entry_set_property_head(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool cache_entry_get_property_uri(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); + static const JSPropertySpec cache_entry_props[] = { - { "content", CACHE_ENTRY_CONTENT, JSPROP_ENUMERATE }, - { "type", CACHE_ENTRY_TYPE, JSPROP_ENUMERATE }, - { "length", CACHE_ENTRY_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY }, - { "head", CACHE_ENTRY_HEAD, JSPROP_ENUMERATE }, - { "uri", CACHE_ENTRY_URI, JSPROP_ENUMERATE | JSPROP_READONLY }, + { "content", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(cache_entry_get_property_content), JSOP_WRAPPER(cache_entry_set_property_content) }, + { "type", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(cache_entry_get_property_type), JSOP_WRAPPER(cache_entry_set_property_type)}, + { "length", 0, JSPROP_ENUMERATE | JSPROP_READONLY, JSOP_WRAPPER(cache_entry_get_property_length), JSOP_NULLWRAPPER }, + { "head", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(cache_entry_get_property_head), JSOP_WRAPPER(cache_entry_set_property_head) }, + { "uri", 0, JSPROP_ENUMERATE | JSPROP_READONLY, JSOP_WRAPPER(cache_entry_get_property_uri), JSOP_NULLWRAPPER }, { NULL } }; -/* @cache_entry_class.getProperty */ static JSBool -cache_entry_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +cache_entry_get_property_content(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + struct cache_entry *cached; + struct fragment *fragment; JSBool ret; /* This can be called if @obj if not itself an instance of the @@ -65,69 +76,28 @@ cache_entry_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) object_lock(cached); undef_to_jsval(ctx, vp); + fragment = get_cache_fragment(cached); - if (!JSID_IS_INT(id)) + if (!fragment) { ret = JS_FALSE; - else switch (JSID_TO_INT(id)) { - case CACHE_ENTRY_CONTENT: { - struct fragment *fragment = get_cache_fragment(cached); - - if (!fragment) { - ret = JS_FALSE; - break; - } - - *vp = STRING_TO_JSVAL(JS_NewStringCopyN(smjs_ctx, - fragment->data, - fragment->length)); - + } else { + *vp = STRING_TO_JSVAL(JS_NewStringCopyN(smjs_ctx, fragment->data, fragment->length)); ret = JS_TRUE; - break; - } - case CACHE_ENTRY_TYPE: - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, - cached->content_type)); - - ret = JS_TRUE; - break; - case CACHE_ENTRY_HEAD: - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, - cached->head)); - - ret = JS_TRUE; - break; - case CACHE_ENTRY_LENGTH: - *vp = INT_TO_JSVAL(cached->length); - - ret = JS_TRUE; - break; - case CACHE_ENTRY_URI: - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, - struri(cached->uri))); - - ret = JS_TRUE; - break; - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case - * and leave *@vp unchanged. Do the same here. - * (Actually not quite the same, as we already used - * @undef_to_jsval.) */ - ret = JS_TRUE; - break; } object_unlock(cached); return ret; } -/* @cache_entry_class.setProperty */ static JSBool -cache_entry_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +cache_entry_set_property_content(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + struct cache_entry *cached; - JSBool ret; + JSString *jsstr; + unsigned char *str; + size_t len; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail @@ -148,68 +118,105 @@ cache_entry_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, * eventually unlock the object. */ object_lock(cached); - if (!JSID_IS_INT(id)) - ret = JS_FALSE; - else switch (JSID_TO_INT(id)) { - case CACHE_ENTRY_CONTENT: { - JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); - unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); - size_t len = JS_GetStringLength(jsstr); - - add_fragment(cached, 0, str, len); - normalize_cache_entry(cached, len); - - ret = JS_TRUE; - break; - } - case CACHE_ENTRY_TYPE: { - JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); - unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); - - mem_free_set(&cached->content_type, stracpy(str)); - - ret = JS_TRUE; - break; - } - case CACHE_ENTRY_HEAD: { - JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); - unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); - - mem_free_set(&cached->head, stracpy(str)); - - ret = JS_TRUE; - break; - } - default: - /* Unrecognized integer property ID; someone is using - * the object as an array. SMJS builtin classes (e.g. - * js_RegExpClass) just return JS_TRUE in this case. - * Do the same here. */ - ret = JS_TRUE; - break; - } + jsstr = JS_ValueToString(smjs_ctx, *vp); + str = JS_EncodeString(smjs_ctx, jsstr); + len = JS_GetStringLength(jsstr); + add_fragment(cached, 0, str, len); + normalize_cache_entry(cached, len); object_unlock(cached); - return ret; + return JS_TRUE; } +static JSBool +cache_entry_get_property_type(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct cache_entry *cached; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) + return JS_FALSE; + + cached = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &cache_entry_class, NULL); + if (!cached) return JS_FALSE; /* already detached */ + + assert(cache_entry_is_valid(cached)); + if_assert_failed return JS_FALSE; + + /* Get a strong reference to the cache entry to prevent it + * from being deleted if some function called below decides to + * collect garbage. After this, all code paths must + * eventually unlock the object. */ + object_lock(cached); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, cached->content_type)); + object_unlock(cached); + + return JS_TRUE; +} + +static JSBool +cache_entry_set_property_type(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct cache_entry *cached; + JSString *jsstr; + unsigned char *str; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) + return JS_FALSE; + + cached = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &cache_entry_class, NULL); + if (!cached) return JS_FALSE; /* already detached */ + + assert(cache_entry_is_valid(cached)); + if_assert_failed return JS_FALSE; + + /* Get a strong reference to the cache entry to prevent it + * from being deleted if some function called below decides to + * collect garbage. After this, all code paths must + * eventually unlock the object. */ + object_lock(cached); + + jsstr = JS_ValueToString(smjs_ctx, *vp); + str = JS_EncodeString(smjs_ctx, jsstr); + mem_free_set(&cached->content_type, stracpy(str)); + + object_unlock(cached); + + return JS_TRUE; +} + + + + + /** Pointed to by cache_entry_class.finalize. SpiderMonkey * automatically finalizes all objects before it frees the JSRuntime, * so cache_entry.jsobject won't be left dangling. */ static void -cache_entry_finalize(JSContext *ctx, JSObject *obj) +cache_entry_finalize(JSFreeOp *op, JSObject *obj) { struct cache_entry *cached; - +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)); if_assert_failed return; +#endif - cached = JS_GetInstancePrivate(ctx, obj, - (JSClass *) &cache_entry_class, NULL); + cached = JS_GetPrivate(obj); if (!cached) return; /* already detached */ - JS_SetPrivate(ctx, obj, NULL); /* perhaps not necessary */ + JS_SetPrivate(obj, NULL); /* perhaps not necessary */ assert(cached->jsobject == obj); if_assert_failed return; cached->jsobject = NULL; @@ -219,7 +226,7 @@ static const JSClass cache_entry_class = { "cache_entry", JSCLASS_HAS_PRIVATE, /* struct cache_entry *; a weak reference */ JS_PropertyStub, JS_PropertyStub, - cache_entry_get_property, cache_entry_set_property, + JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, cache_entry_finalize }; @@ -252,9 +259,7 @@ smjs_get_cache_entry_object(struct cache_entry *cached) /* Do this last, so that if any previous step fails, we can * just forget the object and its finalizer won't attempt to * access @cached. */ - if (JS_FALSE == JS_SetPrivate(smjs_ctx, cache_entry_object, cached)) /* to @cache_entry_class */ - return NULL; - + JS_SetPrivate(cache_entry_object, cached); /* to @cache_entry_class */ cached->jsobject = cache_entry_object; return cache_entry_object; } @@ -278,6 +283,136 @@ smjs_detach_cache_entry_object(struct cache_entry *cached) == cached); if_assert_failed {} - JS_SetPrivate(smjs_ctx, cached->jsobject, NULL); + JS_SetPrivate(cached->jsobject, NULL); cached->jsobject = NULL; } + +static JSBool +cache_entry_get_property_length(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct cache_entry *cached; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) + return JS_FALSE; + + cached = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &cache_entry_class, NULL); + if (!cached) return JS_FALSE; /* already detached */ + + assert(cache_entry_is_valid(cached)); + if_assert_failed return JS_FALSE; + + /* Get a strong reference to the cache entry to prevent it + * from being deleted if some function called below decides to + * collect garbage. After this, all code paths must + * eventually unlock the object. */ + object_lock(cached); + *vp = INT_TO_JSVAL(cached->length); + object_unlock(cached); + + return JS_TRUE; +} + +static JSBool +cache_entry_get_property_head(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct cache_entry *cached; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) + return JS_FALSE; + + cached = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &cache_entry_class, NULL); + if (!cached) return JS_FALSE; /* already detached */ + + assert(cache_entry_is_valid(cached)); + if_assert_failed return JS_FALSE; + + /* Get a strong reference to the cache entry to prevent it + * from being deleted if some function called below decides to + * collect garbage. After this, all code paths must + * eventually unlock the object. */ + object_lock(cached); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, cached->head)); + object_unlock(cached); + + return JS_TRUE; +} + +static JSBool +cache_entry_set_property_head(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct cache_entry *cached; + JSString *jsstr; + unsigned char *str; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) + return JS_FALSE; + + cached = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &cache_entry_class, NULL); + if (!cached) return JS_FALSE; /* already detached */ + + assert(cache_entry_is_valid(cached)); + if_assert_failed return JS_FALSE; + + /* Get a strong reference to the cache entry to prevent it + * from being deleted if some function called below decides to + * collect garbage. After this, all code paths must + * eventually unlock the object. */ + object_lock(cached); + + jsstr = JS_ValueToString(smjs_ctx, *vp); + str = JS_EncodeString(smjs_ctx, jsstr); + mem_free_set(&cached->head, stracpy(str)); + + object_unlock(cached); + + return JS_TRUE; +} + +static JSBool +cache_entry_get_property_uri(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct cache_entry *cached; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) + return JS_FALSE; + + cached = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &cache_entry_class, NULL); + if (!cached) return JS_FALSE; /* already detached */ + + assert(cache_entry_is_valid(cached)); + if_assert_failed return JS_FALSE; + + /* Get a strong reference to the cache entry to prevent it + * from being deleted if some function called below decides to + * collect garbage. After this, all code paths must + * eventually unlock the object. */ + object_lock(cached); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, struri(cached->uri))); + object_unlock(cached); + + return JS_TRUE; +} diff --git a/src/scripting/smjs/core.c b/src/scripting/smjs/core.c index 012c68e5..11488033 100644 --- a/src/scripting/smjs/core.c +++ b/src/scripting/smjs/core.c @@ -94,7 +94,7 @@ smjs_do_file(unsigned char *path) } static JSBool -smjs_do_file_wrapper(JSContext *ctx, uintN argc, jsval *rval) +smjs_do_file_wrapper(JSContext *ctx, unsigned int argc, jsval *rval) { jsval *argv = JS_ARGV(ctx, rval); JSString *jsstr = JS_ValueToString(smjs_ctx, *argv); @@ -136,7 +136,7 @@ init_smjs(struct module *module) return; } - JS_SetOptions(smjs_ctx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT); + JS_SetOptions(smjs_ctx, JSOPTION_VAROBJFIX | JSOPTION_METHODJIT); JS_SetVersion(smjs_ctx, JSVERSION_LATEST); JS_SetErrorReporter(smjs_ctx, error_reporter); diff --git a/src/scripting/smjs/elinks_object.c b/src/scripting/smjs/elinks_object.c index c06dc82e..69a71a67 100644 --- a/src/scripting/smjs/elinks_object.c +++ b/src/scripting/smjs/elinks_object.c @@ -33,7 +33,7 @@ /* @elinks_funcs{"alert"} */ static JSBool -elinks_alert(JSContext *ctx, uintN argc, jsval *rval) +elinks_alert(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; jsval *argv = JS_ARGV(ctx, rval); @@ -69,7 +69,7 @@ elinks_alert(JSContext *ctx, uintN argc, jsval *rval) /* @elinks_funcs{"execute"} */ static JSBool -elinks_execute(JSContext *ctx, uintN argc, jsval *rval) +elinks_execute(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; jsval *argv = JS_ARGV(ctx, rval); @@ -95,10 +95,15 @@ enum elinks_prop { ELINKS_SESSION, }; +static JSBool elinks_get_property_home(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool elinks_get_property_location(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool elinks_set_property_location(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool elinks_get_property_session(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); + static const JSPropertySpec elinks_props[] = { - { "home", ELINKS_HOME, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY }, - { "location", ELINKS_LOCATION, JSPROP_ENUMERATE | JSPROP_PERMANENT }, - { "session", ELINKS_SESSION, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY }, + { "home", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY, JSOP_WRAPPER(elinks_get_property_home), JSOP_NULLWRAPPER }, + { "location", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT, JSOP_WRAPPER(elinks_get_property_location), JSOP_WRAPPER(elinks_set_property_location) }, + { "session", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY, JSOP_WRAPPER(elinks_get_property_session), JSOP_NULLWRAPPER}, { NULL } }; @@ -106,8 +111,11 @@ static const JSClass elinks_class; /* @elinks_class.getProperty */ static JSBool -elinks_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +elinks_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ @@ -161,8 +169,11 @@ elinks_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) } static JSBool -elinks_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +elinks_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ @@ -205,7 +216,7 @@ static const JSClass elinks_class = { 0, JS_PropertyStub, JS_PropertyStub, elinks_get_property, elinks_set_property, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; static const spidermonkeyFunctionSpec elinks_funcs[] = { @@ -262,3 +273,87 @@ smjs_invoke_elinks_object_method(unsigned char *method, jsval argv[], int argc, return JS_CallFunctionValue(smjs_ctx, smjs_elinks_object, *rval, argc, argv, rval); } + +static JSBool +elinks_get_property_home(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &elinks_class, NULL)) + return JS_FALSE; + + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, elinks_home)); + + return JS_TRUE; +} + +static JSBool +elinks_get_property_location(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + struct uri *uri; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &elinks_class, NULL)) + return JS_FALSE; + + if (!smjs_ses) return JS_FALSE; + + uri = have_location(smjs_ses) ? cur_loc(smjs_ses)->vs.uri : smjs_ses->loading_uri; + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, uri ? (const char *) struri(uri) : "")); + + return JS_TRUE; +} + +static JSBool +elinks_set_property_location(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + JSString *jsstr; + unsigned char *url; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &elinks_class, NULL)) + return JS_FALSE; + + if (!smjs_ses) return JS_FALSE; + + jsstr = JS_ValueToString(smjs_ctx, *vp); + if (!jsstr) return JS_FALSE; + + url = JS_EncodeString(smjs_ctx, jsstr); + if (!url) return JS_FALSE; + + goto_url(smjs_ses, url); + + return JS_TRUE; +} + +static JSBool +elinks_get_property_session(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + JSObject *jsobj; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &elinks_class, NULL)) + return JS_FALSE; + + if (!smjs_ses) return JS_FALSE; + + jsobj = smjs_get_session_object(smjs_ses); + if (!jsobj) return JS_FALSE; + + object_to_jsval(ctx, vp, jsobj); + + return JS_TRUE; +} diff --git a/src/scripting/smjs/global_object.c b/src/scripting/smjs/global_object.c index 0976f8ae..74050fde 100644 --- a/src/scripting/smjs/global_object.c +++ b/src/scripting/smjs/global_object.c @@ -19,7 +19,7 @@ static const JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; static JSObject * @@ -29,7 +29,7 @@ smjs_get_global_object(void) assert(smjs_ctx); - jsobj = JS_NewCompartmentAndGlobalObject(smjs_ctx, (JSClass *) &global_class, NULL); + jsobj = JS_NewGlobalObject(smjs_ctx, (JSClass *) &global_class, NULL); if (!jsobj) return NULL; diff --git a/src/scripting/smjs/globhist.c b/src/scripting/smjs/globhist.c index 705e5f5f..fb7064b9 100644 --- a/src/scripting/smjs/globhist.c +++ b/src/scripting/smjs/globhist.c @@ -18,16 +18,15 @@ static const JSClass smjs_globhist_item_class; /* defined below */ /* @smjs_globhist_item_class.finalize */ static void -smjs_globhist_item_finalize(JSContext *ctx, JSObject *obj) +smjs_globhist_item_finalize(JSFreeOp *op, JSObject *obj) { struct global_history_item *history_item; - +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)); if_assert_failed return; +#endif - history_item = JS_GetInstancePrivate(ctx, obj, - (JSClass *) &smjs_globhist_item_class, - NULL); + history_item = JS_GetPrivate(obj); if (history_item) object_unlock(history_item); } @@ -42,18 +41,28 @@ enum smjs_globhist_item_prop { GLOBHIST_LAST_VISIT = -3, }; +static JSBool smjs_globhist_item_get_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool smjs_globhist_item_set_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool smjs_globhist_item_get_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool smjs_globhist_item_set_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); +static JSBool smjs_globhist_item_get_property_last_visit(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp); +static JSBool smjs_globhist_item_set_property_last_visit(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp); + static const JSPropertySpec smjs_globhist_item_props[] = { - { "title", GLOBHIST_TITLE, JSPROP_ENUMERATE }, - { "url", GLOBHIST_URL, JSPROP_ENUMERATE }, - { "last_visit", GLOBHIST_LAST_VISIT, JSPROP_ENUMERATE }, + { "title", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(smjs_globhist_item_get_property_title), JSOP_WRAPPER(smjs_globhist_item_set_property_title) }, + { "url", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(smjs_globhist_item_get_property_url), JSOP_WRAPPER(smjs_globhist_item_set_property_url) }, + { "last_visit", 0, JSPROP_ENUMERATE, JSOP_WRAPPER(smjs_globhist_item_get_property_last_visit), JSOP_WRAPPER(smjs_globhist_item_set_property_last_visit) }, { NULL } }; /* @smjs_globhist_item_class.getProperty */ static JSBool -smjs_globhist_item_get_property(JSContext *ctx, JSObject *obj, jsid id, - jsval *vp) +smjs_globhist_item_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, + JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct global_history_item *history_item; /* This can be called if @obj if not itself an instance of the @@ -101,7 +110,7 @@ smjs_globhist_item_get_property(JSContext *ctx, JSObject *obj, jsid id, * Since the Date object uses milliseconds since the epoch, * I'd rather export that, but SpiderMonkey doesn't provide * a suitable type. -- Miciah */ - JS_NewNumberValue(smjs_ctx, history_item->last_visit, vp); + *vp = JS_NumberValue(history_item->last_visit); return JS_TRUE; default: @@ -117,8 +126,11 @@ smjs_globhist_item_get_property(JSContext *ctx, JSObject *obj, jsid id, /* @smjs_globhist_item_class.setProperty */ static JSBool -smjs_globhist_item_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +smjs_globhist_item_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct global_history_item *history_item; /* This can be called if @obj if not itself an instance of the @@ -154,7 +166,7 @@ smjs_globhist_item_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool s return JS_TRUE; } case GLOBHIST_LAST_VISIT: { - uint32 seconds; + uint32_t seconds; /* Bug 923: Assumes time_t values fit in uint32. */ JS_ValueToECMAUint32(smjs_ctx, *vp, &seconds); @@ -189,10 +201,10 @@ smjs_get_globhist_item_object(struct global_history_item *history_item) NULL, NULL); if (!jsobj || JS_TRUE != JS_DefineProperties(smjs_ctx, jsobj, - (JSPropertySpec *) smjs_globhist_item_props) - || JS_TRUE != JS_SetPrivate(smjs_ctx, jsobj, history_item)) /* to @smjs_globhist_item_class */ + (JSPropertySpec *) smjs_globhist_item_props)) { return NULL; - + } + JS_SetPrivate(jsobj, history_item); /* to @smjs_globhist_item_class */ object_lock(history_item); return jsobj; @@ -201,8 +213,12 @@ smjs_get_globhist_item_object(struct global_history_item *history_item) /* @smjs_globhist_class.getProperty */ static JSBool -smjs_globhist_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +smjs_globhist_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + (void)obj; + JSObject *jsobj; unsigned char *uri_string; struct global_history_item *history_item; @@ -234,7 +250,7 @@ static const JSClass smjs_globhist_class = { "global_history", 0, JS_PropertyStub, JS_PropertyStub, smjs_globhist_get_property, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, }; static JSObject * @@ -265,3 +281,178 @@ smjs_init_globhist_interface(void) JS_SetProperty(smjs_ctx, smjs_elinks_object, "globhist", &val); } + +static JSBool +smjs_globhist_item_get_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, + JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct global_history_item *history_item; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) + return JS_FALSE; + + history_item = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &smjs_globhist_item_class, + NULL); + + if (!history_item) return JS_FALSE; + + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, history_item->title)); + + return JS_TRUE; +} + +static JSBool +smjs_globhist_item_set_property_title(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct global_history_item *history_item; + JSString *jsstr; + unsigned char *str; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) + return JS_FALSE; + + history_item = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &smjs_globhist_item_class, + NULL); + + if (!history_item) return JS_FALSE; + + jsstr = JS_ValueToString(smjs_ctx, *vp); + str = JS_EncodeString(smjs_ctx, jsstr); + mem_free_set(&history_item->title, stracpy(str)); + + return JS_TRUE; +} + +static JSBool +smjs_globhist_item_get_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, + JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct global_history_item *history_item; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) + return JS_FALSE; + + history_item = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &smjs_globhist_item_class, + NULL); + + if (!history_item) return JS_FALSE; + + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, history_item->url)); + + return JS_TRUE; +} + +static JSBool +smjs_globhist_item_set_property_url(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct global_history_item *history_item; + JSString *jsstr; + unsigned char *str; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) + return JS_FALSE; + + history_item = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &smjs_globhist_item_class, + NULL); + + if (!history_item) return JS_FALSE; + + jsstr = JS_ValueToString(smjs_ctx, *vp); + str = JS_EncodeString(smjs_ctx, jsstr); + mem_free_set(&history_item->url, stracpy(str)); + + return JS_TRUE; +} + +static JSBool +smjs_globhist_item_get_property_last_visit(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, + JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct global_history_item *history_item; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) + return JS_FALSE; + + history_item = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &smjs_globhist_item_class, + NULL); + + if (!history_item) return JS_FALSE; + + /* TODO: I'd rather return a date object, but that introduces + * synchronisation issues: + * + * - How do we cause a change to that date object to affect + * the actual global history item? + * - How do we get a change to that global history item + * to affect all date objects? + * + * The biggest obstacle is that we have no way to trigger code + * when one messes with the date object. + * + * -- Miciah */ + /* XXX: Currently, ECMAScript gets seconds since the epoch. + * Since the Date object uses milliseconds since the epoch, + * I'd rather export that, but SpiderMonkey doesn't provide + * a suitable type. -- Miciah */ + *vp = JS_NumberValue(history_item->last_visit); + + return JS_TRUE; +} + +/* @smjs_globhist_item_class.setProperty */ +static JSBool +smjs_globhist_item_set_property_last_visit(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) +{ + ELINKS_CAST_PROP_PARAMS + + struct global_history_item *history_item; + uint32_t seconds; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) + return JS_FALSE; + + history_item = JS_GetInstancePrivate(ctx, obj, + (JSClass *) &smjs_globhist_item_class, + NULL); + + if (!history_item) return JS_FALSE; + + /* Bug 923: Assumes time_t values fit in uint32. */ + JS_ValueToECMAUint32(smjs_ctx, *vp, &seconds); + history_item->last_visit = seconds; + + return JS_TRUE; +} diff --git a/src/scripting/smjs/keybinding.c b/src/scripting/smjs/keybinding.c index 0ddf421b..6a4c28a3 100644 --- a/src/scripting/smjs/keybinding.c +++ b/src/scripting/smjs/keybinding.c @@ -17,8 +17,11 @@ static const JSClass keymap_class; /* defined below */ /* @keymap_class.getProperty */ static JSBool -keymap_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +keymap_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + unsigned char *action_str; const unsigned char *keystroke_str; int *data; @@ -74,8 +77,11 @@ smjs_keybinding_action_callback(va_list ap, void *data) /* @keymap_class.setProperty */ static JSBool -keymap_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +keymap_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + int *data; unsigned char *keymap_str; jsval val; @@ -116,7 +122,7 @@ keymap_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval return JS_TRUE; - } else if (JSVAL_IS_OBJECT(*vp)) { + } else if (!JSVAL_IS_PRIMITIVE(*vp) || JSVAL_IS_NULL(*vp)) { unsigned char *err = NULL; int event_id; struct string event_name = NULL_STRING; @@ -160,15 +166,15 @@ keymap_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval /* @keymap_class.finalize */ static void -keymap_finalize(JSContext *ctx, JSObject *obj) +keymap_finalize(JSFreeOp *op, JSObject *obj) { void *data; - +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &keymap_class, NULL)); if_assert_failed return; +#endif - data = JS_GetInstancePrivate(ctx, obj, - (JSClass *) &keymap_class, NULL); + data = JS_GetPrivate(obj); mem_free(data); } @@ -197,12 +203,8 @@ smjs_get_keymap_object(enum keymap_id keymap_id) data = intdup(keymap_id); if (!data) return NULL; - if (JS_TRUE == JS_SetPrivate(smjs_ctx, keymap_object, data)) /* to @keymap_class */ - return keymap_object; - - mem_free(data); - - return NULL; + JS_SetPrivate(keymap_object, data); /* to @keymap_class */ + return keymap_object; } static const JSClass keymaps_hash_class = { @@ -210,7 +212,7 @@ static const JSClass keymaps_hash_class = { JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, }; static JSObject * diff --git a/src/scripting/smjs/load_uri.c b/src/scripting/smjs/load_uri.c index a35e6ac3..f7011cbd 100644 --- a/src/scripting/smjs/load_uri.c +++ b/src/scripting/smjs/load_uri.c @@ -65,7 +65,7 @@ end: } static JSBool -smjs_load_uri(JSContext *ctx, uintN argc, jsval *rval) +smjs_load_uri(JSContext *ctx, unsigned int argc, jsval *rval) { jsval *argv = JS_ARGV(ctx, rval); struct smjs_load_uri_hop *hop; diff --git a/src/scripting/smjs/session_object.c b/src/scripting/smjs/session_object.c index 89a15dae..41beda41 100644 --- a/src/scripting/smjs/session_object.c +++ b/src/scripting/smjs/session_object.c @@ -42,8 +42,11 @@ static const JSClass location_array_class; /* Defined below. */ /* @location_array.getProperty */ static JSBool -smjs_location_array_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +smjs_location_array_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct session *ses; int index; struct location *loc; @@ -90,19 +93,20 @@ smjs_location_array_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval * * finalizes all objects before it frees the JSRuntime, so * session.history_jsobject won't be left dangling. */ static void -smjs_location_array_finalize(JSContext *ctx, JSObject *obj) +smjs_location_array_finalize(JSFreeOp *op, JSObject *obj) { struct session *ses; +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &location_array_class, NULL)); if_assert_failed return; +#endif - ses = JS_GetInstancePrivate(ctx, obj, - (JSClass *) &location_array_class, NULL); + ses = JS_GetPrivate(obj); if (!ses) return; /* already detached */ - JS_SetPrivate(ctx, obj, NULL); /* perhaps not necessary */ + JS_SetPrivate(obj, NULL); /* perhaps not necessary */ assert(ses->history_jsobject == obj); if_assert_failed return; ses->history_jsobject = NULL; @@ -135,8 +139,7 @@ smjs_get_session_location_array_object(struct session *ses) /* Do this last, so that if any previous step fails, we can * just forget the object and its finalizer won't attempt to * access @ses. */ - if (JS_FALSE == JS_SetPrivate(smjs_ctx, obj, ses)) - return NULL; + JS_SetPrivate(obj, ses); ses->history_jsobject = obj; return obj; @@ -188,8 +191,11 @@ static const JSPropertySpec session_props[] = { /* @session_class.getProperty */ static JSBool -session_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +session_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct session *ses; /* This can be called if @obj if not itself an instance of the @@ -294,8 +300,11 @@ session_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) } static JSBool -session_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +session_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct session *ses; /* This can be called if @obj if not itself an instance of the @@ -450,7 +459,7 @@ session_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsva /** Pointed to by session_class.construct. Create a new session (tab) * and return the JSObject wrapper. */ static JSBool -session_construct(JSContext *ctx, uintN argc, jsval *rval) +session_construct(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; jsval *argv = JS_ARGV(ctx, rval); @@ -484,19 +493,20 @@ session_construct(JSContext *ctx, uintN argc, jsval *rval) * finalizes all objects before it frees the JSRuntime, so session.jsobject * won't be left dangling. */ static void -session_finalize(JSContext *ctx, JSObject *obj) +session_finalize(JSFreeOp *op, JSObject *obj) { struct session *ses; +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &session_class, NULL)); if_assert_failed return; +#endif - ses = JS_GetInstancePrivate(ctx, obj, - (JSClass *) &session_class, NULL); + ses = JS_GetPrivate(obj); if (!ses) return; /* already detached */ - JS_SetPrivate(ctx, obj, NULL); /* perhaps not necessary */ + JS_SetPrivate(obj, NULL); /* perhaps not necessary */ assert(ses->jsobject == obj); if_assert_failed return; ses->jsobject = NULL; @@ -508,7 +518,7 @@ static const JSClass session_class = { JS_PropertyStub, JS_PropertyStub, session_get_property, session_set_property, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, session_finalize, - NULL, NULL, session_construct + NULL, NULL, NULL, session_construct }; /** Return an SMJS object through which scripts can access @a ses. @@ -534,8 +544,7 @@ smjs_get_session_object(struct session *ses) /* Do this last, so that if any previous step fails, we can * just forget the object and its finalizer won't attempt to * access @ses. */ - if (JS_FALSE == JS_SetPrivate(smjs_ctx, obj, ses)) /* to @session_class */ - return NULL; + JS_SetPrivate(obj, ses); /* to @session_class */ ses->jsobject = obj; return obj; @@ -558,7 +567,7 @@ smjs_detach_session_object(struct session *ses) == ses); if_assert_failed {} - JS_SetPrivate(smjs_ctx, ses->jsobject, NULL); + JS_SetPrivate(ses->jsobject, NULL); ses->jsobject = NULL; } @@ -569,7 +578,7 @@ smjs_detach_session_object(struct session *ses) == ses); if_assert_failed {} - JS_SetPrivate(smjs_ctx, ses->history_jsobject, NULL); + JS_SetPrivate(ses->history_jsobject, NULL); ses->history_jsobject = NULL; } } @@ -581,10 +590,13 @@ smjs_detach_session_object(struct session *ses) * previously attached to the session object, the object will remain in * memory but it will no longer be able to access the session object. */ static JSBool -session_array_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +session_array_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + JSObject *tabobj; - struct terminal *term = JS_GetPrivate(ctx, obj); + struct terminal *term = JS_GetPrivate(obj); int index; struct window *tab; @@ -614,7 +626,7 @@ static const JSClass session_array_class = { JSCLASS_HAS_PRIVATE, /* struct terminal *term; a weak reference */ JS_PropertyStub, JS_PropertyStub, session_array_get_property, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; JSObject * @@ -629,8 +641,7 @@ smjs_get_session_array_object(struct terminal *term) NULL, NULL); if (!obj) return NULL; - if (JS_FALSE == JS_SetPrivate(smjs_ctx, obj, term)) - return NULL; + JS_SetPrivate(obj, term); return obj; } @@ -653,12 +664,12 @@ smjs_detach_session_array_object(struct terminal *term) == term); if_assert_failed {} - JS_SetPrivate(smjs_ctx, term->session_array_jsobject, NULL); + JS_SetPrivate(term->session_array_jsobject, NULL); term->session_array_jsobject = NULL; } static JSBool -smjs_session_goto_url(JSContext *ctx, uintN argc, jsval *rval) +smjs_session_goto_url(JSContext *ctx, unsigned int argc, jsval *rval) { jsval val; struct delayed_open *deo; diff --git a/src/scripting/smjs/terminal_object.c b/src/scripting/smjs/terminal_object.c index 7e975362..e47ba87f 100644 --- a/src/scripting/smjs/terminal_object.c +++ b/src/scripting/smjs/terminal_object.c @@ -30,8 +30,11 @@ static const JSPropertySpec terminal_props[] = { /* @terminal_class.getProperty */ static JSBool -terminal_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +terminal_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct terminal *term; /* This can be called if @obj if not itself an instance of the @@ -68,19 +71,18 @@ terminal_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) * finalizes all objects before it frees the JSRuntime, so terminal.jsobject * won't be left dangling. */ static void -terminal_finalize(JSContext *ctx, JSObject *obj) +terminal_finalize(JSFreeOp *op, JSObject *obj) { struct terminal *term; - +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &terminal_class, NULL)); if_assert_failed return; - - term = JS_GetInstancePrivate(ctx, obj, - (JSClass *) &terminal_class, NULL); +#endif + term = JS_GetPrivate(obj); if (!term) return; /* already detached */ - JS_SetPrivate(ctx, obj, NULL); /* perhaps not necessary */ + JS_SetPrivate(obj, NULL); /* perhaps not necessary */ assert(term->jsobject == obj); if_assert_failed return; term->jsobject = NULL; @@ -118,8 +120,7 @@ smjs_get_terminal_object(struct terminal *term) /* Do this last, so that if any previous step fails, we can * just forget the object and its finalizer won't attempt to * access @cached. */ - if (JS_FALSE == JS_SetPrivate(smjs_ctx, obj, term)) /* to @terminal_class */ - return NULL; + JS_SetPrivate(obj, term); /* to @terminal_class */ term->jsobject = obj; return obj; @@ -145,15 +146,18 @@ smjs_detach_terminal_object(struct terminal *term) == term); if_assert_failed {} - JS_SetPrivate(smjs_ctx, term->jsobject, NULL); + JS_SetPrivate(term->jsobject, NULL); term->jsobject = NULL; } /* @terminal_array_class.getProperty */ static JSBool -terminal_array_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +terminal_array_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + int index; struct terminal *term; @@ -181,7 +185,7 @@ static const JSClass terminal_array_class = { 0, JS_PropertyStub, JS_PropertyStub, terminal_array_get_property, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL }; /** Return an SMJS object that scripts can use an array to get terminal diff --git a/src/scripting/smjs/view_state_object.c b/src/scripting/smjs/view_state_object.c index 5cd208a6..1f23a9b3 100644 --- a/src/scripting/smjs/view_state_object.c +++ b/src/scripting/smjs/view_state_object.c @@ -39,8 +39,11 @@ static const JSPropertySpec view_state_props[] = { /* @view_state_class.getProperty */ static JSBool -view_state_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +view_state_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct view_state *vs; /* This can be called if @obj if not itself an instance of the @@ -81,8 +84,11 @@ view_state_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) /* @view_state_class.setProperty */ static JSBool -view_state_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +view_state_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + jsid id = *(hid._); + struct view_state *vs; /* This can be called if @obj if not itself an instance of the @@ -117,19 +123,22 @@ view_state_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, j * finalizes all objects before it frees the JSRuntime, so view_state.jsobject * won't be left dangling. */ static void -view_state_finalize(JSContext *ctx, JSObject *obj) +view_state_finalize(JSFreeOp *op, JSObject *obj) { struct view_state *vs; - +#if 0 assert(JS_InstanceOf(ctx, obj, (JSClass *) &view_state_class, NULL)); if_assert_failed return; vs = JS_GetInstancePrivate(ctx, obj, (JSClass *) &view_state_class, NULL); +#endif + + vs = JS_GetPrivate(obj); if (!vs) return; /* already detached */ - JS_SetPrivate(ctx, obj, NULL); /* perhaps not necessary */ + JS_SetPrivate(obj, NULL); /* perhaps not necessary */ assert(vs->jsobject == obj); if_assert_failed return; vs->jsobject = NULL; @@ -168,16 +177,18 @@ smjs_get_view_state_object(struct view_state *vs) /* Do this last, so that if any previous step fails, we can * just forget the object and its finalizer won't attempt to * access @vs. */ - if (JS_FALSE == JS_SetPrivate(smjs_ctx, view_state_object, vs)) /* to @view_state_class */ - return NULL; + JS_SetPrivate(view_state_object, vs); /* to @view_state_class */ vs->jsobject = view_state_object; return view_state_object; } static JSBool -smjs_elinks_get_view_state(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) +smjs_elinks_get_view_state(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp) { + ELINKS_CAST_PROP_PARAMS + (void)obj; + JSObject *vs_obj; struct view_state *vs; @@ -214,7 +225,7 @@ smjs_detach_view_state_object(struct view_state *vs) == vs); if_assert_failed {} - JS_SetPrivate(smjs_ctx, vs->jsobject, NULL); + JS_SetPrivate(vs->jsobject, NULL); vs->jsobject = NULL; } diff --git a/test/ecmascript/protocol.html b/test/ecmascript/protocol.html index f542f4cc..7ae40c2b 100644 --- a/test/ecmascript/protocol.html +++ b/test/ecmascript/protocol.html @@ -1,5 +1,5 @@

Change the document.title while preventing going anywhere because returning undefined.

-

Change the document.url (which is impossible because it's read-only, but the return value of the statement is used as the link target so it magically still works).

+

Change the document.url (which is impossible because it's read-only, but the return value of the statement is used as the link target so it magically still works).

-

Change the document.title and go to elinks.or.cz (return value of statement).

+

Change the document.title and go to elinks.or.cz (return value of statement).