mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
commit
0886a36b5d
25 changed files with 728 additions and 180 deletions
|
@ -2,13 +2,13 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::trace::trace_object;
|
use dom::bindings::js::JSRef;
|
||||||
use dom::bindings::utils::Reflectable;
|
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::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable};
|
||||||
use js::jsapi::{JS_GetProperty, JSTracer};
|
use js::jsapi::JS_GetProperty;
|
||||||
use js::jsval::{JSVal, UndefinedValue};
|
use js::jsval::{JSVal, UndefinedValue};
|
||||||
|
|
||||||
use std::cast;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use serialize::{Encodable, Encoder};
|
use serialize::{Encodable, Encoder};
|
||||||
|
@ -24,42 +24,61 @@ pub enum ExceptionHandling {
|
||||||
RethrowExceptions
|
RethrowExceptions
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone,Eq)]
|
#[deriving(Clone,Eq,Encodable)]
|
||||||
pub struct CallbackInterface {
|
pub struct CallbackFunction {
|
||||||
pub callback: *mut JSObject
|
object: CallbackObject
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Encoder<E>, E> Encodable<S, E> for CallbackInterface {
|
impl CallbackFunction {
|
||||||
fn encode(&self, s: &mut S) -> Result<(), E> {
|
pub fn new(callback: *mut JSObject) -> CallbackFunction {
|
||||||
unsafe {
|
CallbackFunction {
|
||||||
let tracer: *mut JSTracer = cast::transmute(s);
|
object: CallbackObject {
|
||||||
trace_object(tracer, "callback", self.callback);
|
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 {
|
pub trait CallbackContainer {
|
||||||
|
fn new(callback: *mut JSObject) -> Self;
|
||||||
fn callback(&self) -> *mut JSObject;
|
fn callback(&self) -> *mut JSObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallbackContainer for CallbackInterface {
|
impl CallbackInterface {
|
||||||
fn callback(&self) -> *mut JSObject {
|
pub fn callback(&self) -> *mut JSObject {
|
||||||
self.callback
|
*self.object.callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallbackFunction {
|
||||||
|
pub fn callback(&self) -> *mut JSObject {
|
||||||
|
*self.object.callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallbackInterface {
|
impl CallbackInterface {
|
||||||
pub fn new(callback: *mut JSObject) -> CallbackInterface {
|
pub fn new(callback: *mut JSObject) -> CallbackInterface {
|
||||||
CallbackInterface {
|
CallbackInterface {
|
||||||
callback: callback
|
object: CallbackObject {
|
||||||
|
callback: Traceable::new(callback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetCallableProperty(&self, cx: *mut JSContext, name: &str) -> Result<JSVal, ()> {
|
pub fn GetCallableProperty(&self, cx: *mut JSContext, name: &str) -> Result<JSVal, ()> {
|
||||||
let mut callable = UndefinedValue();
|
let mut callable = UndefinedValue();
|
||||||
unsafe {
|
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(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,14 +92,9 @@ impl CallbackInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetJSObjectFromCallback<T: CallbackContainer>(callback: &T) -> *mut JSObject {
|
pub fn WrapCallThisObject<T: Reflectable>(cx: *mut JSContext,
|
||||||
callback.callback()
|
p: &JSRef<T>) -> *mut JSObject {
|
||||||
}
|
let mut obj = p.reflector().get_jsobject();
|
||||||
|
|
||||||
pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *mut JSContext,
|
|
||||||
_scope: *mut JSObject,
|
|
||||||
p: Box<T>) -> *mut JSObject {
|
|
||||||
let mut obj = GetJSObjectFromCallback(p);
|
|
||||||
assert!(obj.is_not_null());
|
assert!(obj.is_not_null());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -98,7 +112,9 @@ pub struct CallSetup {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
CallSetup {
|
||||||
cx: cx,
|
cx: cx,
|
||||||
handling: handling
|
handling: handling
|
||||||
|
|
|
@ -34,6 +34,7 @@ DOMInterfaces = {
|
||||||
'DOMParser': {},
|
'DOMParser': {},
|
||||||
'Element': {},
|
'Element': {},
|
||||||
'Event': {},
|
'Event': {},
|
||||||
|
'EventHandler': {},
|
||||||
'EventListener': {
|
'EventListener': {
|
||||||
'nativeType': 'EventListenerBinding::EventListener',
|
'nativeType': 'EventListenerBinding::EventListener',
|
||||||
},
|
},
|
||||||
|
@ -133,4 +134,3 @@ DOMInterfaces = {
|
||||||
'TestBinding': {},
|
'TestBinding': {},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
import operator
|
import operator
|
||||||
|
import itertools
|
||||||
|
|
||||||
from WebIDL import *
|
from WebIDL import *
|
||||||
from Configuration import Descriptor
|
from Configuration import getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
|
||||||
|
|
||||||
AUTOGENERATED_WARNING_COMMENT = \
|
AUTOGENERATED_WARNING_COMMENT = \
|
||||||
"/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
|
"/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
|
||||||
|
@ -406,6 +407,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
||||||
isEnforceRange=False,
|
isEnforceRange=False,
|
||||||
isClamp=False,
|
isClamp=False,
|
||||||
exceptionCode=None,
|
exceptionCode=None,
|
||||||
|
allowTreatNonObjectAsNull=False,
|
||||||
isCallbackReturnValue=False,
|
isCallbackReturnValue=False,
|
||||||
sourceDescription="value"):
|
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
|
If isClamp is true, we're converting an integer and clamping if the
|
||||||
value is out of range.
|
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:
|
The return value from this function is a tuple consisting of four things:
|
||||||
|
|
||||||
1) A string representing the conversion code. This will have template
|
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,
|
'%s' % (firstCap(sourceDescription), typeName,
|
||||||
exceptionCode))),
|
exceptionCode))),
|
||||||
post="\n")
|
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
|
# A helper function for handling null default values. Checks that the
|
||||||
# default value, if it exists, is null.
|
# default value, if it exists, is null.
|
||||||
|
@ -699,23 +712,39 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
||||||
|
|
||||||
if type.isCallback():
|
if type.isCallback():
|
||||||
assert not isEnforceRange and not isClamp
|
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:
|
declType = CGGeneric('%s::%s' % (type.unroll().module(), type.unroll().identifier.name))
|
||||||
raise TypeError("Can't handle member callbacks; need to sort out "
|
|
||||||
"rooting issues")
|
conversion = CGCallbackTempRoot(declType.define())
|
||||||
# XXXbz we're going to assume that callback types are always
|
|
||||||
# nullable and always have [TreatNonCallableAsNull] for now.
|
if type.nullable():
|
||||||
haveCallable = "${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())"
|
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:
|
if defaultValue is not None:
|
||||||
assert(isinstance(defaultValue, IDLNullValue))
|
assert isinstance(defaultValue, IDLNullValue)
|
||||||
haveCallable = "${haveValue} && " + haveCallable
|
haveObject = "${haveValue} && " + haveObject
|
||||||
return (
|
template = CGIfElseWrapper(haveObject,
|
||||||
"if (%s) {\n"
|
conversion,
|
||||||
" ${declName} = &${val}.toObject();\n"
|
CGGeneric("None")).define()
|
||||||
"} else {\n"
|
else:
|
||||||
" ${declName} = NULL;\n"
|
template = conversion
|
||||||
"}" % haveCallable,
|
else:
|
||||||
CGGeneric("JSObject*"), None, needsRooting)
|
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():
|
if type.isAny():
|
||||||
assert not isEnforceRange and not isClamp
|
assert not isEnforceRange and not isClamp
|
||||||
|
@ -874,7 +903,8 @@ class CGArgumentConverter(CGThing):
|
||||||
defaultValue=argument.defaultValue,
|
defaultValue=argument.defaultValue,
|
||||||
treatNullAs=argument.treatNullAs,
|
treatNullAs=argument.treatNullAs,
|
||||||
isEnforceRange=argument.enforceRange,
|
isEnforceRange=argument.enforceRange,
|
||||||
isClamp=argument.clamp)
|
isClamp=argument.clamp,
|
||||||
|
allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull())
|
||||||
|
|
||||||
if argument.optional and not argument.defaultValue:
|
if argument.optional and not argument.defaultValue:
|
||||||
declType = CGWrapper(declType, pre="Option<", post=">")
|
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)
|
return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes)
|
||||||
if retVal and type.isSpiderMonkeyInterface():
|
if retVal and type.isSpiderMonkeyInterface():
|
||||||
return True
|
return True
|
||||||
return type.isCallback() or type.isAny() or type.isObject()
|
return type.isAny() or type.isObject()
|
||||||
|
|
||||||
def typeRetValNeedsRooting(type):
|
def typeRetValNeedsRooting(type):
|
||||||
if type is None:
|
if type is None:
|
||||||
|
@ -958,9 +988,11 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
|
||||||
result = CGWrapper(result, pre="Option<", post=">")
|
result = CGWrapper(result, pre="Option<", post=">")
|
||||||
return result
|
return result
|
||||||
if returnType.isCallback():
|
if returnType.isCallback():
|
||||||
# XXXbz we're going to assume that callback types are always
|
result = CGGeneric('%s::%s' % (returnType.unroll().module(),
|
||||||
# nullable for now.
|
returnType.unroll().identifier.name))
|
||||||
return CGGeneric("*mut JSObject")
|
if returnType.nullable():
|
||||||
|
result = CGWrapper(result, pre="Option<", post=">")
|
||||||
|
return result
|
||||||
if returnType.isAny():
|
if returnType.isAny():
|
||||||
return CGGeneric("JSVal")
|
return CGGeneric("JSVal")
|
||||||
if returnType.isObject() or returnType.isSpiderMonkeyInterface():
|
if returnType.isObject() or returnType.isSpiderMonkeyInterface():
|
||||||
|
@ -1346,6 +1378,10 @@ class CGIfWrapper(CGWrapper):
|
||||||
CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
|
CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
|
||||||
post="\n}")
|
post="\n}")
|
||||||
|
|
||||||
|
class CGTemplatedType(CGWrapper):
|
||||||
|
def __init__(self, templateName, child):
|
||||||
|
CGWrapper.__init__(self, child, pre=templateName + "<", post=">")
|
||||||
|
|
||||||
class CGNamespace(CGWrapper):
|
class CGNamespace(CGWrapper):
|
||||||
def __init__(self, namespace, child, public=False):
|
def __init__(self, namespace, child, public=False):
|
||||||
pre = "%smod %s {\n" % ("pub " if public else "", namespace)
|
pre = "%smod %s {\n" % ("pub " if public else "", namespace)
|
||||||
|
@ -1565,23 +1601,32 @@ class CGGeneric(CGThing):
|
||||||
def define(self):
|
def define(self):
|
||||||
return self.text
|
return self.text
|
||||||
|
|
||||||
def getTypes(descriptor):
|
class CGCallbackTempRoot(CGGeneric):
|
||||||
"""
|
def __init__(self, name):
|
||||||
Get all argument and return types for all members of the descriptor
|
val = "%s::new(tempRoot)" % name
|
||||||
"""
|
define = """{
|
||||||
members = [m for m in descriptor.interface.members]
|
let tempRoot = ${val}.to_object();
|
||||||
if descriptor.interface.ctor():
|
%s
|
||||||
members.append(descriptor.interface.ctor())
|
}""" % val
|
||||||
signatures = [s for m in members if m.isMethod() for s in m.signatures()]
|
CGGeneric.__init__(self, define)
|
||||||
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 getAllTypes(descriptors, dictionaries, callbacks):
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
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):
|
def SortedTuples(l):
|
||||||
"""
|
"""
|
||||||
|
@ -1598,24 +1643,23 @@ def SortedDictValues(d):
|
||||||
# We're only interested in the values.
|
# We're only interested in the values.
|
||||||
return (i[1] for i in d)
|
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
|
Returns a CGList containing CGUnionStructs for every union.
|
||||||
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.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Now find all the things we'll need as arguments and return values because
|
# Now find all the things we'll need as arguments and return values because
|
||||||
# we need to wrap or unwrap them.
|
# we need to wrap or unwrap them.
|
||||||
unionStructs = dict()
|
unionStructs = dict()
|
||||||
for d in descriptors:
|
for (t, descriptor, dictionary) in getAllTypes(descriptors, dictionaries, callbacks):
|
||||||
for t in getTypes(d):
|
assert not descriptor or not dictionary
|
||||||
t = t.unroll()
|
t = t.unroll()
|
||||||
if t.isUnion():
|
if not t.isUnion():
|
||||||
|
continue
|
||||||
name = str(t)
|
name = str(t)
|
||||||
if not name in unionStructs:
|
if not name in unionStructs:
|
||||||
unionStructs[name] = CGList([CGUnionStruct(t, d), CGUnionConversionStruct(t, d)])
|
provider = descriptor or config.getDescriptorProvider()
|
||||||
|
unionStructs[name] = CGList([CGUnionStruct(t, provider), CGUnionConversionStruct(t, provider)])
|
||||||
|
|
||||||
return CGList(SortedDictValues(unionStructs), "\n\n")
|
return CGList(SortedDictValues(unionStructs), "\n\n")
|
||||||
|
|
||||||
|
@ -2301,15 +2345,19 @@ class FakeArgument():
|
||||||
A class that quacks like an IDLArgument. This is used to make
|
A class that quacks like an IDLArgument. This is used to make
|
||||||
setters look like method calls or for special operations.
|
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.type = type
|
||||||
self.optional = False
|
self.optional = False
|
||||||
self.variadic = False
|
self.variadic = False
|
||||||
self.defaultValue = None
|
self.defaultValue = None
|
||||||
|
self._allowTreatNonObjectAsNull = allowTreatNonObjectAsNull
|
||||||
self.treatNullAs = interfaceMember.treatNullAs
|
self.treatNullAs = interfaceMember.treatNullAs
|
||||||
self.enforceRange = False
|
self.enforceRange = False
|
||||||
self.clamp = False
|
self.clamp = False
|
||||||
|
|
||||||
|
def allowTreatNonCallableAsNull(self):
|
||||||
|
return self._allowTreatNonObjectAsNull
|
||||||
|
|
||||||
class CGSetterCall(CGPerSignatureCall):
|
class CGSetterCall(CGPerSignatureCall):
|
||||||
"""
|
"""
|
||||||
A class to generate a native object setter call for a particular IDL
|
A class to generate a native object setter call for a particular IDL
|
||||||
|
@ -2317,7 +2365,7 @@ class CGSetterCall(CGPerSignatureCall):
|
||||||
"""
|
"""
|
||||||
def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr):
|
def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr):
|
||||||
CGPerSignatureCall.__init__(self, None, argsPre,
|
CGPerSignatureCall.__init__(self, None, argsPre,
|
||||||
[FakeArgument(argType, attr)],
|
[FakeArgument(argType, attr, allowTreatNonObjectAsNull=True)],
|
||||||
nativeMethodName, False, descriptor, attr,
|
nativeMethodName, False, descriptor, attr,
|
||||||
setter=True)
|
setter=True)
|
||||||
def wrap_return_value(self):
|
def wrap_return_value(self):
|
||||||
|
@ -2702,9 +2750,22 @@ class CGUnionStruct(CGThing):
|
||||||
enumValues = [
|
enumValues = [
|
||||||
" e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars
|
" e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars
|
||||||
]
|
]
|
||||||
return ("pub enum %s {\n"
|
enumConversions = [
|
||||||
"%s\n"
|
" e%s(ref inner) => inner.to_jsval(cx)," % v["name"] for v in templateVars
|
||||||
"}\n") % (self.type, "\n".join(enumValues))
|
]
|
||||||
|
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):
|
class CGUnionConversionStruct(CGThing):
|
||||||
|
@ -3128,7 +3189,7 @@ class ClassMember(ClassItem):
|
||||||
ClassItem.__init__(self, name, visibility)
|
ClassItem.__init__(self, name, visibility)
|
||||||
|
|
||||||
def declare(self, cgClass):
|
def declare(self, cgClass):
|
||||||
return '%s: %s,\n' % (self.name, self.type)
|
return '%s %s: %s,\n' % (self.visibility, self.name, self.type)
|
||||||
|
|
||||||
def define(self, cgClass):
|
def define(self, cgClass):
|
||||||
if not self.static:
|
if not self.static:
|
||||||
|
@ -4162,14 +4223,17 @@ class CGBindingRoot(CGThing):
|
||||||
for d in dictionaries])
|
for d in dictionaries])
|
||||||
|
|
||||||
# Do codegen for all the callbacks.
|
# 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)
|
for c in mainCallbacks)
|
||||||
|
|
||||||
# Do codegen for all the descriptors
|
# Do codegen for all the descriptors
|
||||||
cgthings.extend([CGDescriptor(x) for x in descriptors])
|
cgthings.extend([CGDescriptor(x) for x in descriptors])
|
||||||
|
|
||||||
# Do codegen for all the callback interfaces.
|
# 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
|
# And make sure we have the right number of newlines at the end
|
||||||
curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
|
curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
|
||||||
|
@ -4228,7 +4292,7 @@ class CGBindingRoot(CGThing):
|
||||||
'dom::bindings::utils::VoidVal',
|
'dom::bindings::utils::VoidVal',
|
||||||
'dom::bindings::utils::get_dictionary_property',
|
'dom::bindings::utils::get_dictionary_property',
|
||||||
'dom::bindings::trace::JSTraceable',
|
'dom::bindings::trace::JSTraceable',
|
||||||
'dom::bindings::callback::{CallbackContainer,CallbackInterface}',
|
'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
|
||||||
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
|
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
|
||||||
'dom::bindings::callback::{WrapCallThisObject}',
|
'dom::bindings::callback::{WrapCallThisObject}',
|
||||||
'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}',
|
'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}',
|
||||||
|
@ -4314,8 +4378,9 @@ class CGNativeMember(ClassMethod):
|
||||||
elif type.isPrimitive() and type.tag() in builtinNames:
|
elif type.isPrimitive() and type.tag() in builtinNames:
|
||||||
result = CGGeneric(builtinNames[type.tag()])
|
result = CGGeneric(builtinNames[type.tag()])
|
||||||
if type.nullable():
|
if type.nullable():
|
||||||
result = CGTemplatedType("Nullable", result)
|
raise TypeError("Nullable primitives are not supported here.")
|
||||||
typeDecl, template = result.define(), "return ${declName};"
|
|
||||||
|
typeDecl, template = result.define(), "return Ok(${declName});"
|
||||||
elif type.isDOMString():
|
elif type.isDOMString():
|
||||||
if isMember:
|
if isMember:
|
||||||
# No need for a third element in the isMember case
|
# No need for a third element in the isMember case
|
||||||
|
@ -4355,7 +4420,7 @@ class CGNativeMember(ClassMethod):
|
||||||
("already_AddRefed<%s>" % type.unroll().identifier.name,
|
("already_AddRefed<%s>" % type.unroll().identifier.name,
|
||||||
"return ${declName}.forget();")
|
"return ${declName}.forget();")
|
||||||
elif type.isAny():
|
elif type.isAny():
|
||||||
typeDecl, template = "JS::Value", "return ${declName};"
|
typeDecl, template = "JSVal", "return Ok(${declName});"
|
||||||
elif type.isObject():
|
elif type.isObject():
|
||||||
typeDecl, template = "JSObject*", "return ${declName};"
|
typeDecl, template = "JSObject*", "return ${declName};"
|
||||||
elif type.isSpiderMonkeyInterface():
|
elif type.isSpiderMonkeyInterface():
|
||||||
|
@ -4454,7 +4519,7 @@ class CGNativeMember(ClassMethod):
|
||||||
if type.isUnion():
|
if type.isUnion():
|
||||||
if type.nullable():
|
if type.nullable():
|
||||||
type = type.inner
|
type = type.inner
|
||||||
return str(type), True, True
|
return str(type), False, True
|
||||||
|
|
||||||
if type.isGeckoInterface() and not type.isCallbackInterface():
|
if type.isGeckoInterface() and not type.isCallbackInterface():
|
||||||
iface = type.unroll().inner
|
iface = type.unroll().inner
|
||||||
|
@ -4484,10 +4549,7 @@ class CGNativeMember(ClassMethod):
|
||||||
return type.name, True, True
|
return type.name, True, True
|
||||||
|
|
||||||
if type.isDOMString():
|
if type.isDOMString():
|
||||||
if isMember:
|
declType = "DOMString"
|
||||||
declType = "nsString"
|
|
||||||
else:
|
|
||||||
declType = "nsAString"
|
|
||||||
return declType, True, False
|
return declType, True, False
|
||||||
|
|
||||||
if type.isByteString():
|
if type.isByteString():
|
||||||
|
@ -4520,7 +4582,7 @@ class CGNativeMember(ClassMethod):
|
||||||
if isMember:
|
if isMember:
|
||||||
declType = "JS::Value"
|
declType = "JS::Value"
|
||||||
else:
|
else:
|
||||||
declType = "JS::Handle<JS::Value>"
|
declType = "JSVal"
|
||||||
return declType, False, False
|
return declType, False, False
|
||||||
|
|
||||||
if type.isObject():
|
if type.isObject():
|
||||||
|
@ -4561,8 +4623,8 @@ class CGNativeMember(ClassMethod):
|
||||||
elif optional:
|
elif optional:
|
||||||
# Note: All variadic args claim to be optional, but we can just use
|
# Note: All variadic args claim to be optional, but we can just use
|
||||||
# empty arrays to represent them not being present.
|
# empty arrays to represent them not being present.
|
||||||
decl = CGTemplatedType("Optional", decl)
|
decl = CGTemplatedType("Option", decl)
|
||||||
ref = True
|
ref = False
|
||||||
return (decl, ref)
|
return (decl, ref)
|
||||||
|
|
||||||
def getArg(self, arg):
|
def getArg(self, arg):
|
||||||
|
@ -4573,7 +4635,7 @@ class CGNativeMember(ClassMethod):
|
||||||
arg.optional and not arg.defaultValue,
|
arg.optional and not arg.defaultValue,
|
||||||
"Variadic" if arg.variadic else False)
|
"Variadic" if arg.variadic else False)
|
||||||
if ref:
|
if ref:
|
||||||
decl = CGWrapper(decl, pre="const ", post="&")
|
decl = CGWrapper(decl, pre="&")
|
||||||
|
|
||||||
return Argument(decl.define(), arg.identifier.name)
|
return Argument(decl.define(), arg.identifier.name)
|
||||||
|
|
||||||
|
@ -4641,39 +4703,37 @@ class CGCallback(CGClass):
|
||||||
|
|
||||||
# And now insert our template argument.
|
# And now insert our template argument.
|
||||||
argsWithoutThis = list(args)
|
argsWithoutThis = list(args)
|
||||||
args.insert(0, Argument("Box<T>", "thisObj"))
|
args.insert(0, Argument("&JSRef<T>", "thisObj"))
|
||||||
|
|
||||||
# And the self argument
|
# And the self argument
|
||||||
method.args.insert(0, Argument(None, "&self"))
|
method.args.insert(0, Argument(None, "&self"))
|
||||||
args.insert(0, Argument(None, "&self"))
|
args.insert(0, Argument(None, "&self"))
|
||||||
argsWithoutThis.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"
|
"if s.GetContext().is_null() {\n"
|
||||||
" return Err(FailureUnknown);\n"
|
" return Err(FailureUnknown);\n"
|
||||||
"}\n")
|
"}\n")
|
||||||
|
|
||||||
bodyWithThis = string.Template(
|
bodyWithThis = string.Template(
|
||||||
setupCall+
|
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"
|
"if thisObjJS.is_null() {\n"
|
||||||
" return Err(FailureUnknown);\n"
|
" return Err(FailureUnknown);\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"return ${methodName}(${callArgs});").substitute({
|
"return ${methodName}(${callArgs});").substitute({
|
||||||
"callArgs" : ", ".join(argnamesWithThis),
|
"callArgs" : ", ".join(argnamesWithThis),
|
||||||
"methodName": 'self.' + method.name,
|
"methodName": 'self.' + method.name,
|
||||||
"cxProvider": 'thisObj'
|
|
||||||
})
|
})
|
||||||
bodyWithoutThis = string.Template(
|
bodyWithoutThis = string.Template(
|
||||||
setupCall +
|
setupCall +
|
||||||
"return ${methodName}(${callArgs});").substitute({
|
"return ${methodName}(${callArgs});").substitute({
|
||||||
"callArgs" : ", ".join(argnamesWithoutThis),
|
"callArgs" : ", ".join(argnamesWithoutThis),
|
||||||
"methodName": 'self.' + method.name,
|
"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,
|
return [ClassMethod(method.name+'_', method.returnType, args,
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
templateArgs=["T: 'static+CallbackContainer+Reflectable"],
|
templateArgs=["T: Reflectable"],
|
||||||
body=bodyWithThis,
|
body=bodyWithThis,
|
||||||
visibility='pub'),
|
visibility='pub'),
|
||||||
ClassMethod(method.name+'__', method.returnType, argsWithoutThis,
|
ClassMethod(method.name+'__', method.returnType, argsWithoutThis,
|
||||||
|
@ -4699,15 +4759,27 @@ class CGCallbackFunction(CGCallback):
|
||||||
methods=[CallCallback(callback, descriptorProvider)])
|
methods=[CallCallback(callback, descriptorProvider)])
|
||||||
|
|
||||||
def getConstructors(self):
|
def getConstructors(self):
|
||||||
return CGCallback.getConstructors(self) + [
|
return CGCallback.getConstructors(self)
|
||||||
ClassConstructor(
|
|
||||||
[Argument("CallbackFunction*", "aOther")],
|
class CGCallbackFunctionImpl(CGGeneric):
|
||||||
bodyInHeader=True,
|
def __init__(self, callback):
|
||||||
visibility="pub",
|
impl = string.Template("""impl CallbackContainer for ${type} {
|
||||||
explicit=True,
|
fn new(callback: *mut JSObject) -> ${type} {
|
||||||
baseConstructors=[
|
${type}::new(callback)
|
||||||
"CallbackFunction(aOther)"
|
}
|
||||||
])]
|
|
||||||
|
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):
|
class CGCallbackInterface(CGCallback):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
|
@ -4809,13 +4881,14 @@ class CallbackMember(CGNativeMember):
|
||||||
return CGList([
|
return CGList([
|
||||||
CGGeneric(pre),
|
CGGeneric(pre),
|
||||||
CGWrapper(CGIndenter(CGGeneric(body)),
|
CGWrapper(CGIndenter(CGGeneric(body)),
|
||||||
pre="with_compartment(cx, self.parent.callback, || {\n",
|
pre="with_compartment(cx, self.parent.callback(), || {\n",
|
||||||
post="})")
|
post="})")
|
||||||
], "\n").define()
|
], "\n").define()
|
||||||
|
|
||||||
def getResultConversion(self):
|
def getResultConversion(self):
|
||||||
replacements = {
|
replacements = {
|
||||||
"val": "rval",
|
"val": "rval",
|
||||||
|
"declName": "rvalDecl",
|
||||||
}
|
}
|
||||||
|
|
||||||
if isJSImplementedDescriptor(self.descriptorProvider):
|
if isJSImplementedDescriptor(self.descriptorProvider):
|
||||||
|
@ -4867,19 +4940,10 @@ class CallbackMember(CGNativeMember):
|
||||||
else:
|
else:
|
||||||
jsvalIndex = "%d" % i
|
jsvalIndex = "%d" % i
|
||||||
if arg.optional and not arg.defaultValue:
|
if arg.optional and not arg.defaultValue:
|
||||||
argval += ".Value()"
|
argval += ".clone().unwrap()"
|
||||||
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 = ""
|
|
||||||
|
|
||||||
conversion = prepend + wrapForType("*argv.get_mut(%s)" % jsvalIndex,
|
conversion = wrapForType("*argv.get_mut(%s)" % jsvalIndex,
|
||||||
result=result,
|
result=argval,
|
||||||
successCode="continue;" if arg.variadic else "break;")
|
successCode="continue;" if arg.variadic else "break;")
|
||||||
if arg.variadic:
|
if arg.variadic:
|
||||||
conversion = string.Template(
|
conversion = string.Template(
|
||||||
|
@ -4890,12 +4954,12 @@ class CallbackMember(CGNativeMember):
|
||||||
elif arg.optional and not arg.defaultValue:
|
elif arg.optional and not arg.defaultValue:
|
||||||
conversion = (
|
conversion = (
|
||||||
CGIfWrapper(CGGeneric(conversion),
|
CGIfWrapper(CGGeneric(conversion),
|
||||||
"%s.WasPassed()" % arg.identifier.name).define() +
|
"%s.is_some()" % arg.identifier.name).define() +
|
||||||
" else if (argc == %d) {\n"
|
" else if (argc == %d) {\n"
|
||||||
" // This is our current trailing argument; reduce argc\n"
|
" // This is our current trailing argument; reduce argc\n"
|
||||||
" --argc;\n"
|
" argc -= 1;\n"
|
||||||
"} else {\n"
|
"} else {\n"
|
||||||
" argv[%d] = JS::UndefinedValue();\n"
|
" *argv.get_mut(%d) = UndefinedValue();\n"
|
||||||
"}" % (i+1, i))
|
"}" % (i+1, i))
|
||||||
return conversion
|
return conversion
|
||||||
|
|
||||||
|
@ -4937,7 +5001,7 @@ class CallbackMember(CGNativeMember):
|
||||||
})
|
})
|
||||||
|
|
||||||
def getArgcDecl(self):
|
def getArgcDecl(self):
|
||||||
return CGGeneric("let argc = %su32;" % self.argCountStr);
|
return CGGeneric("let mut argc = %su32;" % self.argCountStr);
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ensureASCIIName(idlObject):
|
def ensureASCIIName(idlObject):
|
||||||
|
@ -4990,7 +5054,7 @@ class CallCallback(CallbackMethod):
|
||||||
return "aThisObj"
|
return "aThisObj"
|
||||||
|
|
||||||
def getCallableDecl(self):
|
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):
|
class CallbackOperationBase(CallbackMethod):
|
||||||
"""
|
"""
|
||||||
|
@ -5003,11 +5067,11 @@ class CallbackOperationBase(CallbackMethod):
|
||||||
|
|
||||||
def getThisObj(self):
|
def getThisObj(self):
|
||||||
if not self.singleOperation:
|
if not self.singleOperation:
|
||||||
return "self.parent.callback"
|
return "self.parent.callback()"
|
||||||
# This relies on getCallableDecl declaring a boolean
|
# This relies on getCallableDecl declaring a boolean
|
||||||
# isCallable in the case when we're a single-operation
|
# isCallable in the case when we're a single-operation
|
||||||
# interface.
|
# interface.
|
||||||
return "if isCallable { aThisObj } else { self.parent.callback }"
|
return "if isCallable { aThisObj } else { self.parent.callback() }"
|
||||||
|
|
||||||
def getCallableDecl(self):
|
def getCallableDecl(self):
|
||||||
replacements = {
|
replacements = {
|
||||||
|
@ -5021,11 +5085,11 @@ class CallbackOperationBase(CallbackMethod):
|
||||||
if not self.singleOperation:
|
if not self.singleOperation:
|
||||||
return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
|
return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
|
||||||
return (
|
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' +
|
'let callable =\n' +
|
||||||
CGIndenter(
|
CGIndenter(
|
||||||
CGIfElseWrapper('isCallable',
|
CGIfElseWrapper('isCallable',
|
||||||
CGGeneric('unsafe { ObjectValue(&*self.parent.callback) }'),
|
CGGeneric('unsafe { ObjectValue(&*self.parent.callback()) }'),
|
||||||
CGGeneric(getCallableFromProp))).define() + ';\n')
|
CGGeneric(getCallableFromProp))).define() + ';\n')
|
||||||
|
|
||||||
class CallbackOperation(CallbackOperationBase):
|
class CallbackOperation(CallbackOperationBase):
|
||||||
|
@ -5233,12 +5297,16 @@ class GlobalGenRoots():
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def UnionTypes(config):
|
def UnionTypes(config):
|
||||||
|
|
||||||
curr = UnionTypes(config.getDescriptors())
|
curr = UnionTypes(config.getDescriptors(),
|
||||||
|
config.getDictionaries(),
|
||||||
|
config.getCallbacks(),
|
||||||
|
config)
|
||||||
|
|
||||||
curr = CGImports(curr, [], [
|
curr = CGImports(curr, [], [
|
||||||
'dom::bindings::utils::unwrap_jsmanaged',
|
'dom::bindings::utils::unwrap_jsmanaged',
|
||||||
'dom::bindings::codegen::PrototypeList',
|
'dom::bindings::codegen::PrototypeList',
|
||||||
'dom::bindings::conversions::FromJSValConvertible',
|
'dom::bindings::conversions::FromJSValConvertible',
|
||||||
|
'dom::bindings::conversions::ToJSValConvertible',
|
||||||
'dom::bindings::conversions::Default',
|
'dom::bindings::conversions::Default',
|
||||||
'dom::bindings::error::throw_not_in_union',
|
'dom::bindings::error::throw_not_in_union',
|
||||||
'dom::bindings::js::JS',
|
'dom::bindings::js::JS',
|
||||||
|
|
|
@ -76,7 +76,11 @@ class Configuration:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _filterForFile(items, webIDLFile=""):
|
def _filterForFile(items, webIDLFile=""):
|
||||||
"""Gets the items that match the given filters."""
|
"""Gets the items that match the given filters."""
|
||||||
|
if not webIDLFile:
|
||||||
|
return items
|
||||||
|
|
||||||
return filter(lambda x: x.filename() == webIDLFile, items)
|
return filter(lambda x: x.filename() == webIDLFile, items)
|
||||||
|
|
||||||
def getDictionaries(self, webIDLFile=""):
|
def getDictionaries(self, webIDLFile=""):
|
||||||
return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile)
|
return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile)
|
||||||
def getCallbacks(self, webIDLFile=""):
|
def getCallbacks(self, webIDLFile=""):
|
||||||
|
@ -269,3 +273,54 @@ class Descriptor(DescriptorProvider):
|
||||||
throws = member.getExtendedAttribute(throwsAttr)
|
throws = member.getExtendedAttribute(throwsAttr)
|
||||||
maybeAppendInfallibleToAttrs(attrs, throws)
|
maybeAppendInfallibleToAttrs(attrs, throws)
|
||||||
return attrs
|
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
|
||||||
|
|
|
@ -464,6 +464,10 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
self._callback = False
|
self._callback = False
|
||||||
self._finished = False
|
self._finished = False
|
||||||
self.members = []
|
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.implementedInterfaces = set()
|
||||||
self._consequential = False
|
self._consequential = False
|
||||||
self._isPartial = True
|
self._isPartial = True
|
||||||
|
@ -696,6 +700,9 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
if identifier == "TreatNonCallableAsNull":
|
if identifier == "TreatNonCallableAsNull":
|
||||||
raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces",
|
raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces",
|
||||||
[attr.location, self.location])
|
[attr.location, self.location])
|
||||||
|
if identifier == "TreatNonObjectAsNull":
|
||||||
|
raise WebIDLError("TreatNonObjectAsNull cannot be specified on interfaces",
|
||||||
|
[attr.location, self.location])
|
||||||
elif identifier == "NoInterfaceObject":
|
elif identifier == "NoInterfaceObject":
|
||||||
if not attr.noArguments():
|
if not attr.noArguments():
|
||||||
raise WebIDLError("[NoInterfaceObject] must take no arguments",
|
raise WebIDLError("[NoInterfaceObject] must take no arguments",
|
||||||
|
@ -1049,11 +1056,12 @@ class IDLType(IDLObject):
|
||||||
assert False # Override me!
|
assert False # Override me!
|
||||||
|
|
||||||
def treatNonCallableAsNull(self):
|
def treatNonCallableAsNull(self):
|
||||||
if not (self.nullable() and self.tag() == IDLType.Tags.callback):
|
assert self.tag() == IDLType.Tags.callback
|
||||||
raise WebIDLError("Type %s cannot be TreatNonCallableAsNull" % self,
|
return self.nullable() and self.inner._treatNonCallableAsNull
|
||||||
[self.location])
|
|
||||||
|
|
||||||
return hasattr(self, "_treatNonCallableAsNull")
|
def treatNonObjectAsNull(self):
|
||||||
|
assert self.tag() == IDLType.Tags.callback
|
||||||
|
return self.nullable() and self.inner._treatNonObjectAsNull
|
||||||
|
|
||||||
def markTreatNonCallableAsNull(self):
|
def markTreatNonCallableAsNull(self):
|
||||||
assert not self.treatNonCallableAsNull()
|
assert not self.treatNonCallableAsNull()
|
||||||
|
@ -2189,6 +2197,7 @@ class IDLArgument(IDLObjectWithIdentifier):
|
||||||
self._isComplete = False
|
self._isComplete = False
|
||||||
self.enforceRange = False
|
self.enforceRange = False
|
||||||
self.clamp = False
|
self.clamp = False
|
||||||
|
self._allowTreatNonCallableAsNull = False
|
||||||
|
|
||||||
assert not variadic or optional
|
assert not variadic or optional
|
||||||
|
|
||||||
|
@ -2215,6 +2224,8 @@ class IDLArgument(IDLObjectWithIdentifier):
|
||||||
raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive",
|
raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive",
|
||||||
[self.location]);
|
[self.location]);
|
||||||
self.enforceRange = True
|
self.enforceRange = True
|
||||||
|
elif identifier == "TreatNonCallableAsNull":
|
||||||
|
self._allowTreatNonCallableAsNull = True
|
||||||
else:
|
else:
|
||||||
raise WebIDLError("Unhandled extended attribute on an argument",
|
raise WebIDLError("Unhandled extended attribute on an argument",
|
||||||
[attribute.location])
|
[attribute.location])
|
||||||
|
@ -2247,6 +2258,9 @@ class IDLArgument(IDLObjectWithIdentifier):
|
||||||
self.location)
|
self.location)
|
||||||
assert self.defaultValue
|
assert self.defaultValue
|
||||||
|
|
||||||
|
def allowTreatNonCallableAsNull(self):
|
||||||
|
return self._allowTreatNonCallableAsNull
|
||||||
|
|
||||||
def _getDependentObjects(self):
|
def _getDependentObjects(self):
|
||||||
deps = set([self.type])
|
deps = set([self.type])
|
||||||
if self.defaultValue:
|
if self.defaultValue:
|
||||||
|
@ -2269,6 +2283,12 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
|
||||||
for argument in arguments:
|
for argument in arguments:
|
||||||
argument.resolve(self)
|
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):
|
def isCallback(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -2308,6 +2328,21 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
|
||||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||||
other.isNonCallbackInterface() or other.isDate())
|
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):
|
def _getDependentObjects(self):
|
||||||
return set([self._returnType] + self._arguments)
|
return set([self._returnType] + self._arguments)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use dom::bindings::utils::jsstring_to_str;
|
||||||
use dom::bindings::utils::unwrap_jsmanaged;
|
use dom::bindings::utils::unwrap_jsmanaged;
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
|
||||||
use js::jsapi::{JSBool, JSContext};
|
use js::jsapi::{JSBool, JSContext, JSObject};
|
||||||
use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64};
|
use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64};
|
||||||
use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32};
|
use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32};
|
||||||
use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean};
|
use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean};
|
||||||
|
@ -18,7 +18,7 @@ use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN};
|
||||||
use js::jsapi::{JS_WrapValue};
|
use js::jsapi::{JS_WrapValue};
|
||||||
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};
|
use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};
|
||||||
use js::glue::RUST_JS_NumberValue;
|
use js::glue::RUST_JS_NumberValue;
|
||||||
use libc;
|
use libc;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
@ -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> {
|
impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
|
||||||
fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
|
fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
|
||||||
match self {
|
match self {
|
||||||
|
@ -348,3 +354,13 @@ impl<X: Default, T: FromJSValConvertible<X>> FromJSValConvertible<()> for Option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToJSValConvertible for *mut JSObject {
|
||||||
|
fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
|
||||||
|
let mut wrapped = ObjectOrNullValue(*self);
|
||||||
|
unsafe {
|
||||||
|
assert!(JS_WrapValue(cx, &mut wrapped) != 0);
|
||||||
|
}
|
||||||
|
wrapped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
/// 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
|
/// (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.
|
/// for that new concrete type to achieve magic compiler-derived trace hooks.
|
||||||
|
#[deriving(Eq, Clone)]
|
||||||
pub struct Traceable<T> {
|
pub struct Traceable<T> {
|
||||||
inner: T
|
inner: T
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* 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::{DocumentDerived, EventCast, HTMLElementCast};
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
|
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
|
||||||
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast};
|
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast};
|
||||||
|
use dom::bindings::codegen::InheritTypes::EventTargetCast;
|
||||||
use dom::bindings::codegen::BindingDeclarations::DocumentBinding;
|
use dom::bindings::codegen::BindingDeclarations::DocumentBinding;
|
||||||
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, TemporaryPushable};
|
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, TemporaryPushable};
|
||||||
use dom::bindings::js::OptionalRootable;
|
use dom::bindings::js::OptionalRootable;
|
||||||
|
@ -21,7 +23,7 @@ use dom::element::{Element, AttributeHandlers, get_attribute_parts};
|
||||||
use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
||||||
use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId};
|
use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId};
|
||||||
use dom::event::Event;
|
use dom::event::Event;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
|
||||||
use dom::htmlcollection::{HTMLCollection, CollectionFilter};
|
use dom::htmlcollection::{HTMLCollection, CollectionFilter};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmlheadelement::HTMLHeadElement;
|
use dom::htmlheadelement::HTMLHeadElement;
|
||||||
|
@ -325,6 +327,8 @@ pub trait DocumentMethods {
|
||||||
fn Applets(&self) -> Temporary<HTMLCollection>;
|
fn Applets(&self) -> Temporary<HTMLCollection>;
|
||||||
fn Location(&mut self) -> Temporary<Location>;
|
fn Location(&mut self) -> Temporary<Location>;
|
||||||
fn Children(&self) -> Temporary<HTMLCollection>;
|
fn Children(&self) -> Temporary<HTMLCollection>;
|
||||||
|
fn GetOnload(&self) -> Option<EventHandlerNonNull>;
|
||||||
|
fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DocumentMethods for JSRef<'a, Document> {
|
impl<'a> DocumentMethods for JSRef<'a, Document> {
|
||||||
|
@ -804,4 +808,14 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
|
||||||
let window = self.window.root();
|
let window = self.window.root();
|
||||||
HTMLCollection::children(&*window, NodeCast::from_ref(self))
|
HTMLCollection::children(&*window, NodeCast::from_ref(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn GetOnload(&self) -> Option<EventHandlerNonNull> {
|
||||||
|
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
|
||||||
|
eventtarget.get_event_handler_common("load")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
|
||||||
|
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
|
||||||
|
eventtarget.set_event_handler_common("load", listener)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub fn dispatch_event<'a, 'b>(target: &JSRef<'a, EventTarget>,
|
||||||
for listener in listeners.iter() {
|
for listener in listeners.iter() {
|
||||||
//FIXME: this should have proper error handling, or explicitly
|
//FIXME: this should have proper error handling, or explicitly
|
||||||
// drop the exception on the floor
|
// 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 {
|
if event.deref().stop_immediate {
|
||||||
break;
|
break;
|
||||||
|
@ -80,7 +80,7 @@ pub fn dispatch_event<'a, 'b>(target: &JSRef<'a, EventTarget>,
|
||||||
for listener in listeners.iter() {
|
for listener in listeners.iter() {
|
||||||
//FIXME: this should have proper error handling, or explicitly drop the
|
//FIXME: this should have proper error handling, or explicitly drop the
|
||||||
// exception on the floor.
|
// exception on the floor.
|
||||||
assert!(listener.HandleEvent__(event, ReportExceptions).is_ok());
|
assert!(listener.HandleEvent_(target, event, ReportExceptions).is_ok());
|
||||||
if event.deref().stop_immediate {
|
if event.deref().stop_immediate {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ pub fn dispatch_event<'a, 'b>(target: &JSRef<'a, EventTarget>,
|
||||||
for listener in listeners.iter() {
|
for listener in listeners.iter() {
|
||||||
//FIXME: this should have proper error handling or explicitly
|
//FIXME: this should have proper error handling or explicitly
|
||||||
// drop exceptions on the floor.
|
// 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 {
|
if event.deref().stop_immediate {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2,16 +2,23 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
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::js::JSRef;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::bindings::error::{Fallible, InvalidState};
|
|
||||||
use dom::bindings::codegen::BindingDeclarations::EventListenerBinding::EventListener;
|
|
||||||
use dom::event::Event;
|
use dom::event::Event;
|
||||||
use dom::eventdispatcher::dispatch_event;
|
use dom::eventdispatcher::dispatch_event;
|
||||||
use dom::node::NodeTypeId;
|
use dom::node::NodeTypeId;
|
||||||
use dom::xmlhttprequest::XMLHttpRequestId;
|
use dom::xmlhttprequest::XMLHttpRequestId;
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use js::jsapi::{JS_CompileUCFunction, JS_GetFunctionObject, JS_CloneFunctionObject};
|
||||||
|
use js::jsapi::{JSContext, JSObject};
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
use libc::{c_char, size_t};
|
||||||
|
use std::ptr;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use collections::hashmap::HashMap;
|
use collections::hashmap::HashMap;
|
||||||
|
|
||||||
|
@ -28,10 +35,24 @@ pub enum EventTargetTypeId {
|
||||||
XMLHttpRequestTargetTypeId(XMLHttpRequestId)
|
XMLHttpRequestTargetTypeId(XMLHttpRequestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Eq, Encodable)]
|
||||||
|
pub enum EventListenerType {
|
||||||
|
Additive(EventListener),
|
||||||
|
Inline(EventListener),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventListenerType {
|
||||||
|
fn get_listener(&self) -> EventListener {
|
||||||
|
match *self {
|
||||||
|
Additive(listener) | Inline(listener) => listener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(Eq,Encodable)]
|
#[deriving(Eq,Encodable)]
|
||||||
pub struct EventListenerEntry {
|
pub struct EventListenerEntry {
|
||||||
pub phase: ListenerPhase,
|
pub phase: ListenerPhase,
|
||||||
pub listener: EventListener
|
pub listener: EventListenerType
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable)]
|
||||||
|
@ -52,7 +73,7 @@ impl EventTarget {
|
||||||
|
|
||||||
pub fn get_listeners(&self, type_: &str) -> Option<Vec<EventListener>> {
|
pub fn get_listeners(&self, type_: &str) -> Option<Vec<EventListener>> {
|
||||||
self.handlers.find_equiv(&type_).map(|listeners| {
|
self.handlers.find_equiv(&type_).map(|listeners| {
|
||||||
listeners.iter().map(|entry| entry.listener).collect()
|
listeners.iter().map(|entry| entry.listener.get_listener()).collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +81,7 @@ impl EventTarget {
|
||||||
-> Option<Vec<EventListener>> {
|
-> Option<Vec<EventListener>> {
|
||||||
self.handlers.find_equiv(&type_).map(|listeners| {
|
self.handlers.find_equiv(&type_).map(|listeners| {
|
||||||
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
|
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
|
||||||
filtered.map(|entry| entry.listener).collect()
|
filtered.map(|entry| entry.listener.get_listener()).collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +90,19 @@ pub trait EventTargetHelpers {
|
||||||
fn dispatch_event_with_target<'a>(&self,
|
fn dispatch_event_with_target<'a>(&self,
|
||||||
target: Option<JSRef<'a, EventTarget>>,
|
target: Option<JSRef<'a, EventTarget>>,
|
||||||
event: &mut JSRef<Event>) -> Fallible<bool>;
|
event: &mut JSRef<Event>) -> Fallible<bool>;
|
||||||
|
fn set_inline_event_listener(&mut self,
|
||||||
|
ty: DOMString,
|
||||||
|
listener: Option<EventListener>);
|
||||||
|
fn get_inline_event_listener(&self, ty: DOMString) -> Option<EventListener>;
|
||||||
|
fn set_event_handler_uncompiled(&mut self,
|
||||||
|
cx: *mut JSContext,
|
||||||
|
url: Url,
|
||||||
|
scope: *mut JSObject,
|
||||||
|
ty: &str,
|
||||||
|
source: DOMString);
|
||||||
|
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> {
|
impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
|
||||||
|
@ -80,6 +114,91 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
|
||||||
}
|
}
|
||||||
Ok(dispatch_event(self, target, event))
|
Ok(dispatch_event(self, target, event))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_inline_event_listener(&mut self,
|
||||||
|
ty: DOMString,
|
||||||
|
listener: Option<EventListener>) {
|
||||||
|
let entries = self.handlers.find_or_insert_with(ty, |_| vec!());
|
||||||
|
let idx = entries.iter().position(|&entry| {
|
||||||
|
match entry.listener {
|
||||||
|
Inline(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match idx {
|
||||||
|
Some(idx) => {
|
||||||
|
match listener {
|
||||||
|
Some(listener) => entries.get_mut(idx).listener = Inline(listener),
|
||||||
|
None => {
|
||||||
|
entries.remove(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if listener.is_some() {
|
||||||
|
entries.push(EventListenerEntry {
|
||||||
|
phase: Bubbling,
|
||||||
|
listener: Inline(listener.unwrap()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_inline_event_listener(&self, ty: DOMString) -> Option<EventListener> {
|
||||||
|
let entries = self.handlers.find(&ty);
|
||||||
|
entries.and_then(|entries| entries.iter().find(|entry| {
|
||||||
|
match entry.listener {
|
||||||
|
Inline(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}).map(|entry| entry.listener.get_listener()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_event_handler_uncompiled(&mut self,
|
||||||
|
cx: *mut JSContext,
|
||||||
|
url: Url,
|
||||||
|
scope: *mut JSObject,
|
||||||
|
ty: &str,
|
||||||
|
source: DOMString) {
|
||||||
|
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
|
||||||
|
|
||||||
|
let nargs = 1; //XXXjdm not true for onerror
|
||||||
|
static arg_name: [c_char, ..6] =
|
||||||
|
['e' as c_char, 'v' as c_char, 'e' as c_char, 'n' as c_char, 't' as c_char, 0];
|
||||||
|
static arg_names: [*c_char, ..1] = [&arg_name as *c_char];
|
||||||
|
|
||||||
|
let source = source.to_utf16();
|
||||||
|
let handler =
|
||||||
|
name.with_ref(|name| {
|
||||||
|
url.with_ref(|url| { unsafe {
|
||||||
|
let fun = JS_CompileUCFunction(cx, ptr::mut_null(), name,
|
||||||
|
nargs, &arg_names as **i8 as *mut *i8, source.as_ptr(),
|
||||||
|
source.len() as size_t,
|
||||||
|
url, lineno);
|
||||||
|
assert!(fun.is_not_null());
|
||||||
|
JS_GetFunctionObject(fun)
|
||||||
|
}})});
|
||||||
|
let funobj = unsafe { JS_CloneFunctionObject(cx, handler, scope) };
|
||||||
|
assert!(funobj.is_not_null());
|
||||||
|
self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj)))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<T: CallbackContainer>(&self, ty: &str) -> Option<T> {
|
||||||
|
let listener = self.get_inline_event_listener(ty.to_owned());
|
||||||
|
listener.map(|listener| CallbackContainer::new(listener.parent.callback()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventTargetMethods {
|
pub trait EventTargetMethods {
|
||||||
|
@ -104,7 +223,7 @@ impl<'a> EventTargetMethods for JSRef<'a, EventTarget> {
|
||||||
let phase = if capture { Capturing } else { Bubbling };
|
let phase = if capture { Capturing } else { Bubbling };
|
||||||
let new_entry = EventListenerEntry {
|
let new_entry = EventListenerEntry {
|
||||||
phase: phase,
|
phase: phase,
|
||||||
listener: listener
|
listener: Additive(listener)
|
||||||
};
|
};
|
||||||
if entry.as_slice().position_elem(&new_entry).is_none() {
|
if entry.as_slice().position_elem(&new_entry).is_none() {
|
||||||
entry.push(new_entry);
|
entry.push(new_entry);
|
||||||
|
@ -122,7 +241,7 @@ impl<'a> EventTargetMethods for JSRef<'a, EventTarget> {
|
||||||
let phase = if capture { Capturing } else { Bubbling };
|
let phase = if capture { Capturing } else { Bubbling };
|
||||||
let old_entry = EventListenerEntry {
|
let old_entry = EventListenerEntry {
|
||||||
phase: phase,
|
phase: phase,
|
||||||
listener: listener
|
listener: Additive(listener)
|
||||||
};
|
};
|
||||||
let position = entry.as_slice().position_elem(&old_entry);
|
let position = entry.as_slice().position_elem(&old_entry);
|
||||||
for &position in position.iter() {
|
for &position in position.iter() {
|
||||||
|
|
|
@ -3,14 +3,19 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::codegen::BindingDeclarations::HTMLBodyElementBinding;
|
use dom::bindings::codegen::BindingDeclarations::HTMLBodyElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLBodyElementDerived;
|
use dom::bindings::codegen::EventHandlerBinding::EventHandlerNonNull;
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
|
||||||
|
use dom::bindings::codegen::InheritTypes::EventTargetCast;
|
||||||
use dom::bindings::error::ErrorResult;
|
use dom::bindings::error::ErrorResult;
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary};
|
||||||
|
use dom::bindings::utils::Reflectable;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::HTMLBodyElementTypeId;
|
use dom::element::HTMLBodyElementTypeId;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, ElementNodeTypeId};
|
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
||||||
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use dom::window::WindowMethods;
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable)]
|
||||||
|
@ -50,6 +55,8 @@ pub trait HTMLBodyElementMethods {
|
||||||
fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult;
|
fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult;
|
||||||
fn Background(&self) -> DOMString;
|
fn Background(&self) -> DOMString;
|
||||||
fn SetBackground(&self, _background: DOMString) -> ErrorResult;
|
fn SetBackground(&self, _background: DOMString) -> ErrorResult;
|
||||||
|
fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
|
||||||
|
fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
|
impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
|
||||||
|
@ -100,4 +107,49 @@ impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
|
||||||
fn SetBackground(&self, _background: DOMString) -> ErrorResult {
|
fn SetBackground(&self, _background: DOMString) -> ErrorResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
|
||||||
|
let win = window_from_node(self).root();
|
||||||
|
win.deref().GetOnunload()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>) {
|
||||||
|
let mut win = window_from_node(self).root();
|
||||||
|
win.SetOnunload(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
|
||||||
|
fn super_type<'a>(&'a mut self) -> Option<&'a mut VirtualMethods:> {
|
||||||
|
let element: &mut JSRef<HTMLElement> = HTMLElementCast::from_mut_ref(self);
|
||||||
|
Some(element as &mut VirtualMethods:)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_set_attr(&mut self, name: DOMString, value: DOMString) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref mut s) => s.after_set_attr(name.clone(), value.clone()),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.starts_with("on") {
|
||||||
|
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 (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,18 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::codegen::BindingDeclarations::HTMLElementBinding;
|
use dom::bindings::codegen::BindingDeclarations::HTMLElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::ElementCast;
|
use dom::bindings::codegen::EventHandlerBinding::EventHandlerNonNull;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLElementDerived;
|
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived};
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived};
|
||||||
|
use dom::bindings::codegen::InheritTypes::EventTargetCast;
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary};
|
||||||
use dom::bindings::error::{ErrorResult, Fallible};
|
use dom::bindings::error::{ErrorResult, Fallible};
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::{Element, ElementTypeId, HTMLElementTypeId};
|
use dom::element::{Element, ElementTypeId, HTMLElementTypeId};
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::node::{Node, ElementNodeTypeId};
|
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use dom::window::WindowMethods;
|
||||||
use js::jsapi::JSContext;
|
use js::jsapi::JSContext;
|
||||||
use js::jsval::{JSVal, NullValue};
|
use js::jsval::{JSVal, NullValue};
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
|
@ -45,6 +48,17 @@ impl HTMLElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait PrivateHTMLElementHelpers {
|
||||||
|
fn is_body_or_frameset(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> {
|
||||||
|
fn is_body_or_frameset(&self) -> bool {
|
||||||
|
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
|
||||||
|
eventtarget.is_htmlbodyelement() || eventtarget.is_htmlframesetelement()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait HTMLElementMethods {
|
pub trait HTMLElementMethods {
|
||||||
fn Title(&self) -> DOMString;
|
fn Title(&self) -> DOMString;
|
||||||
fn SetTitle(&mut self, _title: DOMString);
|
fn SetTitle(&mut self, _title: DOMString);
|
||||||
|
@ -76,6 +90,8 @@ pub trait HTMLElementMethods {
|
||||||
fn OffsetLeft(&self) -> i32;
|
fn OffsetLeft(&self) -> i32;
|
||||||
fn OffsetWidth(&self) -> i32;
|
fn OffsetWidth(&self) -> i32;
|
||||||
fn OffsetHeight(&self) -> i32;
|
fn OffsetHeight(&self) -> i32;
|
||||||
|
fn GetOnload(&self) -> Option<EventHandlerNonNull>;
|
||||||
|
fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
|
impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
|
||||||
|
@ -195,6 +211,22 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
|
||||||
fn OffsetHeight(&self) -> i32 {
|
fn OffsetHeight(&self) -> i32 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn GetOnload(&self) -> Option<EventHandlerNonNull> {
|
||||||
|
if self.is_body_or_frameset() {
|
||||||
|
let win = window_from_node(self).root();
|
||||||
|
win.deref().GetOnload()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
|
||||||
|
if self.is_body_or_frameset() {
|
||||||
|
let mut win = window_from_node(self).root();
|
||||||
|
win.SetOnload(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VirtualMethods for JSRef<'a, HTMLElement> {
|
impl<'a> VirtualMethods for JSRef<'a, HTMLElement> {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use dom::bindings::js::{JS, JSRef, Temporary};
|
use dom::bindings::js::{JS, JSRef, Temporary};
|
||||||
use dom::bindings::codegen::BindingDeclarations::TestBindingBinding::TestEnum;
|
use dom::bindings::codegen::BindingDeclarations::TestBindingBinding::TestEnum;
|
||||||
use dom::bindings::codegen::BindingDeclarations::TestBindingBinding::TestEnumValues::_empty;
|
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::str::ByteString;
|
||||||
use dom::bindings::utils::{Reflector, Reflectable};
|
use dom::bindings::utils::{Reflector, Reflectable};
|
||||||
use dom::blob::Blob;
|
use dom::blob::Blob;
|
||||||
|
@ -136,7 +136,7 @@ pub trait TestBindingMethods {
|
||||||
fn PassEnum(&self, _: TestEnum) {}
|
fn PassEnum(&self, _: TestEnum) {}
|
||||||
fn PassInterface(&self, _: &JSRef<Blob>) {}
|
fn PassInterface(&self, _: &JSRef<Blob>) {}
|
||||||
fn PassUnion(&self, _: HTMLElementOrLong) {}
|
fn PassUnion(&self, _: HTMLElementOrLong) {}
|
||||||
fn PassUnion2(&self, _: StringOrFormData) {}
|
fn PassUnion2(&self, _: EventOrString) {}
|
||||||
fn PassAny(&self, _: *mut JSContext, _: JSVal) {}
|
fn PassAny(&self, _: *mut JSContext, _: JSVal) {}
|
||||||
|
|
||||||
fn PassNullableBoolean(&self, _: Option<bool>) {}
|
fn PassNullableBoolean(&self, _: Option<bool>) {}
|
||||||
|
@ -155,7 +155,7 @@ pub trait TestBindingMethods {
|
||||||
// fn PassNullableEnum(&self, _: Option<TestEnum>) {}
|
// fn PassNullableEnum(&self, _: Option<TestEnum>) {}
|
||||||
fn PassNullableInterface(&self, _: Option<JSRef<Blob>>) {}
|
fn PassNullableInterface(&self, _: Option<JSRef<Blob>>) {}
|
||||||
fn PassNullableUnion(&self, _: Option<HTMLElementOrLong>) {}
|
fn PassNullableUnion(&self, _: Option<HTMLElementOrLong>) {}
|
||||||
fn PassNullableUnion2(&self, _: Option<StringOrFormData>) {}
|
fn PassNullableUnion2(&self, _: Option<EventOrString>) {}
|
||||||
fn PassNullableAny(&self, _: *mut JSContext, _: Option<JSVal>) {}
|
fn PassNullableAny(&self, _: *mut JSContext, _: Option<JSVal>) {}
|
||||||
|
|
||||||
fn PassOptionalBoolean(&self, _: Option<bool>) {}
|
fn PassOptionalBoolean(&self, _: Option<bool>) {}
|
||||||
|
@ -174,7 +174,7 @@ pub trait TestBindingMethods {
|
||||||
fn PassOptionalEnum(&self, _: Option<TestEnum>) {}
|
fn PassOptionalEnum(&self, _: Option<TestEnum>) {}
|
||||||
fn PassOptionalInterface(&self, _: Option<JSRef<Blob>>) {}
|
fn PassOptionalInterface(&self, _: Option<JSRef<Blob>>) {}
|
||||||
fn PassOptionalUnion(&self, _: Option<HTMLElementOrLong>) {}
|
fn PassOptionalUnion(&self, _: Option<HTMLElementOrLong>) {}
|
||||||
fn PassOptionalUnion2(&self, _: Option<StringOrFormData>) {}
|
fn PassOptionalUnion2(&self, _: Option<EventOrString>) {}
|
||||||
fn PassOptionalAny(&self, _: *mut JSContext, _: Option<JSVal>) {}
|
fn PassOptionalAny(&self, _: *mut JSContext, _: Option<JSVal>) {}
|
||||||
|
|
||||||
fn PassOptionalNullableBoolean(&self, _: Option<Option<bool>>) {}
|
fn PassOptionalNullableBoolean(&self, _: Option<Option<bool>>) {}
|
||||||
|
@ -193,7 +193,7 @@ pub trait TestBindingMethods {
|
||||||
// fn PassOptionalNullableEnum(&self, _: Option<Option<TestEnum>>) {}
|
// fn PassOptionalNullableEnum(&self, _: Option<Option<TestEnum>>) {}
|
||||||
fn PassOptionalNullableInterface(&self, _: Option<Option<JSRef<Blob>>>) {}
|
fn PassOptionalNullableInterface(&self, _: Option<Option<JSRef<Blob>>>) {}
|
||||||
fn PassOptionalNullableUnion(&self, _: Option<Option<HTMLElementOrLong>>) {}
|
fn PassOptionalNullableUnion(&self, _: Option<Option<HTMLElementOrLong>>) {}
|
||||||
fn PassOptionalNullableUnion2(&self, _: Option<Option<StringOrFormData>>) {}
|
fn PassOptionalNullableUnion2(&self, _: Option<Option<EventOrString>>) {}
|
||||||
|
|
||||||
fn PassOptionalBooleanWithDefault(&self, _: bool) {}
|
fn PassOptionalBooleanWithDefault(&self, _: bool) {}
|
||||||
fn PassOptionalByteWithDefault(&self, _: i8) {}
|
fn PassOptionalByteWithDefault(&self, _: i8) {}
|
||||||
|
@ -223,7 +223,7 @@ pub trait TestBindingMethods {
|
||||||
// fn PassOptionalNullableEnumWithDefault(&self, _: Option<TestEnum>) {}
|
// fn PassOptionalNullableEnumWithDefault(&self, _: Option<TestEnum>) {}
|
||||||
fn PassOptionalNullableInterfaceWithDefault(&self, _: Option<JSRef<Blob>>) {}
|
fn PassOptionalNullableInterfaceWithDefault(&self, _: Option<JSRef<Blob>>) {}
|
||||||
fn PassOptionalNullableUnionWithDefault(&self, _: Option<HTMLElementOrLong>) {}
|
fn PassOptionalNullableUnionWithDefault(&self, _: Option<HTMLElementOrLong>) {}
|
||||||
fn PassOptionalNullableUnion2WithDefault(&self, _: Option<StringOrFormData>) {}
|
fn PassOptionalNullableUnion2WithDefault(&self, _: Option<EventOrString>) {}
|
||||||
fn PassOptionalAnyWithDefault(&self, _: *mut JSContext, _: JSVal) {}
|
fn PassOptionalAnyWithDefault(&self, _: *mut JSContext, _: JSVal) {}
|
||||||
|
|
||||||
fn PassOptionalNullableBooleanWithNonNullDefault(&self, _: Option<bool>) {}
|
fn PassOptionalNullableBooleanWithNonNullDefault(&self, _: Option<bool>) {}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::InheritTypes::ElementCast;
|
use dom::bindings::codegen::InheritTypes::ElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast;
|
||||||
|
use dom::bindings::codegen::InheritTypes::HTMLBodyElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLImageElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLImageElementCast;
|
||||||
|
@ -11,10 +12,11 @@ use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
|
||||||
use dom::bindings::js::JSRef;
|
use dom::bindings::js::JSRef;
|
||||||
use dom::element::Element;
|
use dom::element::Element;
|
||||||
use dom::element::{ElementTypeId, HTMLAnchorElementTypeId, HTMLImageElementTypeId};
|
use dom::element::{ElementTypeId, HTMLAnchorElementTypeId, HTMLBodyElementTypeId, HTMLImageElementTypeId};
|
||||||
use dom::element::{HTMLIFrameElementTypeId, HTMLObjectElementTypeId, HTMLStyleElementTypeId};
|
use dom::element::{HTMLIFrameElementTypeId, HTMLObjectElementTypeId, HTMLStyleElementTypeId};
|
||||||
use dom::event::Event;
|
use dom::event::Event;
|
||||||
use dom::htmlanchorelement::HTMLAnchorElement;
|
use dom::htmlanchorelement::HTMLAnchorElement;
|
||||||
|
use dom::htmlbodyelement::HTMLBodyElement;
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmliframeelement::HTMLIFrameElement;
|
use dom::htmliframeelement::HTMLIFrameElement;
|
||||||
use dom::htmlimageelement::HTMLImageElement;
|
use dom::htmlimageelement::HTMLImageElement;
|
||||||
|
@ -93,6 +95,10 @@ pub fn vtable_for<'a>(node: &'a mut JSRef<Node>) -> &'a mut VirtualMethods: {
|
||||||
let element: &mut JSRef<HTMLAnchorElement> = HTMLAnchorElementCast::to_mut_ref(node).unwrap();
|
let element: &mut JSRef<HTMLAnchorElement> = HTMLAnchorElementCast::to_mut_ref(node).unwrap();
|
||||||
element as &mut VirtualMethods:
|
element as &mut VirtualMethods:
|
||||||
}
|
}
|
||||||
|
ElementNodeTypeId(HTMLBodyElementTypeId) => {
|
||||||
|
let element: &mut JSRef<HTMLBodyElement> = HTMLBodyElementCast::to_mut_ref(node).unwrap();
|
||||||
|
element as &mut VirtualMethods:
|
||||||
|
}
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
let element: &mut JSRef<HTMLImageElement> = HTMLImageElementCast::to_mut_ref(node).unwrap();
|
let element: &mut JSRef<HTMLImageElement> = HTMLImageElementCast::to_mut_ref(node).unwrap();
|
||||||
element as &mut VirtualMethods:
|
element as &mut VirtualMethods:
|
||||||
|
|
|
@ -68,3 +68,4 @@ partial interface Document {
|
||||||
};
|
};
|
||||||
|
|
||||||
Document implements ParentNode;
|
Document implements ParentNode;
|
||||||
|
Document implements GlobalEventHandlers;
|
||||||
|
|
45
src/components/script/dom/webidls/EventHandler.webidl
Normal file
45
src/components/script/dom/webidls/EventHandler.webidl
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/.
|
||||||
|
*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* http://www.whatwg.org/specs/web-apps/current-work/#eventhandler
|
||||||
|
*
|
||||||
|
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
|
||||||
|
* Opera Software ASA. You are granted a license to use, reproduce
|
||||||
|
* and create derivative works of this document.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[TreatNonObjectAsNull]
|
||||||
|
callback EventHandlerNonNull = any (Event event);
|
||||||
|
typedef EventHandlerNonNull? EventHandler;
|
||||||
|
|
||||||
|
[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;
|
||||||
|
|
||||||
|
[NoInterfaceObject]
|
||||||
|
interface GlobalEventHandlers {
|
||||||
|
attribute EventHandler onload;
|
||||||
|
};
|
||||||
|
|
||||||
|
[NoInterfaceObject]
|
||||||
|
interface WindowEventHandlers {
|
||||||
|
attribute EventHandler onunload;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The spec has |attribute OnErrorEventHandler onerror;| on
|
||||||
|
// GlobalEventHandlers, and calls the handler differently depending on
|
||||||
|
// whether an ErrorEvent was fired. We don't do that, and until we do we'll
|
||||||
|
// need to distinguish between onerror on Window or on nodes.
|
||||||
|
|
||||||
|
[NoInterfaceObject]
|
||||||
|
interface OnErrorEventHandlerForNodes {
|
||||||
|
attribute EventHandler onerror;
|
||||||
|
};
|
||||||
|
|
||||||
|
[NoInterfaceObject]
|
||||||
|
interface OnErrorEventHandlerForWindow {
|
||||||
|
attribute OnErrorEventHandler onerror;
|
||||||
|
};
|
|
@ -23,4 +23,4 @@ partial interface HTMLBodyElement {
|
||||||
[SetterThrows] attribute DOMString background;
|
[SetterThrows] attribute DOMString background;
|
||||||
};
|
};
|
||||||
|
|
||||||
//HTMLBodyElement implements WindowEventHandlers;
|
HTMLBodyElement implements WindowEventHandlers;
|
||||||
|
|
|
@ -54,3 +54,5 @@ partial interface HTMLElement {
|
||||||
readonly attribute long offsetWidth;
|
readonly attribute long offsetWidth;
|
||||||
readonly attribute long offsetHeight;
|
readonly attribute long offsetHeight;
|
||||||
};
|
};
|
||||||
|
HTMLElement implements GlobalEventHandlers;
|
||||||
|
//HTMLElement implements OnErrorEventHandlerForNodes;
|
||||||
|
|
|
@ -70,7 +70,7 @@ interface TestBinding {
|
||||||
attribute TestEnum enumAttribute;
|
attribute TestEnum enumAttribute;
|
||||||
attribute Blob interfaceAttribute;
|
attribute Blob interfaceAttribute;
|
||||||
// attribute (HTMLElement or long) unionAttribute;
|
// attribute (HTMLElement or long) unionAttribute;
|
||||||
// attribute (DOMString or FormData) union2Attribute;
|
// attribute (Event or DOMString) union2Attribute;
|
||||||
attribute any anyAttribute;
|
attribute any anyAttribute;
|
||||||
|
|
||||||
attribute boolean? booleanAttributeNullable;
|
attribute boolean? booleanAttributeNullable;
|
||||||
|
@ -89,7 +89,7 @@ interface TestBinding {
|
||||||
readonly attribute TestEnum? enumAttributeNullable;
|
readonly attribute TestEnum? enumAttributeNullable;
|
||||||
attribute Blob? interfaceAttributeNullable;
|
attribute Blob? interfaceAttributeNullable;
|
||||||
// attribute (HTMLElement or long)? unionAttributeNullable;
|
// attribute (HTMLElement or long)? unionAttributeNullable;
|
||||||
// attribute (DOMString or FormData)? union2AttributeNullable;
|
// attribute (Event or DOMString)? union2AttributeNullable;
|
||||||
|
|
||||||
void receiveVoid();
|
void receiveVoid();
|
||||||
boolean receiveBoolean();
|
boolean receiveBoolean();
|
||||||
|
@ -137,7 +137,7 @@ interface TestBinding {
|
||||||
void passEnum(TestEnum arg);
|
void passEnum(TestEnum arg);
|
||||||
void passInterface(Blob arg);
|
void passInterface(Blob arg);
|
||||||
void passUnion((HTMLElement or long) arg);
|
void passUnion((HTMLElement or long) arg);
|
||||||
void passUnion2((DOMString or FormData) data);
|
void passUnion2((Event or DOMString) data);
|
||||||
void passAny(any arg);
|
void passAny(any arg);
|
||||||
|
|
||||||
void passNullableBoolean(boolean? arg);
|
void passNullableBoolean(boolean? arg);
|
||||||
|
@ -156,7 +156,7 @@ interface TestBinding {
|
||||||
// void passNullableEnum(TestEnum? arg);
|
// void passNullableEnum(TestEnum? arg);
|
||||||
void passNullableInterface(Blob? arg);
|
void passNullableInterface(Blob? arg);
|
||||||
void passNullableUnion((HTMLElement or long)? 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 passOptionalBoolean(optional boolean arg);
|
||||||
void passOptionalByte(optional byte arg);
|
void passOptionalByte(optional byte arg);
|
||||||
|
@ -174,7 +174,7 @@ interface TestBinding {
|
||||||
void passOptionalEnum(optional TestEnum arg);
|
void passOptionalEnum(optional TestEnum arg);
|
||||||
void passOptionalInterface(optional Blob arg);
|
void passOptionalInterface(optional Blob arg);
|
||||||
void passOptionalUnion(optional (HTMLElement or long) 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 passOptionalAny(optional any arg);
|
||||||
|
|
||||||
void passOptionalNullableBoolean(optional boolean? arg);
|
void passOptionalNullableBoolean(optional boolean? arg);
|
||||||
|
@ -193,7 +193,7 @@ interface TestBinding {
|
||||||
// void passOptionalNullableEnum(optional TestEnum? arg);
|
// void passOptionalNullableEnum(optional TestEnum? arg);
|
||||||
void passOptionalNullableInterface(optional Blob? arg);
|
void passOptionalNullableInterface(optional Blob? arg);
|
||||||
void passOptionalNullableUnion(optional (HTMLElement or long)? 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 passOptionalBooleanWithDefault(optional boolean arg = false);
|
||||||
void passOptionalByteWithDefault(optional byte arg = 0);
|
void passOptionalByteWithDefault(optional byte arg = 0);
|
||||||
|
@ -207,7 +207,7 @@ interface TestBinding {
|
||||||
void passOptionalStringWithDefault(optional DOMString arg = "");
|
void passOptionalStringWithDefault(optional DOMString arg = "");
|
||||||
void passOptionalEnumWithDefault(optional TestEnum arg = "foo");
|
void passOptionalEnumWithDefault(optional TestEnum arg = "foo");
|
||||||
// void passOptionalUnionWithDefault(optional (HTMLElement or long) arg = 9);
|
// 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 passOptionalNullableBooleanWithDefault(optional boolean? arg = null);
|
||||||
void passOptionalNullableByteWithDefault(optional byte? arg = null);
|
void passOptionalNullableByteWithDefault(optional byte? arg = null);
|
||||||
|
@ -223,7 +223,7 @@ interface TestBinding {
|
||||||
// void passOptionalNullableEnumWithDefault(optional TestEnum? arg = null);
|
// void passOptionalNullableEnumWithDefault(optional TestEnum? arg = null);
|
||||||
void passOptionalNullableInterfaceWithDefault(optional Blob? arg = null);
|
void passOptionalNullableInterfaceWithDefault(optional Blob? arg = null);
|
||||||
void passOptionalNullableUnionWithDefault(optional (HTMLElement or long)? 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 passOptionalAnyWithDefault(optional any arg = null);
|
||||||
|
|
||||||
void passOptionalNullableBooleanWithNonNullDefault(optional boolean? arg = false);
|
void passOptionalNullableBooleanWithNonNullDefault(optional boolean? arg = false);
|
||||||
|
@ -240,5 +240,5 @@ interface TestBinding {
|
||||||
void passOptionalNullableStringWithNonNullDefault(optional DOMString? arg = "");
|
void passOptionalNullableStringWithNonNullDefault(optional DOMString? arg = "");
|
||||||
// void passOptionalNullableEnumWithNonNullDefault(optional TestEnum? arg = "foo");
|
// void passOptionalNullableEnumWithNonNullDefault(optional TestEnum? arg = "foo");
|
||||||
// void passOptionalNullableUnionWithNonNullDefault(optional (HTMLElement or long)? arg = 7);
|
// void passOptionalNullableUnionWithNonNullDefault(optional (HTMLElement or long)? arg = 7);
|
||||||
// void passOptionalNullableUnion2WithNonNullDefault(optional (DOMString or FormData)? data = "foo");
|
// void passOptionalNullableUnion2WithNonNullDefault(optional (Event or DOMString)? data = "foo");
|
||||||
};
|
};
|
||||||
|
|
|
@ -84,6 +84,9 @@ interface WindowTimers {
|
||||||
void clearInterval(optional long handle = 0);*/
|
void clearInterval(optional long handle = 0);*/
|
||||||
};
|
};
|
||||||
Window implements WindowTimers;
|
Window implements WindowTimers;
|
||||||
|
Window implements GlobalEventHandlers;
|
||||||
|
Window implements WindowEventHandlers;
|
||||||
|
Window implements OnErrorEventHandlerForWindow;
|
||||||
|
|
||||||
// Proprietary extensions.
|
// Proprietary extensions.
|
||||||
partial interface Window {
|
partial interface Window {
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::codegen::BindingDeclarations::WindowBinding;
|
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::js::{JS, JSRef, Temporary, OptionalSettable};
|
||||||
use dom::bindings::trace::{Traceable, Untraceable};
|
use dom::bindings::trace::{Traceable, Untraceable};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::browsercontext::BrowserContext;
|
use dom::browsercontext::BrowserContext;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::Element;
|
use dom::element::Element;
|
||||||
use dom::eventtarget::{EventTarget, WindowTypeId};
|
use dom::eventtarget::{EventTarget, WindowTypeId, EventTargetHelpers};
|
||||||
use dom::console::Console;
|
use dom::console::Console;
|
||||||
use dom::location::Location;
|
use dom::location::Location;
|
||||||
use dom::navigator::Navigator;
|
use dom::navigator::Navigator;
|
||||||
|
@ -140,6 +142,12 @@ pub trait WindowMethods {
|
||||||
fn Window(&self) -> Temporary<Window>;
|
fn Window(&self) -> Temporary<Window>;
|
||||||
fn Self(&self) -> Temporary<Window>;
|
fn Self(&self) -> Temporary<Window>;
|
||||||
fn Performance(&mut self) -> Temporary<Performance>;
|
fn Performance(&mut self) -> Temporary<Performance>;
|
||||||
|
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 Debug(&self, message: DOMString);
|
||||||
fn Gc(&self);
|
fn Gc(&self);
|
||||||
}
|
}
|
||||||
|
@ -268,6 +276,36 @@ impl<'a> WindowMethods for JSRef<'a, Window> {
|
||||||
Temporary::new(self.performance.get_ref().clone())
|
Temporary::new(self.performance.get_ref().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn GetOnload(&self) -> Option<EventHandlerNonNull> {
|
||||||
|
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
|
||||||
|
eventtarget.get_event_handler_common("load")
|
||||||
|
}
|
||||||
|
|
||||||
|
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) -> Option<EventHandlerNonNull> {
|
||||||
|
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
|
||||||
|
eventtarget.get_event_handler_common("unload")
|
||||||
|
}
|
||||||
|
|
||||||
|
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) -> Option<OnErrorEventHandlerNonNull> {
|
||||||
|
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
|
||||||
|
eventtarget.get_event_handler_common("error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SetOnerror(&mut self, listener: Option<OnErrorEventHandlerNonNull>) {
|
||||||
|
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
|
||||||
|
eventtarget.set_event_handler_common("error", listener)
|
||||||
|
}
|
||||||
|
|
||||||
fn Debug(&self, message: DOMString) {
|
fn Debug(&self, message: DOMString) {
|
||||||
debug!("{:s}", message);
|
debug!("{:s}", message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ pub mod dom {
|
||||||
pub mod str;
|
pub mod str;
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
pub mod codegen {
|
pub mod codegen {
|
||||||
|
pub mod EventHandlerBinding;
|
||||||
pub mod InterfaceTypes;
|
pub mod InterfaceTypes;
|
||||||
pub mod InheritTypes;
|
pub mod InheritTypes;
|
||||||
pub mod PrototypeList;
|
pub mod PrototypeList;
|
||||||
|
|
18
src/test/content/test_body_listener.html
Normal file
18
src/test/content/test_body_listener.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
<script>
|
||||||
|
function check_onload(listener) {
|
||||||
|
is(listener, window);
|
||||||
|
var ev = new Event('click', {bubbles: true, cancelable: true});
|
||||||
|
document.body.dispatchEvent(ev);
|
||||||
|
}
|
||||||
|
function check_onclick(listener) {
|
||||||
|
is(listener, document.body);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="check_onload(this)" onclick="check_onclick(this)">
|
||||||
|
</body>
|
||||||
|
</html>
|
9
src/test/content/test_inline_event_handler.html
Normal file
9
src/test/content/test_inline_event_handler.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="is_a(event, Event); finish()">
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -4,13 +4,30 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
addEventListener("load", function(ev) {
|
var onloads = 0;
|
||||||
|
function check(ev) {
|
||||||
is_a(ev, Event);
|
is_a(ev, Event);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
is(ev.defaultPrevented, false);
|
is(ev.defaultPrevented, false);
|
||||||
is(ev.target, document);
|
is(ev.target, document);
|
||||||
is(ev.currentTarget, window);
|
is(ev.currentTarget, window);
|
||||||
|
if (onloads == 2) {
|
||||||
finish();
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function(ev) {
|
||||||
|
_fail("this inline handler should be overwritten");
|
||||||
|
}
|
||||||
|
window.onload = function(ev) {
|
||||||
|
onloads++;
|
||||||
|
is(onloads, 1);
|
||||||
|
check(ev);
|
||||||
|
}
|
||||||
|
addEventListener("load", function(ev) {
|
||||||
|
onloads++;
|
||||||
|
is(onloads, 2);
|
||||||
|
check(ev);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue