Fill out various proxy binding traps as part of making setters work. Add named getter and setter and indexed getter support, as well as proxy object expandos. Fixes #660.

This commit is contained in:
Josh Matthews 2013-08-03 13:48:09 -04:00
parent a4baa7fc6b
commit c9bc2046f6
10 changed files with 376 additions and 48 deletions

View file

@ -2,10 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::is_dom_proxy;
use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar};
use js::jsapi::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free};
use js::glue::{RUST_JSVAL_IS_VOID, RUST_JSVAL_TO_OBJECT, GetProxyExtra};
use js::glue::{GetObjectProto};
use js::jsapi::{JSBool, JS_DefinePropertyById, JS_NewObjectWithGivenProto};
use js::glue::{RUST_JSVAL_IS_VOID, RUST_JSVAL_TO_OBJECT, GetProxyExtra, RUST_OBJECT_TO_JSVAL};
use js::glue::{GetObjectProto, GetObjectParent, SetProxyExtra, GetProxyHandler};
use js::glue::InvokeGetOwnPropertyDescriptor;
use js::crust::{JS_StrictPropertyStub};
use js::{JSPROP_GETTER, JSPROP_ENUMERATE, JSPROP_READONLY, JSRESOLVE_QUALIFIED};
use std::cast;
use std::libc;
@ -15,10 +20,13 @@ use std::sys::size_of;
type c_bool = libc::c_int;
static JSPROXYSLOT_EXPANDO: u32 = 0;
pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
unsafe {
if _getOwnPropertyDescriptor(cx, proxy, id, set, desc) == 0 {
let handler = GetProxyHandler(proxy);
if InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, set, desc) == 0 {
return 0;
}
if (*desc).obj.is_not_null() {
@ -32,34 +40,30 @@ pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
return 1;
}
JS_GetPropertyDescriptorById(cx, proto, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
cast::transmute(desc))
JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, cast::transmute(desc))
}
}
fn _getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
_set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
unsafe {
let v = GetProxyExtra(proxy, 0 /*JSPROXYSLOT_EXPANDO*/);
if RUST_JSVAL_IS_VOID(v) == 0 {
let expando = RUST_JSVAL_TO_OBJECT(v);
if JS_GetPropertyDescriptorById(cx, expando, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
cast::transmute(desc)) == 0 {
pub extern fn defineProperty(cx: *JSContext, proxy: *JSObject, id: jsid,
desc: *JSPropertyDescriptor) -> JSBool {
unsafe {
if ((*desc).attrs & JSPROP_GETTER) != 0 && (*desc).setter == JS_StrictPropertyStub {
/*return JS_ReportErrorFlagsAndNumber(cx,
JSREPORT_WARNING | JSREPORT_STRICT |
JSREPORT_STRICT_MODE_ERROR,
js_GetErrorMessage, NULL,
JSMSG_GETTER_ONLY);*/
return 0;
}
if (*desc).obj.is_not_null() {
(*desc).obj = proxy;
return 1;
}
}
(*desc).obj = ptr::null();
1
}
}
pub extern fn getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
_getOwnPropertyDescriptor(cx, proxy, id, set, desc)
let expando = EnsureExpandoObject(cx, proxy);
if expando.is_null() {
return 0;
}
return JS_DefinePropertyById(cx, expando, id, (*desc).value, (*desc).getter,
(*desc).setter, (*desc).attrs);
}
}
pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
@ -84,6 +88,39 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
}
}
pub fn GetExpandoObject(_proxy: *JSObject) -> *JSObject {
ptr::null()
pub fn GetExpandoObject(obj: *JSObject) -> *JSObject {
unsafe {
assert!(is_dom_proxy(obj));
let val = GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
if RUST_JSVAL_IS_VOID(val) == 1 {
ptr::null()
} else {
RUST_JSVAL_TO_OBJECT(val)
}
}
}
pub fn EnsureExpandoObject(cx: *JSContext, obj: *JSObject) -> *JSObject {
unsafe {
assert!(is_dom_proxy(obj));
let mut expando = GetExpandoObject(obj);
if expando.is_null() {
expando = JS_NewObjectWithGivenProto(cx, ptr::null(), ptr::null(),
GetObjectParent(obj));
if expando.is_null() {
return ptr::null();
}
SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, RUST_OBJECT_TO_JSVAL(expando));
}
return expando;
}
}
pub fn FillPropertyDescriptor(desc: &mut JSPropertyDescriptor, obj: *JSObject, readonly: bool) {
desc.obj = obj;
desc.attrs = if readonly { JSPROP_READONLY } else { 0 } | JSPROP_ENUMERATE;
desc.getter = ptr::null();
desc.setter = ptr::null();
desc.shortid = 0;
}