mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
DOM bindings: Add support for fallible JS unwrapping.
This commit is contained in:
parent
354ac9b8cb
commit
0d39bd1ba9
3 changed files with 75 additions and 36 deletions
|
@ -94,6 +94,8 @@ class CastableObjectUnwrapper():
|
||||||
assert descriptor.castable
|
assert descriptor.castable
|
||||||
|
|
||||||
self.substitution = { "type" : descriptor.nativeType,
|
self.substitution = { "type" : descriptor.nativeType,
|
||||||
|
"depth": descriptor.interface.inheritanceDepth(),
|
||||||
|
"prototype": "prototypes::id::" + descriptor.name,
|
||||||
"protoID" : "prototypes::id::" + descriptor.name + " as uint",
|
"protoID" : "prototypes::id::" + descriptor.name + " as uint",
|
||||||
"source" : source,
|
"source" : source,
|
||||||
"target" : target,
|
"target" : target,
|
||||||
|
@ -118,8 +120,14 @@ class CastableObjectUnwrapper():
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return string.Template(
|
return string.Template(
|
||||||
"""${target} = unwrap(${source});
|
"""match unwrap_object(${source}, ${prototype}, ${depth}) {
|
||||||
|
Ok(val) => ${target} = val,
|
||||||
|
Err(()) => {
|
||||||
|
${codeOnFailure}
|
||||||
|
}
|
||||||
|
}
|
||||||
""").substitute(self.substitution)
|
""").substitute(self.substitution)
|
||||||
|
|
||||||
#"""{
|
#"""{
|
||||||
# nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
|
# nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
|
||||||
# if (NS_FAILED(rv)) {
|
# if (NS_FAILED(rv)) {
|
||||||
|
@ -133,7 +141,7 @@ class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
|
||||||
"""
|
"""
|
||||||
def __init__(self, descriptor, source, target):
|
def __init__(self, descriptor, source, target):
|
||||||
CastableObjectUnwrapper.__init__(self, descriptor, source, target,
|
CastableObjectUnwrapper.__init__(self, descriptor, source, target,
|
||||||
"return Throw<%s>(cx, rv);" %
|
"return 0; //XXXjdm return Throw<%s>(cx, rv);" %
|
||||||
toStringBool(not descriptor.workers))
|
toStringBool(not descriptor.workers))
|
||||||
|
|
||||||
class CGThing():
|
class CGThing():
|
||||||
|
@ -397,6 +405,10 @@ class FakeCastableDescriptor():
|
||||||
self.pointerType = descriptor.pointerType
|
self.pointerType = descriptor.pointerType
|
||||||
self.name = descriptor.name
|
self.name = descriptor.name
|
||||||
self.hasXPConnectImpls = descriptor.hasXPConnectImpls
|
self.hasXPConnectImpls = descriptor.hasXPConnectImpls
|
||||||
|
class FakeInterface:
|
||||||
|
def inheritanceDepth(self):
|
||||||
|
return descriptor.interface.inheritanceDepth()
|
||||||
|
self.interface = FakeInterface()
|
||||||
|
|
||||||
def dictionaryHasSequenceMember(dictionary):
|
def dictionaryHasSequenceMember(dictionary):
|
||||||
return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
|
return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
|
||||||
|
@ -934,41 +946,19 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
elif descriptor.workers:
|
elif descriptor.workers:
|
||||||
templateBody += "${declName} = &${val}.toObject();"
|
templateBody += "${declName} = &${val}.toObject();"
|
||||||
else:
|
else:
|
||||||
# Either external, or new-binding non-castable. We always have a
|
|
||||||
# holder for these, because we don't actually know whether we have
|
|
||||||
# to addref when unwrapping or not. So we just pass an
|
|
||||||
# getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
|
|
||||||
# it'll put a non-null pointer in there.
|
|
||||||
if forceOwningType:
|
|
||||||
# Don't return a holderType in this case; our declName
|
|
||||||
# will just own stuff.
|
|
||||||
templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
|
|
||||||
else:
|
|
||||||
holderType = "nsRefPtr<" + typeName + ">"
|
|
||||||
templateBody += (
|
templateBody += (
|
||||||
"jsval tmpVal = ${val};\n" +
|
"match unwrap_value::<" + typePtr + ">(&${val} as *JSVal, "
|
||||||
typePtr + " tmp;\n"
|
"prototypes::id::%s, %d) {\n" % (descriptor.name, descriptor.interface.inheritanceDepth() if descriptor.concrete else 0) +
|
||||||
"if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
|
" Err(()) => {")
|
||||||
templateBody += CGIndenter(onFailureBadType(failureCode,
|
templateBody += CGIndenter(onFailureBadType(failureCode,
|
||||||
descriptor.interface.identifier.name)).define()
|
descriptor.interface.identifier.name)).define()
|
||||||
templateBody += ("}\n"
|
|
||||||
"MOZ_ASSERT(tmp);\n")
|
|
||||||
|
|
||||||
if not isDefinitelyObject:
|
|
||||||
# Our tmpVal will go out of scope, so we can't rely on it
|
|
||||||
# for rooting
|
|
||||||
templateBody += (
|
templateBody += (
|
||||||
"if (tmpVal != ${val} && !${holderName}) {\n"
|
" }\n"
|
||||||
" // We have to have a strong ref, because we got this off\n"
|
" Ok(unwrapped) => ${declName} = Some(unwrapped)\n"
|
||||||
" // some random object that might get GCed\n"
|
|
||||||
" ${holderName} = tmp;\n"
|
|
||||||
"}\n")
|
"}\n")
|
||||||
|
|
||||||
# And store our tmp, before it goes out of scope.
|
|
||||||
templateBody += "${declName} = tmp;"
|
|
||||||
|
|
||||||
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
|
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
|
||||||
type, "${declName} = NULL",
|
type, "${declName} = None",
|
||||||
failureCode)
|
failureCode)
|
||||||
|
|
||||||
declType = CGGeneric(declType)
|
declType = CGGeneric(declType)
|
||||||
|
@ -2849,7 +2839,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
||||||
getPrototypeOf: ptr::null()
|
getPrototypeOf: ptr::null()
|
||||||
};
|
};
|
||||||
(*script_context).dom_static.proxy_handlers.insert(prototypes::id::%s as uint,
|
(*script_context).dom_static.proxy_handlers.insert(prototypes::id::%s as uint,
|
||||||
CreateProxyHandler(ptr::to_unsafe_ptr(&traps)));
|
CreateProxyHandler(ptr::to_unsafe_ptr(&traps), ptr::to_unsafe_ptr(&Class) as *libc::c_void));
|
||||||
|
|
||||||
""" % self.descriptor.name
|
""" % self.descriptor.name
|
||||||
else:
|
else:
|
||||||
|
@ -3141,7 +3131,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
|
||||||
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
|
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
|
||||||
|
|
||||||
if unwrapFailureCode is None:
|
if unwrapFailureCode is None:
|
||||||
self.unwrapFailureCode = ("return Throw<%s>(cx, rv);" %
|
self.unwrapFailureCode = ("return 0; //XXXjdm return Throw<%s>(cx, rv);" %
|
||||||
toStringBool(not descriptor.workers))
|
toStringBool(not descriptor.workers))
|
||||||
else:
|
else:
|
||||||
self.unwrapFailureCode = unwrapFailureCode
|
self.unwrapFailureCode = unwrapFailureCode
|
||||||
|
|
|
@ -17,6 +17,7 @@ use std::uint;
|
||||||
use std::unstable::intrinsics;
|
use std::unstable::intrinsics;
|
||||||
use js::glue::*;
|
use js::glue::*;
|
||||||
use js::glue::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
|
use js::glue::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
|
||||||
|
use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily};
|
||||||
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB, RESOLVE_STUB};
|
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB, RESOLVE_STUB};
|
||||||
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction};
|
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction};
|
||||||
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
||||||
|
@ -117,16 +118,62 @@ fn is_dom_class(clasp: *JSClass) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_dom_proxy(obj: *JSObject) -> bool {
|
||||||
|
unsafe {
|
||||||
|
(js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) &&
|
||||||
|
IsProxyHandlerFamily(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn unwrap<T>(obj: *JSObject) -> T {
|
pub unsafe fn unwrap<T>(obj: *JSObject) -> T {
|
||||||
let slot = if is_dom_class(JS_GetClass(obj)) {
|
let clasp = JS_GetClass(obj);
|
||||||
|
let slot = if is_dom_class(clasp) {
|
||||||
DOM_OBJECT_SLOT
|
DOM_OBJECT_SLOT
|
||||||
} else {
|
} else {
|
||||||
|
assert!(is_dom_proxy(obj));
|
||||||
DOM_PROXY_OBJECT_SLOT
|
DOM_PROXY_OBJECT_SLOT
|
||||||
} as u32;
|
} as u32;
|
||||||
let val = JS_GetReservedSlot(obj, slot);
|
let val = JS_GetReservedSlot(obj, slot);
|
||||||
cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
|
cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
|
||||||
|
let clasp = JS_GetClass(obj);
|
||||||
|
if is_dom_class(clasp) {
|
||||||
|
debug!("plain old dom object");
|
||||||
|
let domjsclass: *DOMJSClass = cast::transmute(clasp);
|
||||||
|
return Ok((*domjsclass).dom_class);
|
||||||
|
}
|
||||||
|
if is_dom_proxy(obj) {
|
||||||
|
debug!("proxy dom object");
|
||||||
|
let dom_class: *DOMClass = cast::transmute(GetProxyHandlerExtra(obj));
|
||||||
|
return Ok(*dom_class);
|
||||||
|
}
|
||||||
|
debug!("not a dom object");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_object<T>(obj: *JSObject, proto_id: prototypes::id::Prototype, proto_depth: uint) -> Result<T, ()> {
|
||||||
|
unsafe {
|
||||||
|
do get_dom_class(obj).chain |dom_class| {
|
||||||
|
if dom_class.interface_chain[proto_depth] == proto_id {
|
||||||
|
debug!("good prototype");
|
||||||
|
Ok(unwrap(obj))
|
||||||
|
} else {
|
||||||
|
debug!("bad prototype");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_value<T>(val: *JSVal, proto_id: prototypes::id::Prototype, proto_depth: uint) -> Result<T, ()> {
|
||||||
|
unsafe {
|
||||||
|
let obj = RUST_JSVAL_TO_OBJECT(*val);
|
||||||
|
unwrap_object(obj, proto_id, proto_depth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn squirrel_away<T>(x: @mut T) -> *rust_box<T> {
|
pub unsafe fn squirrel_away<T>(x: @mut T) -> *rust_box<T> {
|
||||||
let y: *rust_box<T> = cast::transmute(x);
|
let y: *rust_box<T> = cast::transmute(x);
|
||||||
cast::forget(x);
|
cast::forget(x);
|
||||||
|
@ -373,7 +420,9 @@ pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
|
||||||
|
|
||||||
pub mod prototypes {
|
pub mod prototypes {
|
||||||
pub mod id {
|
pub mod id {
|
||||||
|
#[deriving(Eq)]
|
||||||
pub enum Prototype {
|
pub enum Prototype {
|
||||||
|
Blob,
|
||||||
ClientRect,
|
ClientRect,
|
||||||
ClientRectList,
|
ClientRectList,
|
||||||
DOMParser,
|
DOMParser,
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 26dc2e896a57a28f03be43df46868e1a41a15807
|
Subproject commit 372622906d112ae28825be1d5fcd8737cd03ae58
|
Loading…
Add table
Add a link
Reference in a new issue