diff options
author | Josh Matthews <josh@joshmatthews.net> | 2013-08-03 13:48:09 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2013-08-03 13:48:09 -0400 |
commit | c9bc2046f683d03449d38e0d82339fee32be3528 (patch) | |
tree | 573e69a6a0e43358e678cdcf445820aafb85207d /src | |
parent | a4baa7fc6b072ef4be73a3fb46f3cdb81607192b (diff) | |
download | servo-c9bc2046f683d03449d38e0d82339fee32be3528.tar.gz servo-c9bc2046f683d03449d38e0d82339fee32be3528.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/components/script/dom/bindings/codegen/CodegenRust.py | 290 | ||||
-rw-r--r-- | src/components/script/dom/bindings/codegen/Configuration.py | 1 | ||||
-rw-r--r-- | src/components/script/dom/bindings/proxyhandler.rs | 89 | ||||
-rw-r--r-- | src/components/script/dom/bindings/utils.rs | 8 | ||||
-rw-r--r-- | src/components/script/dom/document.rs | 16 | ||||
-rw-r--r-- | src/components/script/dom/htmlcollection.rs | 4 | ||||
-rw-r--r-- | src/components/script/dom/htmldocument.rs | 4 | ||||
-rw-r--r-- | src/components/script/dom/window.rs | 4 | ||||
m--------- | src/support/spidermonkey/rust-mozjs | 0 | ||||
-rw-r--r-- | src/test/html/test_bindings.js | 4 |
10 files changed, 374 insertions, 46 deletions
diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py index 1c177e2e8ea..5666e177d14 100644 --- a/src/components/script/dom/bindings/codegen/CodegenRust.py +++ b/src/components/script/dom/bindings/codegen/CodegenRust.py @@ -1435,8 +1435,8 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, if not callWrapValue: tail = successCode elif haveSuccessCode: - tail = ("if (!JS_WrapValue(cx, ${jsvalPtr})) {\n" + - " return false;\n" + + tail = ("if JS_WrapValue(cx, ${jsvalPtr}) == 0 {\n" + + " return 0;\n" + "}\n" + successCode) else: @@ -1527,7 +1527,7 @@ for (uint32_t i = 0; i < length; ++i) { properResult = result + ".as_cacheable_wrapper()" else: properResult += " as @mut CacheableWrapper" - wrap = "%s(cx, ${obj}, %s, ${jsvalPtr})" % (wrapMethod, properResult) + wrap = "%s(cx, ${obj}, %s, ${jsvalPtr} as *mut JSVal)" % (wrapMethod, properResult) # We don't support prefable stuff in workers. assert(not descriptor.prefable or not descriptor.workers) if not descriptor.prefable: @@ -1547,7 +1547,7 @@ for (uint32_t i = 0; i < length; ++i) { else: #wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID) if descriptor.pointerType == '': - wrap = "%s.wrap(cx, ${obj}, ${jsvalPtr})" % result + wrap = "(%s.wrap(cx, ${obj}, ${jsvalPtr}) as bool)" % result else: wrap = "if WrapNewBindingObject(cx, ${obj}, %s as @mut CacheableWrapper, ${jsvalPtr}) { 1 } else { 0 };" % result wrappingCode += wrapAndSetPtr(wrap) @@ -2815,13 +2815,13 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): body += """ let traps = ProxyTraps { getPropertyDescriptor: getPropertyDescriptor, getOwnPropertyDescriptor: getOwnPropertyDescriptor, - defineProperty: ptr::null(), + defineProperty: defineProperty, getOwnPropertyNames: ptr::null(), delete_: ptr::null(), enumerate: ptr::null(), has: ptr::null(), - hasOwn: ptr::null(), + hasOwn: hasOwn, get: get, set: ptr::null(), keys: ptr::null(), @@ -3233,8 +3233,8 @@ class CGGenericGetter(CGAbstractBindingMethod): def generate_code(self): return CGIndenter(CGGeneric( - "let _info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "return CallJitPropertyOp(_info, cx, obj, ptr::to_unsafe_ptr(&(*this).payload) as *libc::c_void, vp);")) + "let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" + "return CallJitPropertyOp(info, cx, obj, ptr::to_unsafe_ptr(&(*this).payload) as *libc::c_void, vp);")) class CGSpecializedGetter(CGAbstractExternMethod): """ @@ -3289,7 +3289,7 @@ class CGGenericSetter(CGAbstractBindingMethod): "let undef = JSVAL_VOID;\n" "let argv: *JSVal = if argc != 0 { JS_ARGV(cx, cast::transmute(vp)) } else { &undef as *JSVal };\n" "let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, cast::transmute(vp)));\n" - "if CallJitPropertyOp(info, cx, obj, ptr::to_unsafe_ptr(&(*this).payload) as *libc::c_void, cast::transmute(vp)) == 0 {" + "if CallJitPropertyOp(info, cx, obj, ptr::to_unsafe_ptr(&(*this).payload) as *libc::c_void, argv) == 0 {" " return 0;\n" "}\n" "*vp = JSVAL_VOID;\n" @@ -3555,10 +3555,33 @@ class CGProxyIndexedGetter(CGProxySpecialOperation): self.templateValues = templateValues CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter') +class CGProxyIndexedSetter(CGProxySpecialOperation): + """ + Class to generate a call to an indexed setter. + """ + def __init__(self, descriptor): + CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter') + +class CGProxyNamedGetter(CGProxySpecialOperation): + """ + Class to generate a call to an named getter. If templateValues is not None + the returned value will be wrapped with wrapForType using templateValues. + """ + def __init__(self, descriptor, templateValues=None): + self.templateValues = templateValues + CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter') + +class CGProxyNamedSetter(CGProxySpecialOperation): + """ + Class to generate a call to a named setter. + """ + def __init__(self, descriptor): + CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter') + class CGProxyUnwrap(CGAbstractMethod): def __init__(self, descriptor): args = [Argument('*JSObject', 'obj')] - CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*' + descriptor.nativeType, args, alwaysInline=True) + CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*' + descriptor.concreteType, args, alwaysInline=True) def declare(self): return "" def definition_body(self): @@ -3567,7 +3590,241 @@ class CGProxyUnwrap(CGAbstractMethod): }*/ //MOZ_ASSERT(IsProxy(obj)); let box: *rust_box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj))); - return ptr::to_unsafe_ptr(&(*box).payload);""" % (self.descriptor.nativeType) + return ptr::to_unsafe_ptr(&(*box).payload);""" % (self.descriptor.concreteType) + +class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): + def __init__(self, descriptor): + args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'), + Argument('jsid', 'id'), Argument('JSBool', 'set'), + Argument('*mut JSPropertyDescriptor', 'desc')] + CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor", + "JSBool", args) + self.descriptor = descriptor + def getBody(self): + indexedGetter = self.descriptor.operations['IndexedGetter'] + indexedSetter = self.descriptor.operations['IndexedSetter'] + + setOrIndexedGet = "" + if indexedGetter or indexedSetter: + setOrIndexedGet += "let index = GetArrayIndexFromId(cx, id);\n" + + if indexedGetter: + readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None) + fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn 1;" % readonly + templateValues = {'jsvalRef': '(*desc).value', 'jsvalPtr': 'ptr::to_mut_unsafe_ptr(&mut (*desc).value)', + 'obj': 'proxy', 'successCode': fillDescriptor} + get = ("if index.is_some() {\n" + + " let index = index.get();\n" + + " let this: *%s = UnwrapProxy(proxy);\n" + + CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" + + "}\n") % (self.descriptor.concreteType) + + if indexedSetter or self.descriptor.operations['NamedSetter']: + setOrIndexedGet += "if set != 0 {\n" + if indexedSetter: + setOrIndexedGet += (" if index.is_some() {\n" + + " let index = index.get();\n") + if not 'IndexedCreator' in self.descriptor.operations: + # FIXME need to check that this is a 'supported property index' + assert False + setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, proxy, JSVAL_VOID, false);\n" + + " return 1;\n" + + " }\n") + if self.descriptor.operations['NamedSetter']: + setOrIndexedGet += " if RUST_JSID_IS_STRING(id) {\n" + if not 'NamedCreator' in self.descriptor.operations: + # FIXME need to check that this is a 'supported property name' + assert False + setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, proxy, JSVAL_VOID, false);\n" + + " return 1;\n" + + " }\n") + setOrIndexedGet += "}" + if indexedGetter: + setOrIndexedGet += (" else {\n" + + CGIndenter(CGGeneric(get)).define() + + "}") + setOrIndexedGet += "\n\n" + elif indexedGetter: + setOrIndexedGet += ("if set == 0 {\n" + + CGIndenter(CGGeneric(get)).define() + + "}\n\n") + + namedGetter = self.descriptor.operations['NamedGetter'] + if namedGetter: + readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None) + fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn 1;" % readonly + templateValues = {'jsvalRef': '(*desc).value', 'jsvalPtr': 'ptr::to_unsafe_ptr(&(*desc).value)', + 'obj': 'proxy', 'successCode': fillDescriptor} + # Once we start supporting OverrideBuiltins we need to make + # ResolveOwnProperty or EnumerateOwnProperties filter out named + # properties that shadow prototype properties. + namedGet = ("\n" + + "if set == 0 && RUST_JSID_IS_STRING(id) != 0 && !HasPropertyOnPrototype(cx, proxy, id) {\n" + + " let nameVal = RUST_STRING_TO_JSVAL(RUST_JSID_TO_STRING(id));\n" + + " //FakeDependentString name;\n" + " //if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + + " // eStringify, eStringify, name)) {\n" + + " let strval = jsval_to_str(cx, nameVal);\n" + + " if strval.is_err() {\n" + + " return 0;\n" + + " }\n" + + " let name = str(strval.get());\n" + + "\n" + + " let this: *%s = UnwrapProxy(proxy);\n" + + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" + + "}\n") % (self.descriptor.concreteType) + else: + namedGet = "" + + return setOrIndexedGet + """let expando: *JSObject = GetExpandoObject(proxy); +//if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { +if expando.is_not_null() { + let flags = if set != 0 { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED; + if JS_GetPropertyDescriptorById(cx, expando, id, flags, desc as *JSPropertyDescriptor) == 0 { + return 0; + } + if (*desc).obj.is_not_null() { + // Pretend the property lives on the wrapper. + (*desc).obj = proxy; + return 1; + } +} +""" + namedGet + """ +(*desc).obj = ptr::null(); +return 1;""" + + def definition_body(self): + return self.getBody() + +class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): + def __init__(self, descriptor): + args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'), + Argument('jsid', 'id'), + Argument('*JSPropertyDescriptor', 'desc')] + CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args) + self.descriptor = descriptor + def getBody(self): + set = "" + + indexedSetter = self.descriptor.operations['IndexedSetter'] + if indexedSetter: + if not (self.descriptor.operations['IndexedCreator'] is indexedSetter): + raise TypeError("Can't handle creator that's different from the setter") + set += ("let index = GetArrayIndexFromId(cx, id);\n" + + "if index.is_some() {\n" + + " let index = index.get();\n" + + " let this: *%s = UnwrapProxy(proxy);\n" + + CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() + + " return 1;\n" + + "}\n") % (self.descriptor.concreteType) + elif self.descriptor.operations['IndexedGetter']: + set += ("if GetArrayIndexFromId(cx, id).is_some() {\n" + + " return 0;\n" + + " //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" + + "}\n") % self.descriptor.name + + namedSetter = self.descriptor.operations['NamedSetter'] + if namedSetter: + if not self.descriptor.operations['NamedCreator'] is namedSetter: + raise TypeError("Can't handle creator that's different from the setter") + #XXXjdm need to properly support eStringify + set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" + + " let nameVal: JSVal = RUST_STRING_TO_JSVAL(RUST_JSID_TO_STRING(id));\n" + + " let strval = jsval_to_str(cx, nameVal);\n" + + " //FakeDependentString name;\n" + + " //if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + + " // eStringify, eStringify, name)) {\n" + + " if strval.is_err() {\n" + + " return 0;\n" + + " }\n" + + " let name = str(strval.get());\n" + + "\n" + + " let this: *%s = UnwrapProxy(proxy);\n" + + CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" + + "}\n") % (self.descriptor.concreteType) + elif self.descriptor.operations['NamedGetter']: + set += ("if RUST_JSID_IS_STRING(id) {\n" + + " let nameVal: JSVal = RUST_STRING_TO_JSVAL(RUST_JSID_TO_STRING(id));\n" + + " let strval = jsval_to_str(cx, nameVal);\n" + + " //FakeDependentString name;\n" + " //if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + + " // eStringify, eStringify, name)) {\n" + + " let strval = jsval_to_str(cx, nameVal);\n" + + " if strval.is_err() {\n" + + " return 0;\n" + + " }\n" + + " let name = str(strval.get());\n" + + " let this: %%s = UnwrapProxy(proxy);\n" + + CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + + " if (found) {\n" + " return 0;\n" + + " //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" + + " }\n" + + " return 1;\n" + "}\n") % (self.descriptor.concreteType, self.descriptor.name) + return set + """return proxyhandler::defineProperty(%s);""" % ", ".join(a.name for a in self.args) + + def definition_body(self): + return self.getBody() + +class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): + def __init__(self, descriptor): + args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'), + Argument('jsid', 'id'), Argument('*mut JSBool', 'bp')] + CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "JSBool", args) + self.descriptor = descriptor + def getBody(self): + indexedGetter = self.descriptor.operations['IndexedGetter'] + if indexedGetter: + indexed = ("let index = GetArrayIndexFromId(cx, id);\n" + + "if index.is_some() {\n" + + " let index = index.get();\n" + + " let this: *%s = UnwrapProxy(proxy);\n" + + CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" + + " *bp = found as JSBool;\n" + + " return 1;\n" + + "}\n\n") % (self.descriptor.concreteType) + else: + indexed = "" + + namedGetter = self.descriptor.operations['NamedGetter'] + if namedGetter: + #XXXjdm support eStringify + named = ("if RUST_JSID_IS_STRING(id) != 0 && !HasPropertyOnPrototype(cx, proxy, id) {\n" + + " let nameVal: JSVal = RUST_STRING_TO_JSVAL(RUST_JSID_TO_STRING(id));\n" + + " let strval = jsval_to_str(cx, nameVal);\n" + + " //FakeDependentString name;\n" + " //if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" + + " // eStringify, eStringify, name)) {\n" + + " if strval.is_err() {\n" + + " return 0;\n" + + " }\n" + + " let name = str(strval.get());\n" + + "\n" + + " let this: *%s = UnwrapProxy(proxy);\n" + + CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" + + " *bp = found as JSBool;\n" + " return 1;\n" + "}\n" + + "\n") % (self.descriptor.concreteType) + else: + named = "" + + return indexed + """let expando: *JSObject = GetExpandoObject(proxy); +if expando.is_not_null() { + let b: JSBool = 1; + let ok: JSBool = JS_HasPropertyById(cx, expando, id, &b); + *bp = !!b; + if ok == 0 || *bp != 0 { + return ok; + } +} + +""" + named + """*bp = 0; +return 1;""" + + def definition_body(self): + return self.getBody() class CGDOMJSProxyHandler_get(CGAbstractExternMethod): def __init__(self, descriptor): @@ -3620,7 +3877,7 @@ if expando.is_not_null() { "\n" + " let this = UnwrapProxy(proxy);\n" + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + - "}\n") % (self.descriptor.nativeType) + "}\n") % (self.descriptor.concreteType) else: getNamed = "" @@ -3773,8 +4030,8 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod): def generate_code(self): return """ if (!vp.isObject()) { - *bp = false; - return true; + *bp = 0; + return 1; } jsval protov; @@ -3931,8 +4188,13 @@ class CGDescriptor(CGThing): #cgThings.append(CGProxyIsProxy(descriptor)) cgThings.append(CGProxyUnwrap(descriptor)) cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor)) + cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)) cgThings.append(CGDOMJSProxyHandler_obj_toString(descriptor)) cgThings.append(CGDOMJSProxyHandler_get(descriptor)) + cgThings.append(CGDOMJSProxyHandler_hasOwn(descriptor)) + if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']: + cgThings.append(CGDOMJSProxyHandler_defineProperty(descriptor)) + #cgThings.append(CGDOMJSProxyHandler(descriptor)) #cgThings.append(CGIsMethod(descriptor)) pass diff --git a/src/components/script/dom/bindings/codegen/Configuration.py b/src/components/script/dom/bindings/codegen/Configuration.py index 46e16fdc37c..cf2c13b504e 100644 --- a/src/components/script/dom/bindings/codegen/Configuration.py +++ b/src/components/script/dom/bindings/codegen/Configuration.py @@ -140,6 +140,7 @@ class Descriptor(DescriptorProvider): self.nativeType = desc.get('nativeType', nativeTypeDefault) self.pointerType = desc.get('pointerType', '@mut ') + self.concreteType = desc.get('concreteType', ifaceName) self.hasInstanceInterface = desc.get('hasInstanceInterface', None) # Do something sane for JSObject diff --git a/src/components/script/dom/bindings/proxyhandler.rs b/src/components/script/dom/bindings/proxyhandler.rs index cbbc4f1525d..fef04d6fee9 100644 --- a/src/components/script/dom/bindings/proxyhandler.rs +++ b/src/components/script/dom/bindings/proxyhandler.rs @@ -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; + + let expando = EnsureExpandoObject(cx, proxy); + if expando.is_null() { + return 0; } - } - (*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) + 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; } diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs index 40f0f89ee4d..d55eb9869e4 100644 --- a/src/components/script/dom/bindings/utils.rs +++ b/src/components/script/dom/bindings/utils.rs @@ -120,7 +120,7 @@ fn is_dom_class(clasp: *JSClass) -> bool { } } -fn is_dom_proxy(obj: *JSObject) -> bool { +pub fn is_dom_proxy(obj: *JSObject) -> bool { unsafe { (js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) && IsProxyHandlerFamily(obj) @@ -888,3 +888,9 @@ pub fn FindEnumStringIndex(cx: *JSContext, return Err(()); //XXX pass in behaviour for value not found } } + +pub fn HasPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid) -> bool { + // MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler); + let mut found = false; + return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found; +} diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index 69a02deec71..06012ba7502 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::DocumentBinding; -use dom::bindings::utils::{DOMString, WrapperCache, ErrorResult, null_string}; +use dom::bindings::utils::{DOMString, WrapperCache, ErrorResult, null_string, str}; use dom::bindings::utils::{BindingObject, CacheableWrapper, rust_box, DerivedWrapper}; use dom::element::{HTMLHtmlElement, HTMLHtmlElementTypeId, Element}; use dom::event::Event; @@ -89,7 +89,8 @@ pub struct Document { root: AbstractNode<ScriptView>, wrapper: WrapperCache, window: Option<@mut Window>, - doctype: DocumentType + doctype: DocumentType, + title: ~str } impl Document { @@ -106,7 +107,8 @@ impl Document { root: root, wrapper: WrapperCache::new(), window: window, - doctype: doctype + doctype: doctype, + title: ~"" } } @@ -283,10 +285,14 @@ impl Document { } pub fn Title(&self) -> DOMString { - null_string + str(self.title.clone()) } - pub fn SetTitle(&self, _title: &DOMString, _rv: &mut ErrorResult) { + pub fn SetTitle(&mut self, title: &DOMString, _rv: &mut ErrorResult) { + self.title = match title { + &str(ref s) => s.clone(), + &null_string => ~"" + }; } pub fn Dir(&self) -> DOMString { diff --git a/src/components/script/dom/htmlcollection.rs b/src/components/script/dom/htmlcollection.rs index ac0b66291d3..db668d70e64 100644 --- a/src/components/script/dom/htmlcollection.rs +++ b/src/components/script/dom/htmlcollection.rs @@ -53,6 +53,10 @@ impl HTMLCollection { *found = true; self.Item(index) } + + pub fn NamedGetter(&self, _cx: *JSContext, _name: &DOMString, _found: &mut bool, _rv: &mut ErrorResult) -> *JSObject { + ptr::null() + } } impl BindingObject for HTMLCollection { diff --git a/src/components/script/dom/htmldocument.rs b/src/components/script/dom/htmldocument.rs index 5cbb02b4b9b..619390352f8 100644 --- a/src/components/script/dom/htmldocument.rs +++ b/src/components/script/dom/htmldocument.rs @@ -49,6 +49,10 @@ impl WrappableDocument for HTMLDocument { } impl HTMLDocument { + pub fn NamedGetter(&self, _cx: *JSContext, _name: &DOMString, _found: &mut bool, _rv: &mut ErrorResult) -> *JSObject { + ptr::null() + } + pub fn GetDomain(&self, _rv: &mut ErrorResult) -> DOMString { null_string } diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index dc5665eb79a..3f8339f913d 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -117,6 +117,10 @@ impl Window { pub fn ShowModalDialog(&self, _cx: *JSContext, _url: &DOMString, _argument: JSVal) -> JSVal { JSVAL_NULL } + + pub fn NamedGetter(&self, _cx: *JSContext, _name: &DOMString, _found: &mut bool) -> *JSObject { + ptr::null() + } } impl CacheableWrapper for Window { diff --git a/src/support/spidermonkey/rust-mozjs b/src/support/spidermonkey/rust-mozjs -Subproject df2b9ae514ba76c616e7f58d9de0da545512cfe +Subproject 70f74ad3ff1e6a83737569a9520a4b68e740578 diff --git a/src/test/html/test_bindings.js b/src/test/html/test_bindings.js index a7cbb9c6c46..b0338dc0751 100644 --- a/src/test/html/test_bindings.js +++ b/src/test/html/test_bindings.js @@ -120,6 +120,10 @@ window.alert(ev2.getModifierState("ctrl")); window.alert(ev2 instanceof Event); window.alert(ev2 instanceof UIEvent); +window.alert(document.title); +document.title = "foo"; +window.alert(document.title); + //TODO: Doesn't work until we throw proper exceptions instead of returning 0 on // unwrap failure. /*try { |