aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2014-04-22 17:14:48 -0400
committerMs2ger <ms2ger@gmail.com>2014-05-27 20:43:52 +0200
commit003e5bcd4674fc0e78b36ecd783f3045cba852d2 (patch)
tree8206e58c032795db83c392167129483200ff0f2b /src/components/script/dom
parent04931adf70e6dc70d09c2ceb42e2add85f58051d (diff)
downloadservo-003e5bcd4674fc0e78b36ecd783f3045cba852d2.tar.gz
servo-003e5bcd4674fc0e78b36ecd783f3045cba852d2.zip
Port modern callback handling code from Gecko, and copy related WebIDL parser bits too.
Diffstat (limited to 'src/components/script/dom')
-rw-r--r--src/components/script/dom/bindings/callback.rs70
-rw-r--r--src/components/script/dom/bindings/codegen/CodegenRust.py285
-rw-r--r--src/components/script/dom/bindings/codegen/Configuration.py55
-rw-r--r--src/components/script/dom/bindings/codegen/parser/WebIDL.py43
-rw-r--r--src/components/script/dom/bindings/conversions.rs14
-rw-r--r--src/components/script/dom/bindings/trace.rs1
-rw-r--r--src/components/script/dom/document.rs11
-rw-r--r--src/components/script/dom/eventdispatcher.rs6
-rw-r--r--src/components/script/dom/eventtarget.rs41
-rw-r--r--src/components/script/dom/htmlbodyelement.rs36
-rw-r--r--src/components/script/dom/htmlelement.rs18
-rw-r--r--src/components/script/dom/testbinding.rs12
-rw-r--r--src/components/script/dom/webidls/EventHandler.webidl4
-rw-r--r--src/components/script/dom/webidls/TestBinding.webidl18
-rw-r--r--src/components/script/dom/window.rs28
15 files changed, 420 insertions, 222 deletions
diff --git a/src/components/script/dom/bindings/callback.rs b/src/components/script/dom/bindings/callback.rs
index 8a29c382ca9..deebc53d6e3 100644
--- a/src/components/script/dom/bindings/callback.rs
+++ b/src/components/script/dom/bindings/callback.rs
@@ -2,13 +2,13 @@
* 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::trace::trace_object;
-use dom::bindings::utils::Reflectable;
+use dom::bindings::js::JSRef;
+use dom::bindings::trace::Traceable;
+use dom::bindings::utils::{Reflectable, global_object_for_js_object};
use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable};
-use js::jsapi::{JS_GetProperty, JSTracer};
+use js::jsapi::JS_GetProperty;
use js::jsval::{JSVal, UndefinedValue};
-use std::cast;
use std::ptr;
use serialize::{Encodable, Encoder};
@@ -24,42 +24,61 @@ pub enum ExceptionHandling {
RethrowExceptions
}
-#[deriving(Clone,Eq)]
-pub struct CallbackInterface {
- pub callback: *mut JSObject
+#[deriving(Clone,Eq,Encodable)]
+pub struct CallbackFunction {
+ object: CallbackObject
}
-impl<S: Encoder<E>, E> Encodable<S, E> for CallbackInterface {
- fn encode(&self, s: &mut S) -> Result<(), E> {
- unsafe {
- let tracer: *mut JSTracer = cast::transmute(s);
- trace_object(tracer, "callback", self.callback);
+impl CallbackFunction {
+ pub fn new(callback: *mut JSObject) -> CallbackFunction {
+ CallbackFunction {
+ object: CallbackObject {
+ callback: Traceable::new(callback)
+ }
}
- Ok(())
}
}
+#[deriving(Clone,Eq,Encodable)]
+pub struct CallbackInterface {
+ object: CallbackObject
+}
+
+#[deriving(Clone,Eq,Encodable)]
+struct CallbackObject {
+ callback: Traceable<*mut JSObject>,
+}
+
pub trait CallbackContainer {
+ fn new(callback: *mut JSObject) -> Self;
fn callback(&self) -> *mut JSObject;
}
-impl CallbackContainer for CallbackInterface {
- fn callback(&self) -> *mut JSObject {
- self.callback
+impl CallbackInterface {
+ pub fn callback(&self) -> *mut JSObject {
+ *self.object.callback
+ }
+}
+
+impl CallbackFunction {
+ pub fn callback(&self) -> *mut JSObject {
+ *self.object.callback
}
}
impl CallbackInterface {
pub fn new(callback: *mut JSObject) -> CallbackInterface {
CallbackInterface {
- callback: callback
+ object: CallbackObject {
+ callback: Traceable::new(callback)
+ }
}
}
pub fn GetCallableProperty(&self, cx: *mut JSContext, name: &str) -> Result<JSVal, ()> {
let mut callable = UndefinedValue();
unsafe {
- if name.to_c_str().with_ref(|name| JS_GetProperty(cx, self.callback, name, &mut callable)) == 0 {
+ if name.to_c_str().with_ref(|name| JS_GetProperty(cx, self.callback(), name, &mut callable)) == 0 {
return Err(());
}
@@ -73,14 +92,9 @@ impl CallbackInterface {
}
}
-pub fn GetJSObjectFromCallback<T: CallbackContainer>(callback: &T) -> *mut JSObject {
- callback.callback()
-}
-
-pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *mut JSContext,
- _scope: *mut JSObject,
- p: Box<T>) -> *mut JSObject {
- let mut obj = GetJSObjectFromCallback(p);
+pub fn WrapCallThisObject<T: Reflectable>(cx: *mut JSContext,
+ p: &JSRef<T>) -> *mut JSObject {
+ let mut obj = p.reflector().get_jsobject();
assert!(obj.is_not_null());
unsafe {
@@ -98,7 +112,9 @@ pub struct CallSetup {
}
impl CallSetup {
- pub fn new(cx: *mut JSContext, handling: ExceptionHandling) -> CallSetup {
+ pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup {
+ let win = global_object_for_js_object(callback.callback()).root();
+ let cx = win.deref().get_cx();
CallSetup {
cx: cx,
handling: handling
diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py
index 9fca81cd287..a6da30bad29 100644
--- a/src/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/src/components/script/dom/bindings/codegen/CodegenRust.py
@@ -7,9 +7,10 @@
import os
import string
import operator
+import itertools
from WebIDL import *
-from Configuration import Descriptor
+from Configuration import getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
AUTOGENERATED_WARNING_COMMENT = \
"/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
@@ -406,6 +407,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
isEnforceRange=False,
isClamp=False,
exceptionCode=None,
+ allowTreatNonObjectAsNull=False,
isCallbackReturnValue=False,
sourceDescription="value"):
"""
@@ -439,6 +441,9 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
If isClamp is true, we're converting an integer and clamping if the
value is out of range.
+ If allowTreatNonObjectAsNull is true, then [TreatNonObjectAsNull]
+ extended attributes on nullable callback functions will be honored.
+
The return value from this function is a tuple consisting of four things:
1) A string representing the conversion code. This will have template
@@ -500,6 +505,14 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
'%s' % (firstCap(sourceDescription), typeName,
exceptionCode))),
post="\n")
+ def onFailureNotCallable(failureCode):
+ return CGWrapper(
+ CGGeneric(
+ failureCode or
+ ('//XXXjdm ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "%s");\n'
+ '%s' % (firstCap(sourceDescription), exceptionCode))),
+ post="\n")
+
# A helper function for handling null default values. Checks that the
# default value, if it exists, is null.
@@ -699,23 +712,39 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
if type.isCallback():
assert not isEnforceRange and not isClamp
+ assert not type.treatNonCallableAsNull()
+ assert not type.treatNonObjectAsNull() or type.nullable()
+ assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
- if isMember:
- raise TypeError("Can't handle member callbacks; need to sort out "
- "rooting issues")
- # XXXbz we're going to assume that callback types are always
- # nullable and always have [TreatNonCallableAsNull] for now.
- haveCallable = "${val}.is_object() && JS_ObjectIsCallable(cx, ${val}.to_object()) != 0"
- if defaultValue is not None:
- assert(isinstance(defaultValue, IDLNullValue))
- haveCallable = "${haveValue} && " + haveCallable
- return (
- "if (%s) {\n"
- " ${val}.to_object()\n"
- "} else {\n"
- " ptr::mut_null()\n"
- "}" % haveCallable,
- CGGeneric("*mut JSObject"), needsRooting)
+ declType = CGGeneric('%s::%s' % (type.unroll().module(), type.unroll().identifier.name))
+
+ conversion = CGCallbackTempRoot(declType.define())
+
+ if type.nullable():
+ declType = CGTemplatedType("Option", declType)
+ conversion = CGWrapper(conversion, pre="Some(", post=")")
+
+ if allowTreatNonObjectAsNull and type.treatNonObjectAsNull():
+ if not isDefinitelyObject:
+ haveObject = "${val}.is_object()"
+ if defaultValue is not None:
+ assert isinstance(defaultValue, IDLNullValue)
+ haveObject = "${haveValue} && " + haveObject
+ template = CGIfElseWrapper(haveObject,
+ conversion,
+ CGGeneric("None")).define()
+ else:
+ template = conversion
+ else:
+ template = CGIfElseWrapper("JS_ObjectIsCallable(cx, ${val}.to_object()) != 0",
+ conversion,
+ onFailureNotCallable(failureCode)).define()
+ template = wrapObjectTemplate(
+ template,
+ isDefinitelyObject,
+ type,
+ failureCode)
+ return (template, declType, needsRooting)
if type.isAny():
assert not isEnforceRange and not isClamp
@@ -874,7 +903,8 @@ class CGArgumentConverter(CGThing):
defaultValue=argument.defaultValue,
treatNullAs=argument.treatNullAs,
isEnforceRange=argument.enforceRange,
- isClamp=argument.clamp)
+ isClamp=argument.clamp,
+ allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull())
if argument.optional and not argument.defaultValue:
declType = CGWrapper(declType, pre="Option<", post=">")
@@ -913,7 +943,7 @@ def typeNeedsCx(type, retVal=False):
return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes)
if retVal and type.isSpiderMonkeyInterface():
return True
- return type.isCallback() or type.isAny() or type.isObject()
+ return type.isAny() or type.isObject()
def typeRetValNeedsRooting(type):
if type is None:
@@ -958,9 +988,11 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
result = CGWrapper(result, pre="Option<", post=">")
return result
if returnType.isCallback():
- # XXXbz we're going to assume that callback types are always
- # nullable for now.
- return CGGeneric("*mut JSObject")
+ result = CGGeneric('%s::%s' % (returnType.unroll().module(),
+ returnType.unroll().identifier.name))
+ if returnType.nullable():
+ result = CGWrapper(result, pre="Option<", post=">")
+ return result
if returnType.isAny():
return CGGeneric("JSVal")
if returnType.isObject() or returnType.isSpiderMonkeyInterface():
@@ -1347,12 +1379,8 @@ class CGIfWrapper(CGWrapper):
post="\n}")
class CGTemplatedType(CGWrapper):
- def __init__(self, templateName, child, isConst=False, isReference=False):
- const = "const " if isConst else ""
- pre = "%s%s<" % (const, templateName)
- ref = "&" if isReference else ""
- post = ">%s" % ref
- CGWrapper.__init__(self, child, pre=pre, post=post)
+ def __init__(self, templateName, child):
+ CGWrapper.__init__(self, child, pre=templateName + "<", post=">")
class CGNamespace(CGWrapper):
def __init__(self, namespace, child, public=False):
@@ -1573,23 +1601,32 @@ class CGGeneric(CGThing):
def define(self):
return self.text
-def getTypes(descriptor):
+class CGCallbackTempRoot(CGGeneric):
+ def __init__(self, name):
+ val = "%s::new(tempRoot)" % name
+ define = """{
+ let tempRoot = ${val}.to_object();
+ %s
+}""" % val
+ CGGeneric.__init__(self, define)
+
+
+def getAllTypes(descriptors, dictionaries, callbacks):
"""
- Get all argument and return types for all members of the descriptor
+ Generate all the types we're dealing with. For each type, a tuple
+ containing type, descriptor, dictionary is yielded. The
+ descriptor and dictionary can be None if the type does not come
+ from a descriptor or dictionary; they will never both be non-None.
"""
- members = [m for m in descriptor.interface.members]
- if descriptor.interface.ctor():
- members.append(descriptor.interface.ctor())
- signatures = [s for m in members if m.isMethod() for s in m.signatures()]
- types = []
- for s in signatures:
- assert len(s) == 2
- (returnType, arguments) = s
- types.append(returnType)
- types.extend([a.type for a in arguments])
-
- types.extend(a.type for a in members if a.isAttr())
- return types
+ for d in descriptors:
+ for t in getTypesFromDescriptor(d):
+ yield (t, d, None)
+ for dictionary in dictionaries:
+ for t in getTypesFromDictionary(dictionary):
+ yield (t, None, dictionary)
+ for callback in callbacks:
+ for t in getTypesFromCallback(callback):
+ yield (t, None, None)
def SortedTuples(l):
"""
@@ -1606,24 +1643,23 @@ def SortedDictValues(d):
# We're only interested in the values.
return (i[1] for i in d)
-def UnionTypes(descriptors):
+def UnionTypes(descriptors, dictionaries, callbacks, config):
"""
- Returns a tuple containing a set of header filenames to include, a set of
- tuples containing a type declaration and a boolean if the type is a struct
- for member types of the unions and a CGList containing CGUnionStructs for
- every union.
+ Returns a CGList containing CGUnionStructs for every union.
"""
# Now find all the things we'll need as arguments and return values because
# we need to wrap or unwrap them.
unionStructs = dict()
- for d in descriptors:
- for t in getTypes(d):
- t = t.unroll()
- if t.isUnion():
- name = str(t)
- if not name in unionStructs:
- unionStructs[name] = CGList([CGUnionStruct(t, d), CGUnionConversionStruct(t, d)])
+ for (t, descriptor, dictionary) in getAllTypes(descriptors, dictionaries, callbacks):
+ assert not descriptor or not dictionary
+ t = t.unroll()
+ if not t.isUnion():
+ continue
+ name = str(t)
+ if not name in unionStructs:
+ provider = descriptor or config.getDescriptorProvider()
+ unionStructs[name] = CGList([CGUnionStruct(t, provider), CGUnionConversionStruct(t, provider)])
return CGList(SortedDictValues(unionStructs), "\n\n")
@@ -2309,15 +2345,19 @@ class FakeArgument():
A class that quacks like an IDLArgument. This is used to make
setters look like method calls or for special operations.
"""
- def __init__(self, type, interfaceMember):
+ def __init__(self, type, interfaceMember, allowTreatNonObjectAsNull=False):
self.type = type
self.optional = False
self.variadic = False
self.defaultValue = None
+ self._allowTreatNonObjectAsNull = allowTreatNonObjectAsNull
self.treatNullAs = interfaceMember.treatNullAs
self.enforceRange = False
self.clamp = False
+ def allowTreatNonCallableAsNull(self):
+ return self._allowTreatNonObjectAsNull
+
class CGSetterCall(CGPerSignatureCall):
"""
A class to generate a native object setter call for a particular IDL
@@ -2325,7 +2365,7 @@ class CGSetterCall(CGPerSignatureCall):
"""
def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr):
CGPerSignatureCall.__init__(self, None, argsPre,
- [FakeArgument(argType, attr)],
+ [FakeArgument(argType, attr, allowTreatNonObjectAsNull=True)],
nativeMethodName, False, descriptor, attr,
setter=True)
def wrap_return_value(self):
@@ -2710,9 +2750,22 @@ class CGUnionStruct(CGThing):
enumValues = [
" e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars
]
- return ("pub enum %s {\n"
- "%s\n"
- "}\n") % (self.type, "\n".join(enumValues))
+ enumConversions = [
+ " e%s(ref inner) => inner.to_jsval(cx)," % v["name"] for v in templateVars
+ ]
+ return ("""pub enum %s {
+%s
+}
+
+impl ToJSValConvertible for %s {
+ fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ match *self {
+%s
+ }
+ }
+}
+""") % (self.type, "\n".join(enumValues),
+ self.type, "\n".join(enumConversions))
class CGUnionConversionStruct(CGThing):
@@ -4170,14 +4223,17 @@ class CGBindingRoot(CGThing):
for d in dictionaries])
# Do codegen for all the callbacks.
- cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider())
+ cgthings.extend(CGList([CGCallbackFunction(c, config.getDescriptorProvider()),
+ CGCallbackFunctionImpl(c)], "\n")
for c in mainCallbacks)
# Do codegen for all the descriptors
cgthings.extend([CGDescriptor(x) for x in descriptors])
# Do codegen for all the callback interfaces.
- cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors])
+ cgthings.extend(CGList([CGCallbackInterface(x),
+ CGCallbackFunctionImpl(x)], "\n")
+ for x in callbackDescriptors)
# And make sure we have the right number of newlines at the end
curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
@@ -4236,7 +4292,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::utils::VoidVal',
'dom::bindings::utils::get_dictionary_property',
'dom::bindings::trace::JSTraceable',
- 'dom::bindings::callback::{CallbackContainer,CallbackInterface}',
+ 'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
'dom::bindings::callback::{WrapCallThisObject}',
'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}',
@@ -4322,8 +4378,9 @@ class CGNativeMember(ClassMethod):
elif type.isPrimitive() and type.tag() in builtinNames:
result = CGGeneric(builtinNames[type.tag()])
if type.nullable():
- result = CGTemplatedType("Nullable", result)
- typeDecl, template = result.define(), "return ${declName};"
+ raise TypeError("Nullable primitives are not supported here.")
+
+ typeDecl, template = result.define(), "return Ok(${declName});"
elif type.isDOMString():
if isMember:
# No need for a third element in the isMember case
@@ -4363,9 +4420,9 @@ class CGNativeMember(ClassMethod):
("already_AddRefed<%s>" % type.unroll().identifier.name,
"return ${declName}.forget();")
elif type.isAny():
- typeDecl, template = "JS::Value", "return ${declName};"
+ typeDecl, template = "JSVal", "return Ok(${declName});"
elif type.isObject():
- typeDecl, template = "*JSObject", "return ${declName};"
+ typeDecl, template = "JSObject*", "return ${declName};"
elif type.isSpiderMonkeyInterface():
if type.nullable():
returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
@@ -4462,7 +4519,7 @@ class CGNativeMember(ClassMethod):
if type.isUnion():
if type.nullable():
type = type.inner
- return str(type), True, True
+ return str(type), False, True
if type.isGeckoInterface() and not type.isCallbackInterface():
iface = type.unroll().inner
@@ -4492,10 +4549,7 @@ class CGNativeMember(ClassMethod):
return type.name, True, True
if type.isDOMString():
- if isMember:
- declType = "nsString"
- else:
- declType = "nsAString"
+ declType = "DOMString"
return declType, True, False
if type.isByteString():
@@ -4528,7 +4582,7 @@ class CGNativeMember(ClassMethod):
if isMember:
declType = "JS::Value"
else:
- declType = "JS::Handle<JS::Value>"
+ declType = "JSVal"
return declType, False, False
if type.isObject():
@@ -4570,7 +4624,7 @@ class CGNativeMember(ClassMethod):
# Note: All variadic args claim to be optional, but we can just use
# empty arrays to represent them not being present.
decl = CGTemplatedType("Option", decl)
- ref = True
+ ref = False
return (decl, ref)
def getArg(self, arg):
@@ -4581,7 +4635,7 @@ class CGNativeMember(ClassMethod):
arg.optional and not arg.defaultValue,
"Variadic" if arg.variadic else False)
if ref:
- decl = CGWrapper(decl, pre="const ", post="&")
+ decl = CGWrapper(decl, pre="&")
return Argument(decl.define(), arg.identifier.name)
@@ -4649,39 +4703,37 @@ class CGCallback(CGClass):
# And now insert our template argument.
argsWithoutThis = list(args)
- args.insert(0, Argument("Box<T>", "thisObj"))
+ args.insert(0, Argument("&JSRef<T>", "thisObj"))
# And the self argument
method.args.insert(0, Argument(None, "&self"))
args.insert(0, Argument(None, "&self"))
argsWithoutThis.insert(0, Argument(None, "&self"))
- setupCall = ("let s = CallSetup::new(cx_for_dom_object(${cxProvider}), aExceptionHandling);\n"
+ setupCall = ("let s = CallSetup::new(self, aExceptionHandling);\n"
"if s.GetContext().is_null() {\n"
" return Err(FailureUnknown);\n"
"}\n")
bodyWithThis = string.Template(
setupCall+
- "let thisObjJS = WrapCallThisObject(s.GetContext(), ptr::mut_null() /*XXXjdm proper scope*/, thisObj);\n"
+ "let thisObjJS = WrapCallThisObject(s.GetContext(), thisObj);\n"
"if thisObjJS.is_null() {\n"
" return Err(FailureUnknown);\n"
"}\n"
"return ${methodName}(${callArgs});").substitute({
"callArgs" : ", ".join(argnamesWithThis),
"methodName": 'self.' + method.name,
- "cxProvider": 'thisObj'
})
bodyWithoutThis = string.Template(
setupCall +
"return ${methodName}(${callArgs});").substitute({
"callArgs" : ", ".join(argnamesWithoutThis),
"methodName": 'self.' + method.name,
- "cxProvider": args[2].name #XXXjdm There's no guarantee that this is a DOM object
})
return [ClassMethod(method.name+'_', method.returnType, args,
bodyInHeader=True,
- templateArgs=["T: 'static+CallbackContainer+Reflectable"],
+ templateArgs=["T: Reflectable"],
body=bodyWithThis,
visibility='pub'),
ClassMethod(method.name+'__', method.returnType, argsWithoutThis,
@@ -4707,15 +4759,27 @@ class CGCallbackFunction(CGCallback):
methods=[CallCallback(callback, descriptorProvider)])
def getConstructors(self):
- return CGCallback.getConstructors(self) + [
- ClassConstructor(
- [Argument("CallbackFunction*", "aOther")],
- bodyInHeader=True,
- visibility="pub",
- explicit=True,
- baseConstructors=[
- "CallbackFunction(aOther)"
- ])]
+ return CGCallback.getConstructors(self)
+
+class CGCallbackFunctionImpl(CGGeneric):
+ def __init__(self, callback):
+ impl = string.Template("""impl CallbackContainer for ${type} {
+ fn new(callback: *mut JSObject) -> ${type} {
+ ${type}::new(callback)
+ }
+
+ fn callback(&self) -> *mut JSObject {
+ self.parent.callback()
+ }
+}
+
+impl ToJSValConvertible for ${type} {
+ fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ self.callback().to_jsval(cx)
+ }
+}
+""").substitute({"type": callback.name})
+ CGGeneric.__init__(self, impl)
class CGCallbackInterface(CGCallback):
def __init__(self, descriptor):
@@ -4817,7 +4881,7 @@ class CallbackMember(CGNativeMember):
return CGList([
CGGeneric(pre),
CGWrapper(CGIndenter(CGGeneric(body)),
- pre="with_compartment(cx, self.parent.callback, || {\n",
+ pre="with_compartment(cx, self.parent.callback(), || {\n",
post="})")
], "\n").define()
@@ -4876,19 +4940,10 @@ class CallbackMember(CGNativeMember):
else:
jsvalIndex = "%d" % i
if arg.optional and not arg.defaultValue:
- argval += ".Value()"
- if arg.type.isDOMString():
- # XPConnect string-to-JS conversion wants to mutate the string. So
- # let's give it a string it can mutate
- # XXXbz if we try to do a sequence of strings, this will kinda fail.
- result = "mutableStr"
- prepend = "nsString mutableStr(%s);\n" % argval
- else:
- result = argval
- prepend = ""
+ argval += ".clone().unwrap()"
- conversion = prepend + wrapForType("*argv.get_mut(%s)" % jsvalIndex,
- result=result,
+ conversion = wrapForType("*argv.get_mut(%s)" % jsvalIndex,
+ result=argval,
successCode="continue;" if arg.variadic else "break;")
if arg.variadic:
conversion = string.Template(
@@ -4899,12 +4954,12 @@ class CallbackMember(CGNativeMember):
elif arg.optional and not arg.defaultValue:
conversion = (
CGIfWrapper(CGGeneric(conversion),
- "%s.WasPassed()" % arg.identifier.name).define() +
+ "%s.is_some()" % arg.identifier.name).define() +
" else if (argc == %d) {\n"
" // This is our current trailing argument; reduce argc\n"
- " --argc;\n"
+ " argc -= 1;\n"
"} else {\n"
- " argv[%d] = JS::UndefinedValue();\n"
+ " *argv.get_mut(%d) = UndefinedValue();\n"
"}" % (i+1, i))
return conversion
@@ -4946,7 +5001,7 @@ class CallbackMember(CGNativeMember):
})
def getArgcDecl(self):
- return CGGeneric("let argc = %su32;" % self.argCountStr);
+ return CGGeneric("let mut argc = %su32;" % self.argCountStr);
@staticmethod
def ensureASCIIName(idlObject):
@@ -4999,7 +5054,7 @@ class CallCallback(CallbackMethod):
return "aThisObj"
def getCallableDecl(self):
- return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
+ return "let callable = ObjectValue(unsafe {&*self.parent.callback()});\n";
class CallbackOperationBase(CallbackMethod):
"""
@@ -5012,11 +5067,11 @@ class CallbackOperationBase(CallbackMethod):
def getThisObj(self):
if not self.singleOperation:
- return "self.parent.callback"
+ return "self.parent.callback()"
# This relies on getCallableDecl declaring a boolean
# isCallable in the case when we're a single-operation
# interface.
- return "if isCallable { aThisObj } else { self.parent.callback }"
+ return "if isCallable { aThisObj } else { self.parent.callback() }"
def getCallableDecl(self):
replacements = {
@@ -5030,11 +5085,11 @@ class CallbackOperationBase(CallbackMethod):
if not self.singleOperation:
return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
return (
- 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback) != 0 };\n'
+ 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback()) != 0 };\n'
'let callable =\n' +
CGIndenter(
CGIfElseWrapper('isCallable',
- CGGeneric('unsafe { ObjectValue(&*self.parent.callback) }'),
+ CGGeneric('unsafe { ObjectValue(&*self.parent.callback()) }'),
CGGeneric(getCallableFromProp))).define() + ';\n')
class CallbackOperation(CallbackOperationBase):
@@ -5242,12 +5297,16 @@ class GlobalGenRoots():
@staticmethod
def UnionTypes(config):
- curr = UnionTypes(config.getDescriptors())
+ curr = UnionTypes(config.getDescriptors(),
+ config.getDictionaries(),
+ config.getCallbacks(),
+ config)
curr = CGImports(curr, [], [
'dom::bindings::utils::unwrap_jsmanaged',
'dom::bindings::codegen::PrototypeList',
'dom::bindings::conversions::FromJSValConvertible',
+ 'dom::bindings::conversions::ToJSValConvertible',
'dom::bindings::conversions::Default',
'dom::bindings::error::throw_not_in_union',
'dom::bindings::js::JS',
diff --git a/src/components/script/dom/bindings/codegen/Configuration.py b/src/components/script/dom/bindings/codegen/Configuration.py
index 1272867f542..42d3b56f91c 100644
--- a/src/components/script/dom/bindings/codegen/Configuration.py
+++ b/src/components/script/dom/bindings/codegen/Configuration.py
@@ -76,7 +76,11 @@ class Configuration:
@staticmethod
def _filterForFile(items, webIDLFile=""):
"""Gets the items that match the given filters."""
+ if not webIDLFile:
+ return items
+
return filter(lambda x: x.filename() == webIDLFile, items)
+
def getDictionaries(self, webIDLFile=""):
return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile)
def getCallbacks(self, webIDLFile=""):
@@ -269,3 +273,54 @@ class Descriptor(DescriptorProvider):
throws = member.getExtendedAttribute(throwsAttr)
maybeAppendInfallibleToAttrs(attrs, throws)
return attrs
+
+# Some utility methods
+def getTypesFromDescriptor(descriptor):
+ """
+ Get all argument and return types for all members of the descriptor
+ """
+ members = [m for m in descriptor.interface.members]
+ if descriptor.interface.ctor():
+ members.append(descriptor.interface.ctor())
+ members.extend(descriptor.interface.namedConstructors)
+ signatures = [s for m in members if m.isMethod() for s in m.signatures()]
+ types = []
+ for s in signatures:
+ assert len(s) == 2
+ (returnType, arguments) = s
+ types.append(returnType)
+ types.extend(a.type for a in arguments)
+
+ types.extend(a.type for a in members if a.isAttr())
+ return types
+
+def getFlatTypes(types):
+ retval = set()
+ for type in types:
+ type = type.unroll()
+ if type.isUnion():
+ retval |= set(type.flatMemberTypes)
+ else:
+ retval.add(type)
+ return retval
+
+def getTypesFromDictionary(dictionary):
+ """
+ Get all member types for this dictionary
+ """
+ types = []
+ curDict = dictionary
+ while curDict:
+ types.extend([m.type for m in curDict.members])
+ curDict = curDict.parent
+ return types
+
+def getTypesFromCallback(callback):
+ """
+ Get the types this callback depends on: its return type and the
+ types of its arguments.
+ """
+ sig = callback.signatures()[0]
+ types = [sig[0]] # Return type
+ types.extend(arg.type for arg in sig[1]) # Arguments
+ return types
diff --git a/src/components/script/dom/bindings/codegen/parser/WebIDL.py b/src/components/script/dom/bindings/codegen/parser/WebIDL.py
index bee73d5c489..5740a21ca52 100644
--- a/src/components/script/dom/bindings/codegen/parser/WebIDL.py
+++ b/src/components/script/dom/bindings/codegen/parser/WebIDL.py
@@ -464,6 +464,10 @@ class IDLInterface(IDLObjectWithScope):
self._callback = False
self._finished = False
self.members = []
+ # namedConstructors needs deterministic ordering because bindings code
+ # outputs the constructs in the order that namedConstructors enumerates
+ # them.
+ self.namedConstructors = list()
self.implementedInterfaces = set()
self._consequential = False
self._isPartial = True
@@ -696,6 +700,9 @@ class IDLInterface(IDLObjectWithScope):
if identifier == "TreatNonCallableAsNull":
raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces",
[attr.location, self.location])
+ if identifier == "TreatNonObjectAsNull":
+ raise WebIDLError("TreatNonObjectAsNull cannot be specified on interfaces",
+ [attr.location, self.location])
elif identifier == "NoInterfaceObject":
if not attr.noArguments():
raise WebIDLError("[NoInterfaceObject] must take no arguments",
@@ -1049,11 +1056,12 @@ class IDLType(IDLObject):
assert False # Override me!
def treatNonCallableAsNull(self):
- if not (self.nullable() and self.tag() == IDLType.Tags.callback):
- raise WebIDLError("Type %s cannot be TreatNonCallableAsNull" % self,
- [self.location])
+ assert self.tag() == IDLType.Tags.callback
+ return self.nullable() and self.inner._treatNonCallableAsNull
- return hasattr(self, "_treatNonCallableAsNull")
+ def treatNonObjectAsNull(self):
+ assert self.tag() == IDLType.Tags.callback
+ return self.nullable() and self.inner._treatNonObjectAsNull
def markTreatNonCallableAsNull(self):
assert not self.treatNonCallableAsNull()
@@ -2189,6 +2197,7 @@ class IDLArgument(IDLObjectWithIdentifier):
self._isComplete = False
self.enforceRange = False
self.clamp = False
+ self._allowTreatNonCallableAsNull = False
assert not variadic or optional
@@ -2215,6 +2224,8 @@ class IDLArgument(IDLObjectWithIdentifier):
raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive",
[self.location]);
self.enforceRange = True
+ elif identifier == "TreatNonCallableAsNull":
+ self._allowTreatNonCallableAsNull = True
else:
raise WebIDLError("Unhandled extended attribute on an argument",
[attribute.location])
@@ -2247,6 +2258,9 @@ class IDLArgument(IDLObjectWithIdentifier):
self.location)
assert self.defaultValue
+ def allowTreatNonCallableAsNull(self):
+ return self._allowTreatNonCallableAsNull
+
def _getDependentObjects(self):
deps = set([self.type])
if self.defaultValue:
@@ -2269,6 +2283,12 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
for argument in arguments:
argument.resolve(self)
+ self._treatNonCallableAsNull = False
+ self._treatNonObjectAsNull = False
+
+ def module(self):
+ return self.location.filename().split('/')[-1].split('.webidl')[0] + 'Binding'
+
def isCallback(self):
return True
@@ -2308,6 +2328,21 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isNonCallbackInterface() or other.isDate())
+ def addExtendedAttributes(self, attrs):
+ unhandledAttrs = []
+ for attr in attrs:
+ if attr.identifier() == "TreatNonCallableAsNull":
+ self._treatNonCallableAsNull = True
+ elif attr.identifier() == "TreatNonObjectAsNull":
+ self._treatNonObjectAsNull = True
+ else:
+ unhandledAttrs.append(attr)
+ if self._treatNonCallableAsNull and self._treatNonObjectAsNull:
+ raise WebIDLError("Cannot specify both [TreatNonCallableAsNull] "
+ "and [TreatNonObjectAsNull]", [self.location])
+ if len(unhandledAttrs) != 0:
+ IDLType.addExtendedAttributes(self, unhandledAttrs)
+
def _getDependentObjects(self):
return set([self._returnType] + self._arguments)
diff --git a/src/components/script/dom/bindings/conversions.rs b/src/components/script/dom/bindings/conversions.rs
index e1a155fa457..867e07ade30 100644
--- a/src/components/script/dom/bindings/conversions.rs
+++ b/src/components/script/dom/bindings/conversions.rs
@@ -328,6 +328,12 @@ impl<'a, T: Reflectable> ToJSValConvertible for JSRef<'a, T> {
}
}
+impl<'a, T: Reflectable> ToJSValConvertible for JS<T> {
+ fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ self.reflector().to_jsval(cx)
+ }
+}
+
impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
match self {
@@ -350,7 +356,11 @@ impl<X: Default, T: FromJSValConvertible<X>> FromJSValConvertible<()> for Option
}
impl ToJSValConvertible for *mut JSObject {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- ObjectOrNullValue(*self)
+ fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ let mut wrapped = ObjectOrNullValue(*self);
+ unsafe {
+ assert!(JS_WrapValue(cx, &mut wrapped) != 0);
+ }
+ wrapped
}
}
diff --git a/src/components/script/dom/bindings/trace.rs b/src/components/script/dom/bindings/trace.rs
index d18f6a64448..26decbc450a 100644
--- a/src/components/script/dom/bindings/trace.rs
+++ b/src/components/script/dom/bindings/trace.rs
@@ -110,6 +110,7 @@ impl<T> DerefMut<T> for Untraceable<T> {
/// Encapsulates a type that can be traced but is boxed in a type we don't control
/// (such as RefCell). Wrap a field in Traceable and implement the Encodable trait
/// for that new concrete type to achieve magic compiler-derived trace hooks.
+#[deriving(Eq, Clone)]
pub struct Traceable<T> {
inner: T
}
diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs
index 68ea97d1335..f6f67f93747 100644
--- a/src/components/script/dom/document.rs
+++ b/src/components/script/dom/document.rs
@@ -2,6 +2,7 @@
* 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::codegen::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::{DocumentDerived, EventCast, HTMLElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast};
@@ -45,7 +46,7 @@ use servo_util::namespace::{Namespace, Null};
use servo_util::str::{DOMString, null_str_as_empty_ref};
use collections::hashmap::HashMap;
-use js::jsapi::{JSObject, JSContext};
+use js::jsapi::JSContext;
use std::ascii::StrAsciiExt;
use url::{Url, from_str};
@@ -326,8 +327,8 @@ pub trait DocumentMethods {
fn Applets(&self) -> Temporary<HTMLCollection>;
fn Location(&mut self) -> Temporary<Location>;
fn Children(&self) -> Temporary<HTMLCollection>;
- fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject;
- fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
+ fn GetOnload(&self) -> Option<EventHandlerNonNull>;
+ fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
}
impl<'a> DocumentMethods for JSRef<'a, Document> {
@@ -808,12 +809,12 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
HTMLCollection::children(&*window, NodeCast::from_ref(self))
}
- fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject {
+ fn GetOnload(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("load")
}
- fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
+ fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("load", listener)
}
diff --git a/src/components/script/dom/eventdispatcher.rs b/src/components/script/dom/eventdispatcher.rs
index cc5eb66f577..11db1eb7b2b 100644
--- a/src/components/script/dom/eventdispatcher.rs
+++ b/src/components/script/dom/eventdispatcher.rs
@@ -50,7 +50,7 @@ pub fn dispatch_event<'a, 'b>(target: &JSRef<'a, EventTarget>,
for listener in listeners.iter() {
//FIXME: this should have proper error handling, or explicitly
// drop the exception on the floor
- assert!(listener.HandleEvent__(event, ReportExceptions).is_ok());
+ assert!(listener.HandleEvent_(&**cur_target, event, ReportExceptions).is_ok());
if event.deref().stop_immediate {
break;
@@ -80,7 +80,7 @@ pub fn dispatch_event<'a, 'b>(target: &JSRef<'a, EventTarget>,
for listener in listeners.iter() {
//FIXME: this should have proper error handling, or explicitly drop the
// exception on the floor.
- assert!(listener.HandleEvent__(event, ReportExceptions).is_ok());
+ assert!(listener.HandleEvent_(target, event, ReportExceptions).is_ok());
if event.deref().stop_immediate {
break;
}
@@ -99,7 +99,7 @@ pub fn dispatch_event<'a, 'b>(target: &JSRef<'a, EventTarget>,
for listener in listeners.iter() {
//FIXME: this should have proper error handling or explicitly
// drop exceptions on the floor.
- assert!(listener.HandleEvent__(event, ReportExceptions).is_ok());
+ assert!(listener.HandleEvent_(&**cur_target, event, ReportExceptions).is_ok());
if event.deref().stop_immediate {
break;
diff --git a/src/components/script/dom/eventtarget.rs b/src/components/script/dom/eventtarget.rs
index b0b8a9bad33..db92255cb59 100644
--- a/src/components/script/dom/eventtarget.rs
+++ b/src/components/script/dom/eventtarget.rs
@@ -4,18 +4,21 @@
use dom::bindings::callback::CallbackContainer;
use dom::bindings::codegen::BindingDeclarations::EventListenerBinding::EventListener;
+use dom::bindings::codegen::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::error::{Fallible, InvalidState};
use dom::bindings::js::JSRef;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::event::Event;
use dom::eventdispatcher::dispatch_event;
-use dom::node::{Node, NodeTypeId, window_from_node};
+use dom::node::NodeTypeId;
use dom::xmlhttprequest::XMLHttpRequestId;
use dom::virtualmethods::VirtualMethods;
-use js::jsapi::{JSObject, JS_CompileUCFunction, JS_GetFunctionObject, JS_CloneFunctionObject};
+use js::jsapi::{JS_CompileUCFunction, JS_GetFunctionObject, JS_CloneFunctionObject};
+use js::jsapi::{JSContext, JSObject};
use servo_util::str::DOMString;
use libc::{c_char, size_t};
use std::ptr;
+use url::Url;
use collections::hashmap::HashMap;
@@ -92,11 +95,14 @@ pub trait EventTargetHelpers {
listener: Option<EventListener>);
fn get_inline_event_listener(&self, ty: DOMString) -> Option<EventListener>;
fn set_event_handler_uncompiled(&mut self,
- content: &JSRef<Node>,
+ cx: *mut JSContext,
+ url: Url,
+ scope: *mut JSObject,
ty: &str,
source: DOMString);
- fn set_event_handler_common(&mut self, ty: &str, listener: *mut JSObject);
- fn get_event_handler_common(&self, ty: &str) -> *mut JSObject;
+ fn set_event_handler_common<T: CallbackContainer>(&mut self, ty: &str,
+ listener: Option<T>);
+ fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<T>;
}
impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
@@ -132,7 +138,7 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
None => {
if listener.is_some() {
entries.push(EventListenerEntry {
- phase: Capturing, //XXXjdm no idea when inline handlers should run
+ phase: Bubbling,
listener: Inline(listener.unwrap()),
});
}
@@ -151,12 +157,11 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
}
fn set_event_handler_uncompiled(&mut self,
- content: &JSRef<Node>,
+ cx: *mut JSContext,
+ url: Url,
+ scope: *mut JSObject,
ty: &str,
source: DOMString) {
- let win = window_from_node(content).root();
- let cx = win.deref().get_cx();
- let url = win.deref().get_url();
let url = url.to_str().to_c_str();
let name = ty.to_c_str();
let lineno = 0; //XXXjdm need to get a real number here
@@ -177,20 +182,22 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
assert!(fun.is_not_null());
JS_GetFunctionObject(fun)
}})});
- let scope = win.deref().reflector().get_jsobject();
let funobj = unsafe { JS_CloneFunctionObject(cx, handler, scope) };
assert!(funobj.is_not_null());
- self.set_event_handler_common(ty, funobj)
+ self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj)))
}
- fn set_event_handler_common(&mut self, ty: &str, listener: *mut JSObject) {
- let listener = EventListener::new(listener);
- self.set_inline_event_listener(ty.to_owned(), Some(listener));
+ fn set_event_handler_common<T: CallbackContainer>(
+ &mut self, ty: &str, listener: Option<T>)
+ {
+ let event_listener = listener.map(|listener|
+ EventListener::new(listener.callback()));
+ self.set_inline_event_listener(ty.to_owned(), event_listener);
}
- fn get_event_handler_common(&self, ty: &str) -> *mut JSObject {
+ fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<T> {
let listener = self.get_inline_event_listener(ty.to_owned());
- listener.map(|listener| listener.parent.callback()).unwrap_or(ptr::mut_null())
+ listener.map(|listener| CallbackContainer::new(listener.parent.callback()))
}
}
diff --git a/src/components/script/dom/htmlbodyelement.rs b/src/components/script/dom/htmlbodyelement.rs
index 7f0b8efc66b..6ba82e252f0 100644
--- a/src/components/script/dom/htmlbodyelement.rs
+++ b/src/components/script/dom/htmlbodyelement.rs
@@ -3,10 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::BindingDeclarations::HTMLBodyElementBinding;
+use dom::bindings::codegen::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
-use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast};
+use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::error::ErrorResult;
use dom::bindings::js::{JSRef, Temporary};
+use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::element::HTMLBodyElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
@@ -14,7 +16,6 @@ use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::WindowMethods;
-use js::jsapi::{JSContext, JSObject};
use servo_util::str::DOMString;
#[deriving(Encodable)]
@@ -54,8 +55,8 @@ pub trait HTMLBodyElementMethods {
fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult;
fn Background(&self) -> DOMString;
fn SetBackground(&self, _background: DOMString) -> ErrorResult;
- fn GetOnunload(&self, cx: *mut JSContext) -> *mut JSObject;
- fn SetOnunload(&mut self, cx: *mut JSContext, listener: *mut JSObject);
+ fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
+ fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>);
}
impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
@@ -107,14 +108,14 @@ impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
Ok(())
}
- fn GetOnunload(&self, cx: *mut JSContext) -> *mut JSObject {
+ fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
let win = window_from_node(self).root();
- win.deref().GetOnunload(cx)
+ win.deref().GetOnunload()
}
- fn SetOnunload(&mut self, cx: *mut JSContext, listener: *mut JSObject) {
+ fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>) {
let mut win = window_from_node(self).root();
- win.SetOnunload(cx, listener)
+ win.SetOnunload(listener)
}
}
@@ -131,11 +132,22 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
}
if name.starts_with("on") {
- //XXXjdm This should only forward a subset of event handler names
+ static forwarded_events: &'static [&'static str] =
+ &["onfocus", "onload", "onscroll", "onafterprint", "onbeforeprint",
+ "onbeforeunload", "onhashchange", "onlanguagechange", "onmessage",
+ "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate",
+ "onstorage", "onresize", "onunload", "onerror"];
let mut window = window_from_node(self).root();
- let mut evtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(&mut *window);
- let content: &mut JSRef<Node> = NodeCast::from_mut_ref(self);
- evtarget.set_event_handler_uncompiled(content,
+ let (cx, url, reflector) = (window.get_cx(),
+ window.get_url(),
+ window.reflector().get_jsobject());
+ let evtarget: &mut JSRef<EventTarget> =
+ if forwarded_events.iter().any(|&event| name.as_slice() == event) {
+ EventTargetCast::from_mut_ref(&mut *window)
+ } else {
+ EventTargetCast::from_mut_ref(self)
+ };
+ evtarget.set_event_handler_uncompiled(cx, url, reflector,
name.slice_from(2).to_owned(),
value);
}
diff --git a/src/components/script/dom/htmlelement.rs b/src/components/script/dom/htmlelement.rs
index c5f3fd3ed48..85d2d2bee67 100644
--- a/src/components/script/dom/htmlelement.rs
+++ b/src/components/script/dom/htmlelement.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::BindingDeclarations::HTMLElementBinding;
+use dom::bindings::codegen::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived};
use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived};
use dom::bindings::codegen::InheritTypes::EventTargetCast;
@@ -14,11 +15,10 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::node::{Node, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::WindowMethods;
-use js::jsapi::{JSContext, JSObject};
+use js::jsapi::JSContext;
use js::jsval::{JSVal, NullValue};
use servo_util::namespace;
use servo_util::str::DOMString;
-use std::ptr;
#[deriving(Encodable)]
pub struct HTMLElement {
@@ -90,8 +90,8 @@ pub trait HTMLElementMethods {
fn OffsetLeft(&self) -> i32;
fn OffsetWidth(&self) -> i32;
fn OffsetHeight(&self) -> i32;
- fn GetOnload(&self, cx: *mut JSContext) -> *mut JSObject;
- fn SetOnload(&mut self, cx: *mut JSContext, listener: *mut JSObject);
+ fn GetOnload(&self) -> Option<EventHandlerNonNull>;
+ fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
}
impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
@@ -212,19 +212,19 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
0
}
- fn GetOnload(&self, cx: *mut JSContext) -> *mut JSObject {
+ fn GetOnload(&self) -> Option<EventHandlerNonNull> {
if self.is_body_or_frameset() {
let win = window_from_node(self).root();
- win.deref().GetOnload(cx)
+ win.deref().GetOnload()
} else {
- ptr::mut_null()
+ None
}
}
- fn SetOnload(&mut self, cx: *mut JSContext, listener: *mut JSObject) {
+ fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
if self.is_body_or_frameset() {
let mut win = window_from_node(self).root();
- win.SetOnload(cx, listener)
+ win.SetOnload(listener)
}
}
}
diff --git a/src/components/script/dom/testbinding.rs b/src/components/script/dom/testbinding.rs
index 115fbcadaa5..4b753785e10 100644
--- a/src/components/script/dom/testbinding.rs
+++ b/src/components/script/dom/testbinding.rs
@@ -5,7 +5,7 @@
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::codegen::BindingDeclarations::TestBindingBinding::TestEnum;
use dom::bindings::codegen::BindingDeclarations::TestBindingBinding::TestEnumValues::_empty;
-use dom::bindings::codegen::UnionTypes::{HTMLElementOrLong, StringOrFormData};
+use dom::bindings::codegen::UnionTypes::{HTMLElementOrLong, EventOrString};
use dom::bindings::str::ByteString;
use dom::bindings::utils::{Reflector, Reflectable};
use dom::blob::Blob;
@@ -136,7 +136,7 @@ pub trait TestBindingMethods {
fn PassEnum(&self, _: TestEnum) {}
fn PassInterface(&self, _: &JSRef<Blob>) {}
fn PassUnion(&self, _: HTMLElementOrLong) {}
- fn PassUnion2(&self, _: StringOrFormData) {}
+ fn PassUnion2(&self, _: EventOrString) {}
fn PassAny(&self, _: *mut JSContext, _: JSVal) {}
fn PassNullableBoolean(&self, _: Option<bool>) {}
@@ -155,7 +155,7 @@ pub trait TestBindingMethods {
// fn PassNullableEnum(&self, _: Option<TestEnum>) {}
fn PassNullableInterface(&self, _: Option<JSRef<Blob>>) {}
fn PassNullableUnion(&self, _: Option<HTMLElementOrLong>) {}
- fn PassNullableUnion2(&self, _: Option<StringOrFormData>) {}
+ fn PassNullableUnion2(&self, _: Option<EventOrString>) {}
fn PassNullableAny(&self, _: *mut JSContext, _: Option<JSVal>) {}
fn PassOptionalBoolean(&self, _: Option<bool>) {}
@@ -174,7 +174,7 @@ pub trait TestBindingMethods {
fn PassOptionalEnum(&self, _: Option<TestEnum>) {}
fn PassOptionalInterface(&self, _: Option<JSRef<Blob>>) {}
fn PassOptionalUnion(&self, _: Option<HTMLElementOrLong>) {}
- fn PassOptionalUnion2(&self, _: Option<StringOrFormData>) {}
+ fn PassOptionalUnion2(&self, _: Option<EventOrString>) {}
fn PassOptionalAny(&self, _: *mut JSContext, _: Option<JSVal>) {}
fn PassOptionalNullableBoolean(&self, _: Option<Option<bool>>) {}
@@ -193,7 +193,7 @@ pub trait TestBindingMethods {
// fn PassOptionalNullableEnum(&self, _: Option<Option<TestEnum>>) {}
fn PassOptionalNullableInterface(&self, _: Option<Option<JSRef<Blob>>>) {}
fn PassOptionalNullableUnion(&self, _: Option<Option<HTMLElementOrLong>>) {}
- fn PassOptionalNullableUnion2(&self, _: Option<Option<StringOrFormData>>) {}
+ fn PassOptionalNullableUnion2(&self, _: Option<Option<EventOrString>>) {}
fn PassOptionalBooleanWithDefault(&self, _: bool) {}
fn PassOptionalByteWithDefault(&self, _: i8) {}
@@ -223,7 +223,7 @@ pub trait TestBindingMethods {
// fn PassOptionalNullableEnumWithDefault(&self, _: Option<TestEnum>) {}
fn PassOptionalNullableInterfaceWithDefault(&self, _: Option<JSRef<Blob>>) {}
fn PassOptionalNullableUnionWithDefault(&self, _: Option<HTMLElementOrLong>) {}
- fn PassOptionalNullableUnion2WithDefault(&self, _: Option<StringOrFormData>) {}
+ fn PassOptionalNullableUnion2WithDefault(&self, _: Option<EventOrString>) {}
fn PassOptionalAnyWithDefault(&self, _: *mut JSContext, _: JSVal) {}
fn PassOptionalNullableBooleanWithNonNullDefault(&self, _: Option<bool>) {}
diff --git a/src/components/script/dom/webidls/EventHandler.webidl b/src/components/script/dom/webidls/EventHandler.webidl
index ee760bcd05b..dd922cc3f75 100644
--- a/src/components/script/dom/webidls/EventHandler.webidl
+++ b/src/components/script/dom/webidls/EventHandler.webidl
@@ -11,11 +11,11 @@
* and create derivative works of this document.
*/
-//[TreatNonObjectAsNull] //XXXjdm webidl.py assertion
+[TreatNonObjectAsNull]
callback EventHandlerNonNull = any (Event event);
typedef EventHandlerNonNull? EventHandler;
-//[TreatNonObjectAsNull] //XXXjdm webidl.py assertion
+[TreatNonObjectAsNull]
callback OnErrorEventHandlerNonNull = boolean ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column, optional any error);
typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
diff --git a/src/components/script/dom/webidls/TestBinding.webidl b/src/components/script/dom/webidls/TestBinding.webidl
index 101e4d554e5..467abce3328 100644
--- a/src/components/script/dom/webidls/TestBinding.webidl
+++ b/src/components/script/dom/webidls/TestBinding.webidl
@@ -70,7 +70,7 @@ interface TestBinding {
attribute TestEnum enumAttribute;
attribute Blob interfaceAttribute;
// attribute (HTMLElement or long) unionAttribute;
- // attribute (DOMString or FormData) union2Attribute;
+ // attribute (Event or DOMString) union2Attribute;
attribute any anyAttribute;
attribute boolean? booleanAttributeNullable;
@@ -89,7 +89,7 @@ interface TestBinding {
readonly attribute TestEnum? enumAttributeNullable;
attribute Blob? interfaceAttributeNullable;
// attribute (HTMLElement or long)? unionAttributeNullable;
- // attribute (DOMString or FormData)? union2AttributeNullable;
+ // attribute (Event or DOMString)? union2AttributeNullable;
void receiveVoid();
boolean receiveBoolean();
@@ -137,7 +137,7 @@ interface TestBinding {
void passEnum(TestEnum arg);
void passInterface(Blob arg);
void passUnion((HTMLElement or long) arg);
- void passUnion2((DOMString or FormData) data);
+ void passUnion2((Event or DOMString) data);
void passAny(any arg);
void passNullableBoolean(boolean? arg);
@@ -156,7 +156,7 @@ interface TestBinding {
// void passNullableEnum(TestEnum? arg);
void passNullableInterface(Blob? arg);
void passNullableUnion((HTMLElement or long)? arg);
- void passNullableUnion2((DOMString or FormData)? data);
+ void passNullableUnion2((Event or DOMString)? data);
void passOptionalBoolean(optional boolean arg);
void passOptionalByte(optional byte arg);
@@ -174,7 +174,7 @@ interface TestBinding {
void passOptionalEnum(optional TestEnum arg);
void passOptionalInterface(optional Blob arg);
void passOptionalUnion(optional (HTMLElement or long) arg);
- void passOptionalUnion2(optional (DOMString or FormData) data);
+ void passOptionalUnion2(optional (Event or DOMString) data);
void passOptionalAny(optional any arg);
void passOptionalNullableBoolean(optional boolean? arg);
@@ -193,7 +193,7 @@ interface TestBinding {
// void passOptionalNullableEnum(optional TestEnum? arg);
void passOptionalNullableInterface(optional Blob? arg);
void passOptionalNullableUnion(optional (HTMLElement or long)? arg);
- void passOptionalNullableUnion2(optional (DOMString or FormData)? data);
+ void passOptionalNullableUnion2(optional (Event or DOMString)? data);
void passOptionalBooleanWithDefault(optional boolean arg = false);
void passOptionalByteWithDefault(optional byte arg = 0);
@@ -207,7 +207,7 @@ interface TestBinding {
void passOptionalStringWithDefault(optional DOMString arg = "");
void passOptionalEnumWithDefault(optional TestEnum arg = "foo");
// void passOptionalUnionWithDefault(optional (HTMLElement or long) arg = 9);
- // void passOptionalUnion2WithDefault(optional(DOMString or FormData)? data = "foo");
+ // void passOptionalUnion2WithDefault(optional(Event or DOMString)? data = "foo");
void passOptionalNullableBooleanWithDefault(optional boolean? arg = null);
void passOptionalNullableByteWithDefault(optional byte? arg = null);
@@ -223,7 +223,7 @@ interface TestBinding {
// void passOptionalNullableEnumWithDefault(optional TestEnum? arg = null);
void passOptionalNullableInterfaceWithDefault(optional Blob? arg = null);
void passOptionalNullableUnionWithDefault(optional (HTMLElement or long)? arg = null);
- void passOptionalNullableUnion2WithDefault(optional (DOMString or FormData)? data = null);
+ void passOptionalNullableUnion2WithDefault(optional (Event or DOMString)? data = null);
void passOptionalAnyWithDefault(optional any arg = null);
void passOptionalNullableBooleanWithNonNullDefault(optional boolean? arg = false);
@@ -240,5 +240,5 @@ interface TestBinding {
void passOptionalNullableStringWithNonNullDefault(optional DOMString? arg = "");
// void passOptionalNullableEnumWithNonNullDefault(optional TestEnum? arg = "foo");
// void passOptionalNullableUnionWithNonNullDefault(optional (HTMLElement or long)? arg = 7);
- // void passOptionalNullableUnion2WithNonNullDefault(optional (DOMString or FormData)? data = "foo");
+ // void passOptionalNullableUnion2WithNonNullDefault(optional (Event or DOMString)? data = "foo");
};
diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs
index ecb08928832..0c71edb69a0 100644
--- a/src/components/script/dom/window.rs
+++ b/src/components/script/dom/window.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::BindingDeclarations::WindowBinding;
+use dom::bindings::codegen::EventHandlerBinding::{OnErrorEventHandlerNonNull, EventHandlerNonNull};
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable};
use dom::bindings::trace::{Traceable, Untraceable};
@@ -24,7 +25,7 @@ use servo_util::str::DOMString;
use servo_util::task::{spawn_named};
use servo_util::url::parse_url;
-use js::jsapi::{JSContext, JSObject};
+use js::jsapi::JSContext;
use js::jsapi::{JS_GC, JS_GetRuntime};
use js::jsval::{NullValue, JSVal};
@@ -141,12 +142,12 @@ pub trait WindowMethods {
fn Window(&self) -> Temporary<Window>;
fn Self(&self) -> Temporary<Window>;
fn Performance(&mut self) -> Temporary<Performance>;
- fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject;
- fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
- fn GetOnunload(&self, _cx: *mut JSContext) -> *mut JSObject;
- fn SetOnunload(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
- fn GetOnerror(&self, _cx: *mut JSContext) -> *mut JSObject;
- fn SetOnerror(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
+ fn GetOnload(&self) -> Option<EventHandlerNonNull>;
+ fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
+ fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
+ fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>);
+ fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull>;
+ fn SetOnerror(&mut self, listener: Option<OnErrorEventHandlerNonNull>);
fn Debug(&self, message: DOMString);
fn Gc(&self);
}
@@ -275,32 +276,32 @@ impl<'a> WindowMethods for JSRef<'a, Window> {
Temporary::new(self.performance.get_ref().clone())
}
- fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject {
+ fn GetOnload(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("load")
}
- fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
+ fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("load", listener)
}
- fn GetOnunload(&self, _cx: *mut JSContext) -> *mut JSObject {
+ fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("unload")
}
- fn SetOnunload(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
+ fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("unload", listener)
}
- fn GetOnerror(&self, _cx: *mut JSContext) -> *mut JSObject {
+ fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("error")
}
- fn SetOnerror(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
+ fn SetOnerror(&mut self, listener: Option<OnErrorEventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("error", listener)
}
@@ -429,6 +430,7 @@ impl<'a> PrivateWindowHelpers for JSRef<'a, Window> {
handle
}
}
+
impl Window {
pub fn new(cx: *mut JSContext,
page: Rc<Page>,