mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Merge generic funs to share them across all bindings (fixes #2684)
This commit is contained in:
parent
e7808c526c
commit
a90983553b
5 changed files with 185 additions and 200 deletions
|
@ -1441,7 +1441,7 @@ class MethodDefiner(PropertyDefiner):
|
||||||
if m.get("methodInfo", True):
|
if m.get("methodInfo", True):
|
||||||
identifier = m.get("nativeName", m["name"])
|
identifier = m.get("nativeName", m["name"])
|
||||||
jitinfo = "&%s_methodinfo" % identifier
|
jitinfo = "&%s_methodinfo" % identifier
|
||||||
accessor = "Some(genericMethod)"
|
accessor = "Some(generic_method)"
|
||||||
else:
|
else:
|
||||||
jitinfo = "0 as *const JSJitInfo"
|
jitinfo = "0 as *const JSJitInfo"
|
||||||
accessor = 'Some(%s)' % m.get("nativeName", m["name"])
|
accessor = 'Some(%s)' % m.get("nativeName", m["name"])
|
||||||
|
@ -1481,9 +1481,9 @@ class AttrDefiner(PropertyDefiner):
|
||||||
jitinfo = "0 as *const JSJitInfo"
|
jitinfo = "0 as *const JSJitInfo"
|
||||||
else:
|
else:
|
||||||
if attr.hasLenientThis():
|
if attr.hasLenientThis():
|
||||||
accessor = "genericLenientGetter"
|
accessor = "generic_lenient_getter"
|
||||||
else:
|
else:
|
||||||
accessor = "genericGetter"
|
accessor = "generic_getter"
|
||||||
jitinfo = "&%s_getterinfo" % attr.identifier.name
|
jitinfo = "&%s_getterinfo" % attr.identifier.name
|
||||||
|
|
||||||
return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
|
return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
|
||||||
|
@ -1499,9 +1499,9 @@ class AttrDefiner(PropertyDefiner):
|
||||||
jitinfo = "0 as *const JSJitInfo"
|
jitinfo = "0 as *const JSJitInfo"
|
||||||
else:
|
else:
|
||||||
if attr.hasLenientThis():
|
if attr.hasLenientThis():
|
||||||
accessor = "genericLenientSetter"
|
accessor = "generic_lenient_setter"
|
||||||
else:
|
else:
|
||||||
accessor = "genericSetter"
|
accessor = "generic_setter"
|
||||||
jitinfo = "&%s_setterinfo" % attr.identifier.name
|
jitinfo = "&%s_setterinfo" % attr.identifier.name
|
||||||
|
|
||||||
return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
|
return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
|
||||||
|
@ -2696,52 +2696,6 @@ class CGSetterCall(CGPerSignatureCall):
|
||||||
# We just get our stuff from our last arg no matter what
|
# We just get our stuff from our last arg no matter what
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
class CGAbstractBindingMethod(CGAbstractExternMethod):
|
|
||||||
"""
|
|
||||||
Common class to generate the JSNatives for all our methods, getters, and
|
|
||||||
setters. This will generate the function declaration and unwrap the
|
|
||||||
|this| object. Subclasses are expected to override the generate_code
|
|
||||||
function to do the rest of the work. This function should return a
|
|
||||||
CGThing which is already properly indented.
|
|
||||||
"""
|
|
||||||
def __init__(self, descriptor, name, args, unwrapFailureCode=None):
|
|
||||||
CGAbstractExternMethod.__init__(self, descriptor, name, "u8", args)
|
|
||||||
|
|
||||||
if unwrapFailureCode is None:
|
|
||||||
self.unwrapFailureCode = (
|
|
||||||
'throw_type_error(cx, "\\"this\\" object does not '
|
|
||||||
'implement interface %s.");\n'
|
|
||||||
'return 0;' % descriptor.interface.identifier.name)
|
|
||||||
else:
|
|
||||||
self.unwrapFailureCode = unwrapFailureCode
|
|
||||||
|
|
||||||
def definition_body(self):
|
|
||||||
# Our descriptor might claim that we're not castable, simply because
|
|
||||||
# we're someone's consequential interface. But for this-unwrapping, we
|
|
||||||
# know that we're the real deal. So fake a descriptor here for
|
|
||||||
# consumption by FailureFatalCastableObjectUnwrapper.
|
|
||||||
unwrapThis = str(CastableObjectUnwrapper(
|
|
||||||
FakeCastableDescriptor(self.descriptor),
|
|
||||||
"obj.handle()", self.unwrapFailureCode, "object"))
|
|
||||||
unwrapThis = CGGeneric(
|
|
||||||
"let args = CallArgs::from_vp(vp, argc);\n"
|
|
||||||
"let thisobj = args.thisv();\n"
|
|
||||||
"if !thisobj.get().is_null_or_undefined() && !thisobj.get().is_object() {\n"
|
|
||||||
" return JSFalse;\n"
|
|
||||||
"}\n"
|
|
||||||
"let obj = if thisobj.get().is_object() {\n"
|
|
||||||
" RootedObject::new(cx, thisobj.get().to_object())\n"
|
|
||||||
"} else {\n"
|
|
||||||
" RootedObject::new(cx, GetGlobalForObjectCrossCompartment(JS_CALLEE(cx, vp).to_object_or_null()))\n"
|
|
||||||
"};\n"
|
|
||||||
"\n"
|
|
||||||
"let this: Root<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis))
|
|
||||||
return CGList([ unwrapThis, self.generate_code() ], "\n")
|
|
||||||
|
|
||||||
def generate_code(self):
|
|
||||||
assert(False) # Override me
|
|
||||||
|
|
||||||
|
|
||||||
class CGAbstractStaticBindingMethod(CGAbstractMethod):
|
class CGAbstractStaticBindingMethod(CGAbstractMethod):
|
||||||
"""
|
"""
|
||||||
Common class to generate the JSNatives for all our static methods, getters
|
Common class to generate the JSNatives for all our static methods, getters
|
||||||
|
@ -2767,21 +2721,6 @@ let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
|
||||||
def generate_code(self):
|
def generate_code(self):
|
||||||
assert False # Override me
|
assert False # Override me
|
||||||
|
|
||||||
|
|
||||||
class CGGenericMethod(CGAbstractBindingMethod):
|
|
||||||
"""
|
|
||||||
A class for generating the C++ code for an IDL method..
|
|
||||||
"""
|
|
||||||
def __init__(self, descriptor):
|
|
||||||
args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
|
|
||||||
Argument('*mut JSVal', 'vp')]
|
|
||||||
CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args)
|
|
||||||
|
|
||||||
def generate_code(self):
|
|
||||||
return CGGeneric(
|
|
||||||
"let _info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
|
|
||||||
"return CallJitMethodOp(_info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);")
|
|
||||||
|
|
||||||
class CGSpecializedMethod(CGAbstractExternMethod):
|
class CGSpecializedMethod(CGAbstractExternMethod):
|
||||||
"""
|
"""
|
||||||
A class for generating the C++ code for a specialized method that the JIT
|
A class for generating the C++ code for a specialized method that the JIT
|
||||||
|
@ -2825,30 +2764,6 @@ class CGStaticMethod(CGAbstractStaticBindingMethod):
|
||||||
call = CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method)
|
call = CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method)
|
||||||
return CGList([setupArgs, call])
|
return CGList([setupArgs, call])
|
||||||
|
|
||||||
class CGGenericGetter(CGAbstractBindingMethod):
|
|
||||||
"""
|
|
||||||
A class for generating the C++ code for an IDL attribute getter.
|
|
||||||
"""
|
|
||||||
def __init__(self, descriptor, lenientThis=False):
|
|
||||||
args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
|
|
||||||
Argument('*mut JSVal', 'vp')]
|
|
||||||
if lenientThis:
|
|
||||||
name = "genericLenientGetter"
|
|
||||||
unwrapFailureCode = (
|
|
||||||
"assert!(JS_IsExceptionPending(cx) == 0);\n"
|
|
||||||
"*vp = UndefinedValue();\n"
|
|
||||||
"return 1;")
|
|
||||||
else:
|
|
||||||
name = "genericGetter"
|
|
||||||
unwrapFailureCode = None
|
|
||||||
CGAbstractBindingMethod.__init__(self, descriptor, name, args,
|
|
||||||
unwrapFailureCode)
|
|
||||||
|
|
||||||
def generate_code(self):
|
|
||||||
return CGGeneric(
|
|
||||||
"let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
|
|
||||||
"return CallJitGetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);")
|
|
||||||
|
|
||||||
class CGSpecializedGetter(CGAbstractExternMethod):
|
class CGSpecializedGetter(CGAbstractExternMethod):
|
||||||
"""
|
"""
|
||||||
A class for generating the code for a specialized attribute getter
|
A class for generating the code for a specialized attribute getter
|
||||||
|
@ -2900,34 +2815,6 @@ class CGStaticGetter(CGAbstractStaticBindingMethod):
|
||||||
self.attr)
|
self.attr)
|
||||||
return CGList([setupArgs, call])
|
return CGList([setupArgs, call])
|
||||||
|
|
||||||
|
|
||||||
class CGGenericSetter(CGAbstractBindingMethod):
|
|
||||||
"""
|
|
||||||
A class for generating the Rust code for an IDL attribute setter.
|
|
||||||
"""
|
|
||||||
def __init__(self, descriptor, lenientThis=False):
|
|
||||||
args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
|
|
||||||
Argument('*mut JSVal', 'vp')]
|
|
||||||
if lenientThis:
|
|
||||||
name = "genericLenientSetter"
|
|
||||||
unwrapFailureCode = (
|
|
||||||
"assert!(JS_IsExceptionPending(cx) == 0);\n"
|
|
||||||
"return 1;")
|
|
||||||
else:
|
|
||||||
name = "genericSetter"
|
|
||||||
unwrapFailureCode = None
|
|
||||||
CGAbstractBindingMethod.__init__(self, descriptor, name, args,
|
|
||||||
unwrapFailureCode)
|
|
||||||
|
|
||||||
def generate_code(self):
|
|
||||||
return CGGeneric(
|
|
||||||
"let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
|
|
||||||
"if CallJitSetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp) == 0 {\n"
|
|
||||||
" return 0;\n"
|
|
||||||
"}\n"
|
|
||||||
"*vp = UndefinedValue();\n"
|
|
||||||
"return 1;")
|
|
||||||
|
|
||||||
class CGSpecializedSetter(CGAbstractExternMethod):
|
class CGSpecializedSetter(CGAbstractExternMethod):
|
||||||
"""
|
"""
|
||||||
A class for generating the code for a specialized attribute setter
|
A class for generating the code for a specialized attribute setter
|
||||||
|
@ -4641,8 +4528,6 @@ class CGDescriptor(CGThing):
|
||||||
# cgThings.append(CGGetConstructorObjectMethod(descriptor))
|
# cgThings.append(CGGetConstructorObjectMethod(descriptor))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
(hasMethod, hasGetter, hasLenientGetter,
|
|
||||||
hasSetter, hasLenientSetter) = False, False, False, False, False
|
|
||||||
for m in descriptor.interface.members:
|
for m in descriptor.interface.members:
|
||||||
if (m.isMethod() and
|
if (m.isMethod() and
|
||||||
(not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
|
(not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
|
||||||
|
@ -4652,7 +4537,6 @@ class CGDescriptor(CGThing):
|
||||||
elif not descriptor.interface.isCallback():
|
elif not descriptor.interface.isCallback():
|
||||||
cgThings.append(CGSpecializedMethod(descriptor, m))
|
cgThings.append(CGSpecializedMethod(descriptor, m))
|
||||||
cgThings.append(CGMemberJITInfo(descriptor, m))
|
cgThings.append(CGMemberJITInfo(descriptor, m))
|
||||||
hasMethod = True
|
|
||||||
elif m.isAttr():
|
elif m.isAttr():
|
||||||
if m.stringifier:
|
if m.stringifier:
|
||||||
raise TypeError("Stringifier attributes not supported yet. "
|
raise TypeError("Stringifier attributes not supported yet. "
|
||||||
|
@ -4664,10 +4548,6 @@ class CGDescriptor(CGThing):
|
||||||
cgThings.append(CGStaticGetter(descriptor, m))
|
cgThings.append(CGStaticGetter(descriptor, m))
|
||||||
elif not descriptor.interface.isCallback():
|
elif not descriptor.interface.isCallback():
|
||||||
cgThings.append(CGSpecializedGetter(descriptor, m))
|
cgThings.append(CGSpecializedGetter(descriptor, m))
|
||||||
if m.hasLenientThis():
|
|
||||||
hasLenientGetter = True
|
|
||||||
else:
|
|
||||||
hasGetter = True
|
|
||||||
|
|
||||||
if not m.readonly:
|
if not m.readonly:
|
||||||
if m.isStatic():
|
if m.isStatic():
|
||||||
|
@ -4675,27 +4555,12 @@ class CGDescriptor(CGThing):
|
||||||
cgThings.append(CGStaticSetter(descriptor, m))
|
cgThings.append(CGStaticSetter(descriptor, m))
|
||||||
elif not descriptor.interface.isCallback():
|
elif not descriptor.interface.isCallback():
|
||||||
cgThings.append(CGSpecializedSetter(descriptor, m))
|
cgThings.append(CGSpecializedSetter(descriptor, m))
|
||||||
if m.hasLenientThis():
|
|
||||||
hasLenientSetter = True
|
|
||||||
else:
|
|
||||||
hasSetter = True
|
|
||||||
elif m.getExtendedAttribute("PutForwards"):
|
elif m.getExtendedAttribute("PutForwards"):
|
||||||
cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
|
cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
|
||||||
hasSetter = True
|
|
||||||
|
|
||||||
if (not m.isStatic() and
|
if (not m.isStatic() and
|
||||||
not descriptor.interface.isCallback()):
|
not descriptor.interface.isCallback()):
|
||||||
cgThings.append(CGMemberJITInfo(descriptor, m))
|
cgThings.append(CGMemberJITInfo(descriptor, m))
|
||||||
if hasMethod:
|
|
||||||
cgThings.append(CGGenericMethod(descriptor))
|
|
||||||
if hasGetter:
|
|
||||||
cgThings.append(CGGenericGetter(descriptor))
|
|
||||||
if hasLenientGetter:
|
|
||||||
cgThings.append(CGGenericGetter(descriptor, lenientThis=True))
|
|
||||||
if hasSetter:
|
|
||||||
cgThings.append(CGGenericSetter(descriptor))
|
|
||||||
if hasLenientSetter:
|
|
||||||
cgThings.append(CGGenericSetter(descriptor, lenientThis=True))
|
|
||||||
|
|
||||||
if descriptor.concrete:
|
if descriptor.concrete:
|
||||||
cgThings.append(CGClassFinalizeHook(descriptor))
|
cgThings.append(CGClassFinalizeHook(descriptor))
|
||||||
|
@ -5128,6 +4993,9 @@ class CGBindingRoot(CGThing):
|
||||||
'dom::bindings::utils::{NativeProperties, NativePropertyHooks}',
|
'dom::bindings::utils::{NativeProperties, NativePropertyHooks}',
|
||||||
'dom::bindings::utils::ConstantVal::{IntVal, UintVal}',
|
'dom::bindings::utils::ConstantVal::{IntVal, UintVal}',
|
||||||
'dom::bindings::utils::NonNullJSNative',
|
'dom::bindings::utils::NonNullJSNative',
|
||||||
|
'dom::bindings::utils::{generic_getter, generic_lenient_getter}',
|
||||||
|
'dom::bindings::utils::{generic_lenient_setter, generic_method}',
|
||||||
|
'dom::bindings::utils::generic_setter',
|
||||||
'dom::bindings::trace::{JSTraceable, RootedTraceable}',
|
'dom::bindings::trace::{JSTraceable, RootedTraceable}',
|
||||||
'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
|
'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
|
||||||
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
|
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
|
||||||
|
@ -5756,6 +5624,15 @@ class GlobalGenRoots():
|
||||||
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
|
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
|
||||||
CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength),
|
CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength),
|
||||||
CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone", repr="u16"),
|
CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone", repr="u16"),
|
||||||
|
CGWrapper(CGIndenter(CGList([CGGeneric('"' + name + '"') for name in protos],
|
||||||
|
",\n"),
|
||||||
|
indentLevel=4),
|
||||||
|
pre="static INTERFACES: [&'static str; %d] = [\n" % len(protos),
|
||||||
|
post="\n];\n\n"),
|
||||||
|
CGGeneric("pub fn proto_id_to_name(proto_id: u16) -> &'static str {\n"
|
||||||
|
" debug_assert!(proto_id < ID::Count as u16);\n"
|
||||||
|
" INTERFACES[proto_id as usize]\n"
|
||||||
|
"}\n\n"),
|
||||||
CGNonNamespacedEnum('Proxies', proxies, [0], deriving="PartialEq, Copy, Clone"),
|
CGNonNamespacedEnum('Proxies', proxies, [0], deriving="PartialEq, Copy, Clone"),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
|
@ -41,17 +41,16 @@ use dom::bindings::utils::{Reflectable, Reflector, DOMClass};
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
use js;
|
use js;
|
||||||
use js::glue::{RUST_JSID_TO_STRING, RUST_JSID_IS_STRING};
|
use js::glue::{GetProxyPrivate, IsWrapper, RUST_JS_NumberValue};
|
||||||
use js::glue::RUST_JS_NumberValue;
|
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject};
|
||||||
use js::rust::{ToUint64, ToInt64};
|
use js::rust::{ToUint64, ToInt64};
|
||||||
use js::rust::{ToUint32, ToInt32};
|
use js::rust::{ToUint32, ToInt32};
|
||||||
use js::rust::{ToUint16, ToNumber, ToBoolean, ToString};
|
use js::rust::{ToUint16, ToNumber, ToBoolean, ToString};
|
||||||
use js::jsapi::{JSContext, JSObject, JSString};
|
use js::jsapi::{HandleId, HandleObject, HandleValue, JS_GetClass};
|
||||||
use js::jsapi::{JS_StringHasLatin1Chars, JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength};
|
use js::jsapi::{JS_GetLatin1StringCharsAndLength, JS_GetReservedSlot};
|
||||||
use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN};
|
use js::jsapi::{JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN};
|
||||||
use js::jsapi::{JS_WrapValue};
|
use js::jsapi::{JS_NewUCStringCopyN, JS_StringHasLatin1Chars, JS_WrapValue};
|
||||||
use js::jsapi::{JSClass, JS_GetClass};
|
use js::jsapi::{JSClass, JSContext, JSObject, JSString, MutableHandleValue};
|
||||||
use js::jsapi::{HandleId, HandleValue, HandleObject, MutableHandleValue};
|
|
||||||
use js::jsval::JSVal;
|
use js::jsval::JSVal;
|
||||||
use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value};
|
use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value};
|
||||||
use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};
|
use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};
|
||||||
|
@ -504,25 +503,27 @@ pub fn is_dom_proxy(obj: *mut JSObject) -> bool {
|
||||||
// globals and non-globals.
|
// globals and non-globals.
|
||||||
pub const DOM_OBJECT_SLOT: u32 = 0;
|
pub const DOM_OBJECT_SLOT: u32 = 0;
|
||||||
|
|
||||||
/// Get the DOM object from the given reflector.
|
/// Get the private pointer of a DOM object from a given reflector.
|
||||||
pub unsafe fn native_from_reflector<T>(obj: *mut JSObject) -> *const T {
|
unsafe fn private_from_reflector(obj: *mut JSObject) -> *const libc::c_void {
|
||||||
use js::jsapi::JS_GetReservedSlot;
|
|
||||||
use js::glue::GetProxyPrivate;
|
|
||||||
|
|
||||||
let clasp = JS_GetClass(obj);
|
let clasp = JS_GetClass(obj);
|
||||||
let value = if is_dom_class(clasp) {
|
let value = if is_dom_class(clasp) {
|
||||||
JS_GetReservedSlot(obj, DOM_OBJECT_SLOT)
|
JS_GetReservedSlot(obj, DOM_OBJECT_SLOT)
|
||||||
} else {
|
} else {
|
||||||
assert!(is_dom_proxy(obj));
|
debug_assert!(is_dom_proxy(obj));
|
||||||
GetProxyPrivate(obj)
|
GetProxyPrivate(obj)
|
||||||
};
|
};
|
||||||
if value.is_undefined() {
|
if value.is_undefined() {
|
||||||
ptr::null()
|
ptr::null()
|
||||||
} else {
|
} else {
|
||||||
value.to_private() as *const T
|
value.to_private()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the DOM object from the given reflector.
|
||||||
|
pub unsafe fn native_from_reflector<T>(obj: *mut JSObject) -> *const T {
|
||||||
|
private_from_reflector(obj) as *const T
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
|
/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
|
||||||
unsafe fn get_dom_class(obj: *mut JSObject) -> Result<DOMClass, ()> {
|
unsafe fn get_dom_class(obj: *mut JSObject) -> Result<DOMClass, ()> {
|
||||||
use dom::bindings::utils::DOMJSClass;
|
use dom::bindings::utils::DOMJSClass;
|
||||||
|
@ -543,47 +544,57 @@ unsafe fn get_dom_class(obj: *mut JSObject) -> Result<DOMClass, ()> {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an `Unrooted<T>` for the given DOM object, unwrapping any wrapper
|
/// Get a `*const libc::c_void` for the given DOM object, unwrapping any
|
||||||
|
/// wrapper around it first, and checking if the object is of the correct type.
|
||||||
|
///
|
||||||
|
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
|
||||||
|
/// not an object for a DOM object of the given type (as defined by the
|
||||||
|
/// proto_id and proto_depth).
|
||||||
|
pub unsafe fn private_from_proto_chain(mut obj: *mut JSObject,
|
||||||
|
proto_id: u16, proto_depth: u16)
|
||||||
|
-> Result<*const libc::c_void, ()> {
|
||||||
|
let dom_class = try!(get_dom_class(obj).or_else(|_| {
|
||||||
|
if IsWrapper(obj) == 1 {
|
||||||
|
debug!("found wrapper");
|
||||||
|
obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
|
||||||
|
if obj.is_null() {
|
||||||
|
debug!("unwrapping security wrapper failed");
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
assert!(IsWrapper(obj) == 0);
|
||||||
|
debug!("unwrapped successfully");
|
||||||
|
get_dom_class(obj)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug!("not a dom wrapper");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
if dom_class.interface_chain[proto_depth as usize] as u16 == proto_id {
|
||||||
|
debug!("good prototype");
|
||||||
|
Ok(private_from_reflector(obj))
|
||||||
|
} else {
|
||||||
|
debug!("bad prototype");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a `Root<T>` for the given DOM object, unwrapping any wrapper
|
||||||
/// around it first, and checking if the object is of the correct type.
|
/// around it first, and checking if the object is of the correct type.
|
||||||
///
|
///
|
||||||
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
|
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
|
||||||
/// not a reflector for a DOM object of the given type (as defined by the
|
/// not a reflector for a DOM object of the given type (as defined by the
|
||||||
/// proto_id and proto_depth).
|
/// proto_id and proto_depth).
|
||||||
pub fn native_from_reflector_jsmanaged<T>(mut obj: *mut JSObject) -> Result<Root<T>, ()>
|
pub fn native_from_reflector_jsmanaged<T>(obj: *mut JSObject) -> Result<Root<T>, ()>
|
||||||
where T: Reflectable + IDLInterface
|
where T: Reflectable + IDLInterface
|
||||||
{
|
{
|
||||||
use js::glue::{IsWrapper, UnwrapObject};
|
let proto_id = <T as IDLInterface>::get_prototype_id() as u16;
|
||||||
|
let proto_depth = <T as IDLInterface>::get_prototype_depth() as u16;
|
||||||
unsafe {
|
unsafe {
|
||||||
let dom_class = try!(get_dom_class(obj).or_else(|_| {
|
private_from_proto_chain(obj, proto_id, proto_depth).map(|obj| {
|
||||||
if IsWrapper(obj) == 1 {
|
Root::new(NonZero::new(obj as *const T))
|
||||||
debug!("found wrapper");
|
})
|
||||||
obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
|
|
||||||
if obj.is_null() {
|
|
||||||
debug!("unwrapping security wrapper failed");
|
|
||||||
Err(())
|
|
||||||
} else {
|
|
||||||
assert!(IsWrapper(obj) == 0);
|
|
||||||
debug!("unwrapped successfully");
|
|
||||||
get_dom_class(obj)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug!("not a dom wrapper");
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
let proto_id = <T as IDLInterface>::get_prototype_id();
|
|
||||||
let proto_depth = <T as IDLInterface>::get_prototype_depth();
|
|
||||||
if dom_class.interface_chain[proto_depth] == proto_id {
|
|
||||||
debug!("good prototype");
|
|
||||||
let native = native_from_reflector(obj);
|
|
||||||
assert!(!native.is_null());
|
|
||||||
Ok(Root::new(NonZero::new(native)))
|
|
||||||
} else {
|
|
||||||
debug!("bad prototype");
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! Utilities to throw exceptions from Rust bindings.
|
//! Utilities to throw exceptions from Rust bindings.
|
||||||
|
|
||||||
|
use dom::bindings::codegen::PrototypeList::proto_id_to_name;
|
||||||
use dom::bindings::conversions::ToJSValConvertible;
|
use dom::bindings::conversions::ToJSValConvertible;
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::domexception::{DOMException, DOMErrorName};
|
use dom::domexception::{DOMException, DOMErrorName};
|
||||||
|
@ -150,6 +151,15 @@ pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) {
|
||||||
throw_type_error(cx, &error);
|
throw_type_error(cx, &error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Throw an exception to signal that a `JSObject` can not be converted to a
|
||||||
|
/// given DOM type.
|
||||||
|
pub fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) {
|
||||||
|
debug_assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
|
||||||
|
let error = format!("\"this\" object does not implement interface {}.",
|
||||||
|
proto_id_to_name(proto_id));
|
||||||
|
throw_type_error(cx, &error);
|
||||||
|
}
|
||||||
|
|
||||||
/// Format string used to throw javascript errors.
|
/// Format string used to throw javascript errors.
|
||||||
static ERROR_FORMAT_STRING_STRING: [libc::c_char; 4] = [
|
static ERROR_FORMAT_STRING_STRING: [libc::c_char; 4] = [
|
||||||
'{' as libc::c_char,
|
'{' as libc::c_char,
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::PrototypeList;
|
use dom::bindings::codegen::PrototypeList;
|
||||||
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
|
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
|
||||||
use dom::bindings::conversions::{native_from_handleobject, is_dom_class, jsstring_to_str};
|
use dom::bindings::conversions::{is_dom_class, jsstring_to_str};
|
||||||
use dom::bindings::error::{Error, ErrorResult, Fallible, throw_type_error};
|
use dom::bindings::conversions::native_from_handleobject;
|
||||||
|
use dom::bindings::conversions::private_from_proto_chain;
|
||||||
|
use dom::bindings::error::{Error, ErrorResult, Fallible, throw_invalid_this};
|
||||||
|
use dom::bindings::error::throw_type_error;
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::js::Root;
|
||||||
use dom::bindings::trace::trace_object;
|
use dom::bindings::trace::trace_object;
|
||||||
|
@ -24,8 +27,11 @@ use std::ptr;
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use js::glue::UnwrapObject;
|
use js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, IsWrapper};
|
||||||
use js::glue::{IsWrapper, RUST_JSID_IS_INT, RUST_JSID_TO_INT};
|
use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT};
|
||||||
|
use js::glue::{RUST_JSID_TO_INT, UnwrapObject};
|
||||||
|
use js::jsapi::{CallArgs, GetGlobalForObjectCrossCompartment, JSJitInfo};
|
||||||
|
use js::jsapi::JS_IsExceptionPending;
|
||||||
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction, JSTraceOp};
|
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction, JSTraceOp};
|
||||||
use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo};
|
use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo};
|
||||||
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
|
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
|
||||||
|
@ -47,13 +53,12 @@ use js::jsapi::{ObjectOpResult, RootedObject, RootedValue, Heap, MutableHandleOb
|
||||||
use js::jsapi::PropertyDefinitionBehavior;
|
use js::jsapi::PropertyDefinitionBehavior;
|
||||||
use js::jsapi::JSAutoCompartment;
|
use js::jsapi::JSAutoCompartment;
|
||||||
use js::jsapi::{DOMCallbacks, JSWrapObjectCallbacks};
|
use js::jsapi::{DOMCallbacks, JSWrapObjectCallbacks};
|
||||||
use js::jsval::JSVal;
|
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue};
|
||||||
use js::jsval::{PrivateValue, NullValue};
|
use js::jsval::{PrivateValue, UInt32Value, UndefinedValue};
|
||||||
use js::jsval::{Int32Value, UInt32Value, DoubleValue, BooleanValue};
|
|
||||||
use js::rust::{GCMethods, ToString};
|
use js::rust::{GCMethods, ToString};
|
||||||
use js::glue::{WrapperNew, GetCrossCompartmentWrapper};
|
use js::glue::{WrapperNew, GetCrossCompartmentWrapper};
|
||||||
use js::{JSPROP_ENUMERATE, JSPROP_READONLY, JSPROP_PERMANENT};
|
use js::{JS_ARGV, JS_CALLEE, JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE};
|
||||||
use js::JSFUN_CONSTRUCTOR;
|
use js::{JSPROP_PERMANENT, JSPROP_READONLY};
|
||||||
use js;
|
use js;
|
||||||
use string_cache::{Atom, Namespace};
|
use string_cache::{Atom, Namespace};
|
||||||
|
|
||||||
|
@ -670,6 +675,91 @@ pub unsafe fn delete_property_by_id(cx: *mut JSContext, object: HandleObject,
|
||||||
JS_DeletePropertyById1(cx, object, id, bp)
|
JS_DeletePropertyById1(cx, object, id, bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn generic_call(cx: *mut JSContext, argc: libc::c_uint, vp: *mut JSVal,
|
||||||
|
is_lenient: bool,
|
||||||
|
call: unsafe extern fn(*const JSJitInfo, *mut JSContext,
|
||||||
|
HandleObject, *mut libc::c_void, u32,
|
||||||
|
*mut JSVal)
|
||||||
|
-> u8)
|
||||||
|
-> u8 {
|
||||||
|
let args = CallArgs::from_vp(vp, argc);
|
||||||
|
let thisobj = args.thisv();
|
||||||
|
if !thisobj.get().is_null_or_undefined() && !thisobj.get().is_object() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let obj = if thisobj.get().is_object() {
|
||||||
|
thisobj.get().to_object()
|
||||||
|
} else {
|
||||||
|
GetGlobalForObjectCrossCompartment(JS_CALLEE(cx, vp).to_object_or_null())
|
||||||
|
};
|
||||||
|
let obj = RootedObject::new(cx, obj);
|
||||||
|
let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
|
||||||
|
let proto_id = (*info).protoID;
|
||||||
|
let depth = (*info).depth;
|
||||||
|
let this = match private_from_proto_chain(obj.ptr, proto_id, depth) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(()) => {
|
||||||
|
if is_lenient {
|
||||||
|
debug_assert!(JS_IsExceptionPending(cx) == 0);
|
||||||
|
*vp = UndefinedValue();
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
throw_invalid_this(cx, proto_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
call(info, cx, obj.handle(), this as *mut libc::c_void, argc, vp)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic method of IDL interface.
|
||||||
|
pub unsafe extern fn generic_method(cx: *mut JSContext,
|
||||||
|
argc: libc::c_uint, vp: *mut JSVal)
|
||||||
|
-> u8 {
|
||||||
|
generic_call(cx, argc, vp, false, CallJitMethodOp)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic getter of IDL interface.
|
||||||
|
pub unsafe extern fn generic_getter(cx: *mut JSContext,
|
||||||
|
argc: libc::c_uint, vp: *mut JSVal)
|
||||||
|
-> u8 {
|
||||||
|
generic_call(cx, argc, vp, false, CallJitGetterOp)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic lenient getter of IDL interface.
|
||||||
|
pub unsafe extern fn generic_lenient_getter(cx: *mut JSContext,
|
||||||
|
argc: libc::c_uint,
|
||||||
|
vp: *mut JSVal)
|
||||||
|
-> u8 {
|
||||||
|
generic_call(cx, argc, vp, true, CallJitGetterOp)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern fn call_setter(info: *const JSJitInfo, cx: *mut JSContext,
|
||||||
|
handle: HandleObject, this: *mut libc::c_void,
|
||||||
|
argc: u32, vp: *mut JSVal)
|
||||||
|
-> u8 {
|
||||||
|
if CallJitSetterOp(info, cx, handle, this, argc, vp) == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*vp = UndefinedValue();
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic setter of IDL interface.
|
||||||
|
pub unsafe extern fn generic_setter(cx: *mut JSContext,
|
||||||
|
argc: libc::c_uint, vp: *mut JSVal)
|
||||||
|
-> u8 {
|
||||||
|
generic_call(cx, argc, vp, false, call_setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic lenient setter of IDL interface.
|
||||||
|
pub unsafe extern fn generic_lenient_setter(cx: *mut JSContext,
|
||||||
|
argc: libc::c_uint,
|
||||||
|
vp: *mut JSVal)
|
||||||
|
-> u8 {
|
||||||
|
generic_call(cx, argc, vp, true, call_setter)
|
||||||
|
}
|
||||||
|
|
||||||
/// Validate a qualified name. See https://dom.spec.whatwg.org/#validate for details.
|
/// Validate a qualified name. See https://dom.spec.whatwg.org/#validate for details.
|
||||||
pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
|
pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
|
||||||
match xml_name_type(qualified_name) {
|
match xml_name_type(qualified_name) {
|
||||||
|
|
|
@ -57,9 +57,6 @@
|
||||||
[Document interface: attribute commands]
|
[Document interface: attribute commands]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Document interface: attribute onreadystatechange]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Document interface: attribute fgColor]
|
[Document interface: attribute fgColor]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue