aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/script/dom/bindings/callback.rs105
-rw-r--r--src/components/script/dom/bindings/codegen/Bindings.conf20
-rw-r--r--src/components/script/dom/bindings/codegen/CodegenRust.py491
-rw-r--r--src/components/script/dom/bindings/codegen/Document.webidl4
-rw-r--r--src/components/script/dom/bindings/codegen/EventListener.webidl16
-rw-r--r--src/components/script/dom/bindings/codegen/EventTarget.webidl8
-rw-r--r--src/components/script/dom/bindings/codegen/Node.webidl2
-rw-r--r--src/components/script/dom/bindings/codegen/Window.webidl2
-rw-r--r--src/components/script/dom/bindings/node.rs2
-rw-r--r--src/components/script/dom/bindings/utils.rs36
-rw-r--r--src/components/script/dom/document.rs6
-rw-r--r--src/components/script/dom/event.rs10
-rw-r--r--src/components/script/dom/eventtarget.rs80
-rw-r--r--src/components/script/dom/node.rs9
-rw-r--r--src/components/script/dom/window.rs9
-rw-r--r--src/components/script/script.rc1
m---------src/support/spidermonkey/rust-mozjs0
-rw-r--r--src/test/html/content/test_event_listener.html17
18 files changed, 489 insertions, 329 deletions
diff --git a/src/components/script/dom/bindings/callback.rs b/src/components/script/dom/bindings/callback.rs
new file mode 100644
index 00000000000..6cf88b353ed
--- /dev/null
+++ b/src/components/script/dom/bindings/callback.rs
@@ -0,0 +1,105 @@
+/* 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/. */
+
+use dom::bindings::utils::{WrapNativeParent, Reflectable};
+use js::jsapi::{JSContext, JSObject, JS_WrapObject, JSVal, JS_ObjectIsCallable};
+use js::jsapi::JS_GetProperty;
+use js::{JSVAL_IS_OBJECT, JSVAL_TO_OBJECT};
+
+use std::libc;
+use std::ptr;
+
+pub enum ExceptionHandling {
+ // Report any exception and don't throw it to the caller code.
+ eReportExceptions,
+ // Throw an exception to the caller code if the thrown exception is a
+ // binding object for a DOMError from the caller's scope, otherwise report
+ // it.
+ eRethrowContentExceptions,
+ // Throw any exception to the caller code.
+ eRethrowExceptions
+}
+
+#[deriving(Clone,Eq)]
+pub struct CallbackInterface {
+ callback: *JSObject
+}
+
+pub trait CallbackContainer {
+ fn callback(&self) -> *JSObject;
+}
+
+impl CallbackContainer for CallbackInterface {
+ fn callback(&self) -> *JSObject {
+ self.callback
+ }
+}
+
+impl CallbackInterface {
+ pub fn new(callback: *JSObject) -> CallbackInterface {
+ CallbackInterface {
+ callback: callback
+ }
+ }
+
+ #[fixed_stack_segment]
+ pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool {
+ unsafe {
+ if JS_GetProperty(cx, self.callback, name, &*callable) == 0 {
+ return false;
+ }
+
+ if !JSVAL_IS_OBJECT(*callable) ||
+ JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(*callable)) == 0 {
+ //ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
+
+pub fn GetJSObjectFromCallback<T: CallbackContainer>(callback: &T) -> *JSObject {
+ callback.callback()
+}
+
+#[fixed_stack_segment]
+pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *JSContext,
+ scope: *JSObject,
+ p: @mut T) -> *JSObject {
+ let mut obj = GetJSObjectFromCallback(p);
+ if obj.is_null() {
+ obj = WrapNativeParent(cx, scope, Some(p as @mut Reflectable));
+ if obj.is_null() {
+ return ptr::null();
+ }
+ }
+
+ unsafe {
+ if JS_WrapObject(cx, &obj) == 0 {
+ return ptr::null();
+ }
+ }
+
+ return obj;
+}
+
+pub struct CallSetup {
+ cx: *JSContext,
+ handling: ExceptionHandling
+}
+
+impl CallSetup {
+ pub fn new(cx: *JSContext, handling: ExceptionHandling) -> CallSetup {
+ CallSetup {
+ cx: cx,
+ handling: handling
+ }
+ }
+
+ pub fn GetContext(&self) -> *JSContext {
+ self.cx
+ }
+}
diff --git a/src/components/script/dom/bindings/codegen/Bindings.conf b/src/components/script/dom/bindings/codegen/Bindings.conf
index 770bea35c33..d1760f27901 100644
--- a/src/components/script/dom/bindings/codegen/Bindings.conf
+++ b/src/components/script/dom/bindings/codegen/Bindings.conf
@@ -184,26 +184,12 @@ DOMInterfaces = {
'Event': {
},
-'EventListener': [
-{
+'EventListener': {
+ 'nativeType': 'EventListenerBinding::EventListener',
},
-{
- 'workers': True,
-}],
-'EventTarget': [
-{
-# 'nativeType': 'nsDOMEventTargetHelper',
-# 'hasInstanceInterface': 'nsIDOMEventTarget',
-# 'concrete': False,
-# 'prefable': True,
+'EventTarget': {
},
-#{
-# 'workers': True,
-# 'headerFile': 'mozilla/dom/workers/bindings/EventTarget.h',
-# 'concrete': False
-#}
-],
'FileList': [
{
diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py
index 0d012d2b1c8..8252135b0a5 100644
--- a/src/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/src/components/script/dom/bindings/codegen/CodegenRust.py
@@ -525,7 +525,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
# failureCode will prevent pending exceptions from being set in cases when
# they really should be!
if exceptionCode is None:
- exceptionCode = "return false;"
+ exceptionCode = "return 0;"
# We often want exceptionCode to be indented, since it often appears in an
# if body.
exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
@@ -915,19 +915,14 @@ for (uint32_t i = 0; i < length; ++i) {
type.unroll().inner.identifier.name)
if descriptor.interface.isCallback():
- name = descriptor.interface.identifier.name
- if type.nullable() or isCallbackReturnValue:
- declType = CGGeneric("nsRefPtr<%s>" % name);
- else:
- declType = CGGeneric("OwningNonNull<%s>" % name)
- conversion = (
- " ${declName} = new %s(&${val}.toObject());\n" % name)
+ name = descriptor.nativeType
+ declType = CGGeneric("Option<%s>" % name);
+ conversion = (" ${declName} = Some(%s::new(JSVAL_TO_OBJECT(${val})));\n" % name)
template = wrapObjectTemplate(conversion, type,
- "${declName} = nullptr",
+ "${declName} = None",
failureCode)
- return JSToNativeConversionInfo(template, declType=declType,
- dealWithOptional=isOptional)
+ return (template, declType, None, isOptional, None)
# This is an interface that we implement as a concrete class
# or an XPCOM interface.
@@ -980,13 +975,6 @@ for (uint32_t i = 0; i < length; ++i) {
"JSVAL_TO_OBJECT(${val})",
"${declName}",
isOptional or argIsPointer or type.nullable()))
- elif descriptor.interface.isCallback() and False:
- #XXXjdm unfinished
- templateBody += str(CallbackObjectUnwrapper(
- descriptor,
- "&${val}.toObject()",
- "${declName}",
- codeOnFailure=failureCode))
elif descriptor.workers:
templateBody += "${declName} = &${val}.toObject();"
else:
@@ -1265,7 +1253,7 @@ for (uint32_t i = 0; i < length; ++i) {
assert not isOptional
# This one only happens for return values, and its easy: Just
# ignore the jsval.
- return JSToNativeConversionInfo("")
+ return ("", None, None, False, None)
if not type.isPrimitive():
raise TypeError("Need conversion for argument type '%s'" % str(type))
@@ -1280,16 +1268,20 @@ for (uint32_t i = 0; i < length; ++i) {
if type.nullable():
dataLoc = "${declName}.SetValue()"
- nullCondition = "${val}.isNullOrUndefined()"
+ nullCondition = "(RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0)"
if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
nullCondition = "!(${haveValue}) || " + nullCondition
+ #XXXjdm support conversionBehavior here
template = (
"if (%s) {\n"
- " ${declName}.SetNull();\n"
- "} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
- " return false;\n"
- "}" % (nullCondition, typeName, conversionBehavior, dataLoc))
- declType = CGGeneric("Nullable<" + typeName + ">")
+ " ${declName} = None;\n"
+ "} else {\n"
+ " match JSValConvertible::from_jsval(${val}) {\n"
+ " Some(val_) => ${declName} = Some(val_),\n"
+ " None => return 0\n"
+ " }\n"
+ "}" % nullCondition)
+ declType = CGGeneric("Option<" + typeName + ">")
else:
assert(defaultValue is None or
not isinstance(defaultValue, IDLNullValue))
@@ -1317,10 +1309,10 @@ for (uint32_t i = 0; i < length; ++i) {
" %s = %s;\n"
"}" % (dataLoc, defaultStr))).define()
- if typeName != "bool":
- return (template, declType, None, isOptional, "0 as %s" % typeName)
- else:
- return (template, declType, None, isOptional, "false")
+ initialVal = "false" if typeName == "bool" else ("0 as %s" % typeName)
+ if type.nullable():
+ initialVal = "Some(%s)" % initialVal
+ return (template, declType, None, isOptional, initialVal)
def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
argcAndIndex=None):
@@ -1593,8 +1585,8 @@ for (uint32_t i = 0; i < length; ++i) {
# Non-prefable bindings can only fail to wrap as a new-binding object
# if they already threw an exception. Same thing for
# non-prefable bindings.
- failed = ("//MOZ_ASSERT(JS_IsExceptionPending(cx));\n" +
- "return 0;")
+ failed = ("assert!(unsafe { JS_IsExceptionPending(cx) != 0 });\n" +
+ "%s" % exceptionCode)
else:
if descriptor.notflattened:
raise TypeError("%s is prefable but not flattened; "
@@ -2423,9 +2415,10 @@ class Argument():
self.name = name
self.default = default
def declare(self):
- string = self.argType + ' ' + self.name
- if self.default is not None:
- string += " = " + self.default
+ string = self.name + ((': ' + self.argType) if self.argType else '')
+ #XXXjdm Support default arguments somehow :/
+ #if self.default is not None:
+ # string += " = " + self.default
return string
def define(self):
return self.argType + ' ' + self.name
@@ -2470,7 +2463,7 @@ class CGAbstractMethod(CGThing):
self.pub = pub;
self.unsafe = unsafe
def _argstring(self, declare):
- return ', '.join([a.declare() if declare else a.define() for a in self.args])
+ return ', '.join([a.declare() for a in self.args])
def _template(self):
if self.templateArgs is None:
return ''
@@ -3575,7 +3568,7 @@ class ClassItem:
assert False
class ClassBase(ClassItem):
- def __init__(self, name, visibility='public'):
+ def __init__(self, name, visibility='pub'):
ClassItem.__init__(self, name, visibility)
def declare(self, cgClass):
return '%s %s' % (self.visibility, self.name)
@@ -3595,11 +3588,11 @@ class ClassMethod(ClassItem):
assert not override or virtual
self.returnType = returnType
self.args = args
- self.inline = inline or bodyInHeader
+ self.inline = False
self.static = static
self.virtual = virtual
self.const = const
- self.bodyInHeader = bodyInHeader
+ self.bodyInHeader = True
self.templateArgs = templateArgs
self.body = body
self.breakAfterReturnDecl = breakAfterReturnDecl
@@ -3608,7 +3601,7 @@ class ClassMethod(ClassItem):
ClassItem.__init__(self, name, visibility)
def getDecorators(self, declaring):
- decorators = []
+ decorators = ['#[fixed_stack_segment]']
if self.inline:
decorators.append('inline')
if declaring:
@@ -3626,62 +3619,32 @@ class ClassMethod(ClassItem):
return self.body
def declare(self, cgClass):
- templateClause = 'template <%s>\n' % ', '.join(self.templateArgs) \
+ templateClause = '<%s>' % ', '.join(self.templateArgs) \
if self.bodyInHeader and self.templateArgs else ''
args = ', '.join([a.declare() for a in self.args])
if self.bodyInHeader:
body = CGIndenter(CGGeneric(self.getBody())).define()
- body = '\n{\n' + body + '\n}'
+ body = ' {\n' + body + '\n}'
else:
body = ';'
- return string.Template("${templateClause}${decorators}${returnType}%s"
- "${name}(${args})${const}${override}${body}%s" %
+ return string.Template("${decorators}%s"
+ "${visibility}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" %
(self.breakAfterReturnDecl, self.breakAfterSelf)
).substitute({
'templateClause': templateClause,
'decorators': self.getDecorators(True),
- 'returnType': self.returnType,
+ 'returnType': (" -> %s" % self.returnType) if self.returnType else "",
'name': self.name,
'const': ' const' if self.const else '',
'override': ' MOZ_OVERRIDE' if self.override else '',
'args': args,
- 'body': body
+ 'body': body,
+ 'visibility': self.visibility + ' ' if self.visibility is not 'priv' else ''
})
def define(self, cgClass):
- if self.bodyInHeader:
- return ''
-
- templateArgs = cgClass.templateArgs
- if templateArgs:
- if cgClass.templateSpecialization:
- templateArgs = \
- templateArgs[len(cgClass.templateSpecialization):]
-
- if templateArgs:
- templateClause = \
- 'template <%s>\n' % ', '.join([str(a) for a in templateArgs])
- else:
- templateClause = ''
-
- args = ', '.join([a.define() for a in self.args])
-
- body = CGIndenter(CGGeneric(self.getBody())).define()
-
- return string.Template("""${templateClause}${decorators}${returnType}
-${className}::${name}(${args})${const}
-{
-${body}
-}
-""").substitute({ 'templateClause': templateClause,
- 'decorators': self.getDecorators(False),
- 'returnType': self.returnType,
- 'className': cgClass.getNameString(),
- 'name': self.name,
- 'args': args,
- 'const': ' const' if self.const else '',
- 'body': body })
+ pass
class ClassUsingDeclaration(ClassItem):
""""
@@ -3729,10 +3692,10 @@ class ClassConstructor(ClassItem):
body contains a string with the code for the constructor, defaults to empty.
"""
def __init__(self, args, inline=False, bodyInHeader=False,
- visibility="private", explicit=False, baseConstructors=None,
+ visibility="priv", explicit=False, baseConstructors=None,
body=""):
self.args = args
- self.inline = inline or bodyInHeader
+ self.inline = False
self.bodyInHeader = bodyInHeader
self.explicit = explicit
self.baseConstructors = baseConstructors or []
@@ -3761,21 +3724,22 @@ class ClassConstructor(ClassItem):
return '\n : ' + ',\n '.join(items)
return ''
- def getBody(self):
- return self.body
+ def getBody(self, cgClass):
+ initializers = [" parent: %s" % str(self.baseConstructors[0])]
+ return (self.body + (
+ "%s {\n"
+ "%s\n"
+ "}") % (cgClass.name, '\n'.join(initializers)))
def declare(self, cgClass):
args = ', '.join([a.declare() for a in self.args])
- if self.bodyInHeader:
- body = ' ' + self.getBody();
- body = stripTrailingWhitespace(body.replace('\n', '\n '))
- if len(body) > 0:
- body += '\n'
- body = self.getInitializationList(cgClass) + '\n{\n' + body + '}'
- else:
- body = ';'
+ body = ' ' + self.getBody(cgClass);
+ body = stripTrailingWhitespace(body.replace('\n', '\n '))
+ if len(body) > 0:
+ body += '\n'
+ body = ' {\n' + body + '}'
- return string.Template("""${decorators}${className}(${args})${body}
+ return string.Template("""pub fn ${decorators}new(${args}) -> ${className}${body}
""").substitute({ 'decorators': self.getDecorators(True),
'className': cgClass.getNameString(),
'args': args,
@@ -3870,7 +3834,7 @@ ${className}::~${className}()
'body': body })
class ClassMember(ClassItem):
- def __init__(self, name, type, visibility="private", static=False,
+ def __init__(self, name, type, visibility="priv", static=False,
body=None):
self.type = type;
self.static = static
@@ -3878,8 +3842,7 @@ class ClassMember(ClassItem):
ClassItem.__init__(self, name, visibility)
def declare(self, cgClass):
- return '%s%s %s;\n' % ('static ' if self.static else '', self.type,
- self.name)
+ return '%s: %s,\n' % (self.name, self.type)
def define(self, cgClass):
if not self.static:
@@ -3962,7 +3925,7 @@ class CGClass(CGThing):
self.isStruct = isStruct
self.disallowCopyConstruction = disallowCopyConstruction
self.indent = indent
- self.defaultVisibility ='public' if isStruct else 'private'
+ self.defaultVisibility ='pub' if isStruct else 'priv'
self.decorators = decorators
self.extradeclarations = extradeclarations
self.extradefinitions = extradefinitions
@@ -3983,68 +3946,36 @@ class CGClass(CGThing):
result = result + self.indent + 'template <%s>\n' \
% ','.join([str(a) for a in templateArgs])
- type = 'struct' if self.isStruct else 'class'
-
if self.templateSpecialization:
specialization = \
'<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
else:
specialization = ''
- myself = '%s%s %s%s' % (self.indent, type, self.name, specialization)
+ myself = ''
if self.decorators != '':
- myself += " " + self.decorators
+ myself += self.decorators + '\n'
+ myself += '%spub struct %s%s' % (self.indent, self.name, specialization)
result += myself
+ assert len(self.bases) == 1 #XXjdm Can we support multiple inheritance?
+
+ result += '{\n%s\n' % self.indent
+
if self.bases:
- inherit = ' : '
- result += inherit
- # Grab our first base
- baseItems = [CGGeneric(b.declare(self)) for b in self.bases]
- bases = baseItems[:1]
- # Indent the rest
- bases.extend(CGIndenter(b, len(myself) + len(inherit)) for
- b in baseItems[1:])
- result += ",\n".join(b.define() for b in bases)
-
- result = result + '\n%s{\n' % self.indent
+ self.members = [ClassMember("parent", self.bases[0].name, "pub")] + self.members
result += CGIndenter(CGGeneric(self.extradeclarations),
len(self.indent)).define()
- def declareMembers(cgClass, memberList, defaultVisibility, itemCount,
- separator=''):
- members = { 'private': [], 'protected': [], 'public': [] }
-
- for member in memberList:
- members[member.visibility].append(member)
-
-
- if defaultVisibility == 'public':
- order = [ 'public', 'protected', 'private' ]
- else:
- order = [ 'private', 'protected', 'public' ]
-
+ def declareMembers(cgClass, memberList):
result = ''
- lastVisibility = defaultVisibility
- for visibility in order:
- list = members[visibility]
- if list:
- if visibility != lastVisibility:
- if itemCount:
- result = result + '\n'
- result = result + visibility + ':\n'
- itemCount = 0
- for member in list:
- if itemCount != 0:
- result = result + separator
- declaration = member.declare(cgClass)
- declaration = CGIndenter(CGGeneric(declaration)).define()
- result = result + declaration
- itemCount = itemCount + 1
- lastVisibility = visibility
- return (result, lastVisibility, itemCount)
+ for member in memberList:
+ declaration = member.declare(cgClass)
+ declaration = CGIndenter(CGGeneric(declaration)).define()
+ result = result + declaration
+ return result
if self.disallowCopyConstruction:
class DisallowedCopyConstructor(object):
@@ -4059,48 +3990,33 @@ class CGClass(CGThing):
disallowedCopyConstructors = []
order = [(self.enums, ''), (self.unions, ''),
- (self.typedefs, ''), (self.members, ''),
- (self.constructors + disallowedCopyConstructors, '\n'),
- (self.destructors, '\n'), (self.methods, '\n')]
+ (self.typedefs, ''), (self.members, '')]
- lastVisibility = self.defaultVisibility
- itemCount = 0
for (memberList, separator) in order:
- (memberString, lastVisibility, itemCount) = \
- declareMembers(self, memberList, lastVisibility, itemCount,
- separator)
+ memberString = declareMembers(self, memberList)
if self.indent:
memberString = CGIndenter(CGGeneric(memberString),
len(self.indent)).define()
result = result + memberString
- result = result + self.indent + '};\n'
- return result
+ result += self.indent + '}\n\n'
+ result += 'impl %s {\n' % self.name
- def define(self):
- def defineMembers(cgClass, memberList, itemCount, separator=''):
- result = ''
- for member in memberList:
- if itemCount != 0:
- result = result + separator
- definition = member.define(cgClass)
- if definition:
- # Member variables would only produce empty lines here.
- result += definition
- itemCount += 1
- return (result, itemCount)
-
- order = [(self.members, ''), (self.constructors, '\n'),
- (self.destructors, '\n'), (self.methods, '\n')]
-
- result = self.extradefinitions
- itemCount = 0
+ order = [(self.constructors + disallowedCopyConstructors, '\n'),
+ (self.destructors, '\n'), (self.methods, '\n)')]
for (memberList, separator) in order:
- (memberString, itemCount) = defineMembers(self, memberList,
- itemCount, separator)
+ memberString = declareMembers(self, memberList)
+ if self.indent:
+ memberString = CGIndenter(CGGeneric(memberString),
+ len(self.indent)).define()
result = result + memberString
+
+ result += "}"
return result
+ def define(self):
+ return ''
+
class CGXrayHelper(CGAbstractExternMethod):
def __init__(self, descriptor, name, args, properties):
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@@ -5301,10 +5217,10 @@ class CGBindingRoot(CGThing):
'js::glue::*',
'dom::types::*',
'dom::bindings::utils::*',
+ 'dom::bindings::callback::*',
'dom::bindings::conversions::*',
'dom::bindings::codegen::*', #XXXjdm
'script_task::{JSPageInfo, page_from_context}',
- 'dom::bindings::utils::EnumEntry',
'dom::bindings::proxyhandler',
'dom::bindings::proxyhandler::*',
'dom::document::AbstractDocument',
@@ -5383,29 +5299,31 @@ class CGNativeMember(ClassMethod):
never examine this value.
"""
if type.isVoid():
- return "void", "", ""
- if type.isPrimitive() and type.tag() in builtinNames:
+ typeDecl, errorDefault, template = "", "", ""
+ elif type.isPrimitive() and type.tag() in builtinNames:
result = CGGeneric(builtinNames[type.tag()])
defaultReturnArg = "0"
if type.nullable():
result = CGTemplatedType("Nullable", result)
defaultReturnArg = ""
- return (result.define(),
- "%s(%s)" % (result.define(), defaultReturnArg),
- "return ${declName};")
- if type.isDOMString():
+ typeDecl, errorDefault, template = \
+ (result.define(),
+ "%s(%s)" % (result.define(), defaultReturnArg),
+ "return ${declName};")
+ elif type.isDOMString():
if isMember:
# No need for a third element in the isMember case
- return "nsString", None, None
+ typeDecl, errorDefault, template = "nsString", None, None
# Outparam
- return "void", "", "retval = ${declName};"
- if type.isByteString():
+ else:
+ typeDecl, errorDefault, template = "void", "", "retval = ${declName};"
+ elif type.isByteString():
if isMember:
# No need for a third element in the isMember case
- return "nsCString", None, None
+ typeDecl, errorDefault, template = "nsCString", None, None
# Outparam
- return "void", "", "retval = ${declName};"
- if type.isEnum():
+ typeDecl, errorDefault, template = "void", "", "retval = ${declName};"
+ elif type.isEnum():
enumName = type.unroll().inner.identifier.name
if type.nullable():
enumName = CGTemplatedType("Nullable",
@@ -5413,8 +5331,8 @@ class CGNativeMember(ClassMethod):
defaultValue = "%s()" % enumName
else:
defaultValue = "%s(0)" % enumName
- return enumName, defaultValue, "return ${declName};"
- if type.isGeckoInterface():
+ typeDecl, errorDefault, template = enumName, defaultValue, "return ${declName};"
+ elif type.isGeckoInterface():
iface = type.unroll().inner;
nativeType = self.descriptorProvider.getDescriptor(
iface.identifier.name).nativeType
@@ -5442,21 +5360,25 @@ class CGNativeMember(ClassMethod):
# Since we always force an owning type for callback return values,
# our ${declName} is an OwningNonNull or nsRefPtr. So we can just
# .forget() to get our already_AddRefed.
- return result.define(), "nullptr", "return ${declName}.forget();"
- if type.isCallback():
- return ("already_AddRefed<%s>" % type.unroll().identifier.name,
- "nullptr", "return ${declName}.forget();")
- if type.isAny():
- return "JS::Value", "JS::UndefinedValue()", "return ${declName};"
- if type.isObject():
- return "JSObject*", "nullptr", "return ${declName};"
- if type.isSpiderMonkeyInterface():
+ typeDecl, errorDefault, template = \
+ result.define(), "nullptr", "return ${declName}.forget();"
+ elif type.isCallback():
+ typeDecl, errorDefault, template = \
+ ("already_AddRefed<%s>" % type.unroll().identifier.name,
+ "nullptr", "return ${declName}.forget();")
+ elif type.isAny():
+ typeDecl, errorDefault, template = \
+ "JS::Value", "JS::UndefinedValue()", "return ${declName};"
+ elif type.isObject():
+ typeDecl, errorDefault, template = \
+ "JSObject*", "nullptr", "return ${declName};"
+ elif type.isSpiderMonkeyInterface():
if type.nullable():
returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
else:
returnCode = "return ${declName}.Obj();"
- return "JSObject*", "nullptr", returnCode
- if type.isSequence():
+ typeDecl, errorDefault, template = "JSObject*", "nullptr", returnCode
+ elif type.isSequence():
# If we want to handle sequence-of-sequences return values, we're
# going to need to fix example codegen to not produce nsTArray<void>
# for the relevant argument...
@@ -5470,15 +5392,26 @@ class CGNativeMember(ClassMethod):
"}")
else:
returnCode = "retval.SwapElements(${declName});"
- return "void", "", returnCode
- if type.isDate():
+ typeDecl, errorDefault, template = "void", "", returnCode
+ elif type.isDate():
result = CGGeneric("Date")
if type.nullable():
result = CGTemplatedType("Nullable", result)
- return (result.define(), "%s()" % result.define(),
- "return ${declName};")
- raise TypeError("Don't know how to declare return value for %s" %
- type)
+ typeDecl, errorDefault, template = \
+ (result.define(), "%s()" % result.define(), "return ${declName};")
+ else:
+ raise TypeError("Don't know how to declare return value for %s" % type)
+
+ if not 'infallible' in self.extendedAttrs:
+ if typeDecl:
+ typeDecl = "Fallible<%s>" % typeDecl
+ else:
+ typeDecl = "ErrorResult"
+ if not errorDefault:
+ errorDefault = "Err(FailureUnknown)"
+ if not template:
+ template = "return Ok(());"
+ return typeDecl, errorDefault, template
def getArgs(self, returnType, argList):
args = [self.getArg(arg) for arg in argList]
@@ -5497,10 +5430,6 @@ class CGNativeMember(ClassMethod):
if nullable:
type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "retval"))
- # And the ErrorResult
- if not 'infallible' in self.extendedAttrs:
- # Use aRv so it won't conflict with local vars named "rv"
- args.append(Argument("ErrorResult&", "aRv"))
# The legacycaller thisval
if self.member.isMethod() and self.member.isLegacycaller():
# If it has an identifier, we can't deal with it yet
@@ -5552,7 +5481,7 @@ class CGNativeMember(ClassMethod):
if (optional or isMember) and forceOwningType:
typeDecl = "nsRefPtr<%s>"
else:
- typeDecl = "%s*"
+ typeDecl = "*%s"
else:
if optional or isMember:
if forceOwningType:
@@ -5560,9 +5489,9 @@ class CGNativeMember(ClassMethod):
else:
typeDecl = "NonNull<%s>"
else:
- typeDecl = "%s&"
- return ((typeDecl %
- self.descriptorProvider.getDescriptor(iface.identifier.name).nativeType),
+ typeDecl = "%s%s"
+ descriptor = self.descriptorProvider.getDescriptor(iface.identifier.name)
+ return (typeDecl % (descriptor.pointerType, descriptor.nativeType),
False, False)
if type.isSpiderMonkeyInterface():
@@ -5692,16 +5621,17 @@ class CGCallback(CGClass):
CGClass.__init__(self, name,
bases=[ClassBase(baseName)],
constructors=self.getConstructors(),
- methods=realMethods+getters+setters)
+ methods=realMethods+getters+setters,
+ decorators="#[deriving(Eq,Clone)]")
def getConstructors(self):
return [ClassConstructor(
- [Argument("JSObject*", "aCallback")],
+ [Argument("*JSObject", "aCallback")],
bodyInHeader=True,
- visibility="public",
- explicit=True,
+ visibility="pub",
+ explicit=False,
baseConstructors=[
- "%s(aCallback)" % self.baseName
+ "%s::new(aCallback)" % self.baseName
])]
def getMethodImpls(self, method):
@@ -5709,14 +5639,14 @@ class CGCallback(CGClass):
args = list(method.args)
# Strip out the JSContext*/JSObject* args
# that got added.
- assert args[0].name == "cx" and args[0].argType == "JSContext*"
- assert args[1].name == "aThisObj" and args[1].argType == "JS::Handle<JSObject*>"
+ assert args[0].name == "cx" and args[0].argType == "*JSContext"
+ assert args[1].name == "aThisObj" and args[1].argType == "*JSObject"
args = args[2:]
# Record the names of all the arguments, so we can use them when we call
# the private method.
argnames = [arg.name for arg in args]
argnamesWithThis = ["s.GetContext()", "thisObjJS"] + argnames
- argnamesWithoutThis = ["s.GetContext()", "JS::NullPtr()"] + argnames
+ argnamesWithoutThis = ["s.GetContext()", "JSVAL_TO_OBJECT(JSVAL_NULL)"] + argnames
# Now that we've recorded the argnames for our call to our private
# method, insert our optional argument for deciding whether the
# CallSetup should re-throw exceptions on aRv.
@@ -5724,63 +5654,52 @@ class CGCallback(CGClass):
"eReportExceptions"))
# And now insert our template argument.
argsWithoutThis = list(args)
- args.insert(0, Argument("const T&", "thisObj"))
+ args.insert(0, Argument("@mut T", "thisObj"))
+
+ # And the self argument
+ method.args.insert(0, Argument(None, "&self"))
+ args.insert(0, Argument(None, "&self"))
+ argsWithoutThis.insert(0, Argument(None, "&self"))
- setupCall = ("CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
- "if (!s.GetContext()) {\n"
- " aRv.Throw(NS_ERROR_UNEXPECTED);\n"
+ setupCall = ("let s = CallSetup::new(cx_for_dom_object(${cxProvider}), aExceptionHandling);\n"
+ "if s.GetContext().is_null() {\n"
" return${errorReturn};\n"
"}\n")
bodyWithThis = string.Template(
setupCall+
- "JS::Rooted<JSObject*> thisObjJS(s.GetContext(),\n"
- " WrapCallThisObject(s.GetContext(), CallbackPreserveColor(), thisObj));\n"
- "if (!thisObjJS) {\n"
- " aRv.Throw(NS_ERROR_FAILURE);\n"
+ "let thisObjJS = WrapCallThisObject(s.GetContext(), ptr::null() /*XXXjdm proper scope*/, thisObj);\n"
+ "if thisObjJS.is_null() {\n"
" return${errorReturn};\n"
"}\n"
"return ${methodName}(${callArgs});").substitute({
"errorReturn" : method.getDefaultRetval(),
"callArgs" : ", ".join(argnamesWithThis),
- "methodName": method.name,
+ "methodName": 'self.' + method.name,
+ "cxProvider": 'thisObj'
})
bodyWithoutThis = string.Template(
setupCall +
"return ${methodName}(${callArgs});").substitute({
"errorReturn" : method.getDefaultRetval(),
"callArgs" : ", ".join(argnamesWithoutThis),
- "methodName": 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,
- templateArgs=["typename T"],
- body=bodyWithThis),
- ClassMethod(method.name, method.returnType, argsWithoutThis,
+ templateArgs=["T: 'static+CallbackContainer+Reflectable"],
+ body=bodyWithThis,
+ visibility='pub'),
+ ClassMethod(method.name+'__', method.returnType, argsWithoutThis,
bodyInHeader=True,
- body=bodyWithoutThis),
+ body=bodyWithoutThis,
+ visibility='pub'),
method]
def deps(self):
return self._deps
-class CGCallbackFunction(CGCallback):
- def __init__(self, callback, descriptorProvider):
- CGCallback.__init__(self, callback, descriptorProvider,
- "CallbackFunction",
- methods=[CallCallback(callback, descriptorProvider)])
-
- def getConstructors(self):
- return CGCallback.getConstructors(self) + [
- ClassConstructor(
- [Argument("CallbackFunction*", "aOther")],
- bodyInHeader=True,
- visibility="public",
- explicit=True,
- baseConstructors=[
- "CallbackFunction(aOther)"
- ])]
-
# We're always fallible
def callbackGetterName(attr):
return "Get" + MakeNativeName(attr.identifier.name)
@@ -5799,7 +5718,7 @@ class CGCallbackFunction(CGCallback):
ClassConstructor(
[Argument("CallbackFunction*", "aOther")],
bodyInHeader=True,
- visibility="public",
+ visibility="pub",
explicit=True,
baseConstructors=[
"CallbackFunction(aOther)"
@@ -5865,7 +5784,7 @@ class CallbackMember(CGNativeMember):
self.needThisHandling = needThisHandling
# If needThisHandling, we generate ourselves as private and the caller
# will handle generating public versions that handle the "this" stuff.
- visibility = "private" if needThisHandling else "public"
+ visibility = "priv" if needThisHandling else "pub"
self.rethrowContentException = rethrowContentException
# We don't care, for callback codegen, whether our original member was
# a method or attribute or whatnot. Just always pass FakeMember()
@@ -5878,8 +5797,7 @@ class CallbackMember(CGNativeMember):
jsObjectsArePtr=True)
# We have to do all the generation of our body now, because
# the caller relies on us throwing if we can't manage it.
- self.exceptionCode=("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
- "return%s;" % self.getDefaultRetval())
+ self.exceptionCode= "return Err(FailureUnknown);\n"
self.body = self.getImpl()
def getImpl(self):
@@ -5894,11 +5812,7 @@ class CallbackMember(CGNativeMember):
if self.argCount > 0:
replacements["argCount"] = self.argCountStr
replacements["argvDecl"] = string.Template(
- "JS::AutoValueVector argv(cx);\n"
- "if (!argv.resize(${argCount})) {\n"
- " aRv.Throw(NS_ERROR_OUT_OF_MEMORY);\n"
- " return${errorReturn};\n"
- "}\n"
+ "let mut argv = vec::from_elem(${argCount}, JSVAL_VOID);\n"
).substitute(replacements)
else:
# Avoid weird 0-sized arrays
@@ -5929,13 +5843,13 @@ class CallbackMember(CGNativeMember):
isCallbackReturnValue = "JSImpl"
else:
isCallbackReturnValue = "Callback"
- convertType = instantiateJSToNativeConversion(
- getJSToNativeConversionInfo(self.retvalType,
- self.descriptorProvider,
- exceptionCode=self.exceptionCode,
- isCallbackReturnValue=isCallbackReturnValue,
- # XXXbz we should try to do better here
- sourceDescription="return value"),
+ convertType = instantiateJSToNativeConversionTemplate(
+ getJSToNativeConversionTemplate(self.retvalType,
+ self.descriptorProvider,
+ exceptionCode=self.exceptionCode,
+ isCallbackReturnValue=isCallbackReturnValue,
+ # XXXbz we should try to do better here
+ sourceDescription="return value"),
replacements)
assignRetval = string.Template(
self.getRetvalInfo(self.retvalType,
@@ -5954,8 +5868,8 @@ class CallbackMember(CGNativeMember):
# Wrap each one in a scope so that any locals it has don't leak out, and
# also so that we can just "break;" for our successCode.
argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
- pre="do {\n",
- post="\n} while (0);")
+ pre="loop {\n",
+ post="\nbreak;}\n")
for c in argConversions]
if self.argCount > 0:
argConversions.insert(0, self.getArgcDecl())
@@ -5989,10 +5903,11 @@ class CallbackMember(CGNativeMember):
'successCode' : "continue;" if arg.variadic else "break;",
'jsvalRef' : "argv.handleAt(%s)" % jsvalIndex,
'jsvalHandle' : "argv.handleAt(%s)" % jsvalIndex,
+ 'jsvalPtr': "&mut argv[%s]" % jsvalIndex,
# XXXbz we don't have anything better to use for 'obj',
# really... It's OK to use CallbackPreserveColor because
# CallSetup already handled the unmark-gray bits for us.
- 'obj' : 'CallbackPreserveColor()',
+ 'obj' : 'ptr::null() /*XXXjdm proper scope*/', #XXXjdm 'CallbackPreserveColor()',
'returnsNewObject': False,
'exceptionCode' : self.exceptionCode
})
@@ -6033,8 +5948,8 @@ class CallbackMember(CGNativeMember):
return args
# We want to allow the caller to pass in a "this" object, as
# well as a JSContext.
- return [Argument("JSContext*", "cx"),
- Argument("JS::Handle<JSObject*>", "aThisObj")] + args
+ return [Argument("*JSContext", "cx"),
+ Argument("*JSObject", "aThisObj")] + args
def getCallSetup(self):
if self.needThisHandling:
@@ -6052,7 +5967,6 @@ class CallbackMember(CGNativeMember):
"${callSetup}\n"
"JSContext* cx = s.GetContext();\n"
"if (!cx) {\n"
- " aRv.Throw(NS_ERROR_UNEXPECTED);\n"
" return${errorReturn};\n"
"}\n").substitute({
"callSetup": callSetup,
@@ -6060,7 +5974,7 @@ class CallbackMember(CGNativeMember):
})
def getArgcDecl(self):
- return CGGeneric("unsigned argc = %s;" % self.argCountStr);
+ return CGGeneric("let argc = %su32;" % self.argCountStr);
@staticmethod
def ensureASCIIName(idlObject):
@@ -6082,7 +5996,7 @@ class CallbackMethod(CallbackMember):
CallbackMember.__init__(self, sig, name, descriptorProvider,
needThisHandling, rethrowContentException)
def getRvalDecl(self):
- return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
+ return "let mut rval = JSVAL_VOID;\n"
def getCall(self):
replacements = {
@@ -6091,15 +6005,14 @@ class CallbackMethod(CallbackMember):
"getCallable": self.getCallableDecl()
}
if self.argCount > 0:
- replacements["argv"] = "argv.begin()"
+ replacements["argv"] = "&argv[0]"
replacements["argc"] = "argc"
else:
replacements["argv"] = "nullptr"
replacements["argc"] = "0"
return string.Template("${getCallable}"
- "if (!JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
- " ${argc}, ${argv}, rval.address())) {\n"
- " aRv.Throw(NS_ERROR_UNEXPECTED);\n"
+ "if unsafe { JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
+ " ${argc}, ${argv}, &rval) == 0 } {\n"
" return${errorReturn};\n"
"}\n").substitute(replacements)
@@ -6125,11 +6038,11 @@ class CallbackOperationBase(CallbackMethod):
def getThisObj(self):
if not self.singleOperation:
- return "mCallback"
+ return "self.parent.callback"
# This relies on getCallableDecl declaring a boolean
# isCallable in the case when we're a single-operation
# interface.
- return "isCallable ? aThisObj.get() : mCallback"
+ return "if isCallable { aThisObj } else { self.parent.callback }"
def getCallableDecl(self):
replacements = {
@@ -6137,17 +6050,16 @@ class CallbackOperationBase(CallbackMethod):
"methodName": self.methodName
}
getCallableFromProp = string.Template(
- 'if (!GetCallableProperty(cx, "${methodName}", &callable)) {\n'
- ' aRv.Throw(NS_ERROR_UNEXPECTED);\n'
+ 'if "${methodName}".to_c_str().with_ref(|name| !self.parent.GetCallableProperty(cx, name, &mut callable)) {\n'
' return${errorReturn};\n'
'}\n').substitute(replacements)
if not self.singleOperation:
return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
return (
- 'bool isCallable = JS_ObjectIsCallable(cx, mCallback);\n'
- 'JS::Rooted<JS::Value> callable(cx);\n'
- 'if (isCallable) {\n'
- ' callable = JS::ObjectValue(*mCallback);\n'
+ 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback) != 0 };\n'
+ 'let mut callable = JSVAL_VOID;\n'
+ 'if isCallable {\n'
+ ' callable = unsafe { RUST_OBJECT_TO_JSVAL(self.parent.callback) };\n'
'} else {\n'
'%s'
'}\n' % CGIndenter(CGGeneric(getCallableFromProp)).define())
@@ -6304,7 +6216,12 @@ class GlobalGenRoots():
@staticmethod
def InterfaceTypes(config):
- descriptors = [d.name for d in config.getDescriptors(register=True)]
+ def pathToType(descriptor):
+ if descriptor.interface.isCallback():
+ return "dom::bindings::codegen::%sBinding" % descriptor.name
+ return "dom::%s" % descriptor.name.lower()
+
+ descriptors = [d.name for d in config.getDescriptors(register=True, hasInterfaceObject=True)]
curr = CGList([CGGeneric(declare="pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors])
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
diff --git a/src/components/script/dom/bindings/codegen/Document.webidl b/src/components/script/dom/bindings/codegen/Document.webidl
index ef479f01a97..10d212910fc 100644
--- a/src/components/script/dom/bindings/codegen/Document.webidl
+++ b/src/components/script/dom/bindings/codegen/Document.webidl
@@ -58,8 +58,8 @@ interface Document : Node {
[Throws]
Node adoptNode(Node node);*/
- // [Creator, Throws]
- // Event createEvent(DOMString interface_);
+ [Creator, Throws]
+ Event createEvent(DOMString interface_);
/*[Creator, Throws]
Range createRange();*/
diff --git a/src/components/script/dom/bindings/codegen/EventListener.webidl b/src/components/script/dom/bindings/codegen/EventListener.webidl
new file mode 100644
index 00000000000..05e1684d31e
--- /dev/null
+++ b/src/components/script/dom/bindings/codegen/EventListener.webidl
@@ -0,0 +1,16 @@
+/* -*- 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.w3.org/TR/2012/WD-dom-20120105/
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+callback interface EventListener {
+ void handleEvent(Event event);
+};
+
diff --git a/src/components/script/dom/bindings/codegen/EventTarget.webidl b/src/components/script/dom/bindings/codegen/EventTarget.webidl
index f4e1ba00f70..897756fa273 100644
--- a/src/components/script/dom/bindings/codegen/EventTarget.webidl
+++ b/src/components/script/dom/bindings/codegen/EventTarget.webidl
@@ -11,4 +11,12 @@
*/
interface EventTarget {
+ void addEventListener(DOMString type,
+ EventListener? listener,
+ optional boolean capture = false);
+ void removeEventListener(DOMString type,
+ EventListener? listener,
+ optional boolean capture = false);
+ [Throws]
+ boolean dispatchEvent(Event event);
};
diff --git a/src/components/script/dom/bindings/codegen/Node.webidl b/src/components/script/dom/bindings/codegen/Node.webidl
index 5f32ff93f67..1a9d9d53bb3 100644
--- a/src/components/script/dom/bindings/codegen/Node.webidl
+++ b/src/components/script/dom/bindings/codegen/Node.webidl
@@ -14,7 +14,7 @@
interface URI;
interface UserDataHandler;*/
-interface Node /*: EventTarget*/ {
+interface Node : EventTarget {
const unsigned short ELEMENT_NODE = 1;
const unsigned short ATTRIBUTE_NODE = 2; // historical
const unsigned short TEXT_NODE = 3;
diff --git a/src/components/script/dom/bindings/codegen/Window.webidl b/src/components/script/dom/bindings/codegen/Window.webidl
index b85890676eb..59ea26308e3 100644
--- a/src/components/script/dom/bindings/codegen/Window.webidl
+++ b/src/components/script/dom/bindings/codegen/Window.webidl
@@ -8,7 +8,7 @@
*/
[NamedPropertiesObject]
-/*sealed*/ interface Window /*: EventTarget*/ {
+/*sealed*/ interface Window : EventTarget {
// the current browsing context
/*[Unforgeable] readonly attribute WindowProxy window;
[Replaceable] readonly attribute WindowProxy self;*/
diff --git a/src/components/script/dom/bindings/node.rs b/src/components/script/dom/bindings/node.rs
index 0ec5b13e80b..8574c084062 100644
--- a/src/components/script/dom/bindings/node.rs
+++ b/src/components/script/dom/bindings/node.rs
@@ -50,7 +50,7 @@ impl Traceable for Node<ScriptView> {
}
}
}
- debug!("tracing {:p}?:", self.reflector_.get_jsobject());
+ debug!("tracing {:p}?:", self.reflector().get_jsobject());
trace_node(tracer, self.parent_node, "parent");
trace_node(tracer, self.first_child, "first child");
trace_node(tracer, self.last_child, "last child");
diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs
index 42f1eb7f4fc..8e8200fb18e 100644
--- a/src/components/script/dom/bindings/utils.rs
+++ b/src/components/script/dom/bindings/utils.rs
@@ -4,8 +4,8 @@
use dom::bindings::codegen::PrototypeList;
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
-use dom::window;
use dom::node::{AbstractNode, ScriptView};
+use dom::window;
use std::libc::c_uint;
use std::cast;
@@ -22,6 +22,7 @@ use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFam
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction, JS_GetGlobalObject};
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength};
+use js::jsapi::{JS_ObjectIsRegExp, JS_ObjectIsDate};
use js::jsapi::{JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject};
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
use js::jsapi::{JS_NewUCStringCopyN, JS_DefineFunctions, JS_DefineProperty};
@@ -30,7 +31,7 @@ use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative, JSTracer};
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JS_NewGlobalObject, JS_InitStandardClasses};
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
-use js::{JSPROP_ENUMERATE, JSVAL_NULL};
+use js::{JSPROP_ENUMERATE, JSVAL_NULL, JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS};
use js::{JSPROP_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER};
use js::{JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE};
use js::{JS_THIS_OBJECT, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY};
@@ -820,6 +821,13 @@ pub fn HasPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid) -> boo
}
#[fixed_stack_segment]
+pub fn IsConvertibleToCallbackInterface(cx: *JSContext, obj: *JSObject) -> bool {
+ unsafe {
+ JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0
+ }
+}
+
+#[fixed_stack_segment]
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
unsafe {
let obj = JS_NewGlobalObject(cx, class, ptr::null());
@@ -832,6 +840,30 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
}
}
+#[fixed_stack_segment]
+fn cx_for_dom_wrapper(obj: *JSObject) -> *JSContext {
+ unsafe {
+ let global = GetGlobalForObjectCrossCompartment(obj);
+ let clasp = JS_GetClass(global);
+ assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
+ //XXXjdm either don't hardcode or sanity assert prototype stuff
+ let win = unwrap_object::<*Box<window::Window>>(global, PrototypeList::id::Window, 1);
+ match win {
+ Ok(win) => {
+ match (*win).data.page.js_info {
+ Some(ref info) => info.js_context.ptr,
+ None => fail!("no JS context for DOM global")
+ }
+ }
+ Err(_) => fail!("found DOM global that doesn't unwrap to Window")
+ }
+ }
+}
+
+pub fn cx_for_dom_object<T: Reflectable>(obj: @mut T) -> *JSContext {
+ cx_for_dom_wrapper(obj.reflector().get_jsobject())
+}
+
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
/// for details.
pub fn is_valid_element_name(name: &str) -> bool {
diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs
index 9805ea71dfa..72f0c378a95 100644
--- a/src/components/script/dom/document.rs
+++ b/src/components/script/dom/document.rs
@@ -10,6 +10,7 @@ use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable, n
use dom::documentfragment::DocumentFragment;
use dom::element::{Element};
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
+use dom::event::Event;
use dom::htmlcollection::HTMLCollection;
use dom::htmldocument::HTMLDocument;
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
@@ -255,6 +256,11 @@ impl Document {
Comment::new(null_str_as_word_null(data), abstract_self)
}
+ pub fn CreateEvent(&self, interface: &DOMString) -> Fallible<@mut Event> {
+ //FIXME: We need to do a proper Event inheritance simulation
+ Ok(Event::new(self.window, interface))
+ }
+
pub fn Title(&self, _: AbstractDocument) -> DOMString {
let mut title = ~"";
match self.doctype {
diff --git a/src/components/script/dom/event.rs b/src/components/script/dom/event.rs
index 43ee6f894c1..1fd709f2dfe 100644
--- a/src/components/script/dom/event.rs
+++ b/src/components/script/dom/event.rs
@@ -6,7 +6,7 @@ use dom::eventtarget::EventTarget;
use dom::window::Window;
use dom::bindings::codegen::EventBinding;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
-use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
+use dom::bindings::utils::{DOMString, ErrorResult, Fallible, null_str_as_word_null};
use geom::point::Point2D;
use js::jsapi::{JSObject, JSContext};
@@ -23,7 +23,7 @@ pub enum Event_ {
pub struct Event {
reflector_: Reflector,
- type_: DOMString,
+ type_: ~str,
default_prevented: bool,
cancelable: bool,
bubbles: bool,
@@ -34,7 +34,7 @@ impl Event {
pub fn new_inherited(type_: &DOMString) -> Event {
Event {
reflector_: Reflector::new(),
- type_: (*type_).clone(),
+ type_: null_str_as_word_null(type_),
default_prevented: false,
cancelable: true,
bubbles: true,
@@ -51,7 +51,7 @@ impl Event {
}
pub fn Type(&self) -> DOMString {
- self.type_.clone()
+ Some(self.type_.clone())
}
pub fn GetTarget(&self) -> Option<@mut EventTarget> {
@@ -92,7 +92,7 @@ impl Event {
type_: &DOMString,
bubbles: bool,
cancelable: bool) -> ErrorResult {
- self.type_ = (*type_).clone();
+ self.type_ = type_.to_str();
self.cancelable = cancelable;
self.bubbles = bubbles;
Ok(())
diff --git a/src/components/script/dom/eventtarget.rs b/src/components/script/dom/eventtarget.rs
index 35a1fe6e6cc..834c1db767c 100644
--- a/src/components/script/dom/eventtarget.rs
+++ b/src/components/script/dom/eventtarget.rs
@@ -2,26 +2,96 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+use dom::bindings::callback::eReportExceptions;
use dom::bindings::codegen::EventTargetBinding;
-use dom::bindings::utils::{Reflectable, Reflector};
+use dom::bindings::utils::{Reflectable, Reflector, DOMString, Fallible};
+use dom::bindings::codegen::EventListenerBinding::EventListener;
+use dom::event::Event;
use script_task::page_from_context;
use js::jsapi::{JSObject, JSContext};
+use std::hashmap::HashMap;
+
pub struct EventTarget {
- reflector_: Reflector
+ reflector_: Reflector,
+ capturing_handlers: HashMap<~str, ~[EventListener]>,
+ bubbling_handlers: HashMap<~str, ~[EventListener]>
}
impl EventTarget {
- pub fn new() -> ~EventTarget {
- ~EventTarget {
- reflector_: Reflector::new()
+ pub fn new() -> EventTarget {
+ EventTarget {
+ reflector_: Reflector::new(),
+ capturing_handlers: HashMap::new(),
+ bubbling_handlers: HashMap::new(),
}
}
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
self.wrap_object_shared(cx, scope);
}
+
+ pub fn AddEventListener(&mut self,
+ ty: &DOMString,
+ listener: Option<EventListener>,
+ capture: bool) {
+ // TODO: Handle adding a listener during event dispatch: should not be invoked during
+ // current phase.
+ // (https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener#Adding_a_listener_during_event_dispatch)
+
+ for listener in listener.iter() {
+ let handlers = if capture {
+ &mut self.capturing_handlers
+ } else {
+ &mut self.bubbling_handlers
+ };
+ let entry = handlers.find_or_insert_with(ty.to_str(), |_| ~[]);
+ if entry.position_elem(listener).is_none() {
+ entry.push((*listener).clone());
+ }
+ }
+ }
+
+ pub fn RemoveEventListener(&mut self,
+ ty: &DOMString,
+ listener: Option<EventListener>,
+ capture: bool) {
+ for listener in listener.iter() {
+ let handlers = if capture {
+ &mut self.capturing_handlers
+ } else {
+ &mut self.bubbling_handlers
+ };
+ let mut entry = handlers.find_mut(&ty.to_str());
+ for entry in entry.mut_iter() {
+ let position = entry.position_elem(listener);
+ for &position in position.iter() {
+ entry.remove(position);
+ }
+ }
+ }
+ }
+
+ pub fn DispatchEvent(&self, event: @mut Event) -> Fallible<bool> {
+ //FIXME: get proper |this| object
+
+ let maybe_handlers = self.capturing_handlers.find(&event.type_);
+ for handlers in maybe_handlers.iter() {
+ for handler in handlers.iter() {
+ handler.HandleEvent__(event, eReportExceptions);
+ }
+ }
+ if event.bubbles {
+ let maybe_handlers = self.bubbling_handlers.find(&event.type_);
+ for handlers in maybe_handlers.iter() {
+ for handler in handlers.iter() {
+ handler.HandleEvent__(event, eReportExceptions);
+ }
+ }
+ }
+ Ok(!event.DefaultPrevented())
+ }
}
impl Reflectable for EventTarget {
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 2caa76eed69..2e331cc82f9 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -12,6 +12,7 @@ use dom::document::{AbstractDocument, DocumentTypeId};
use dom::documenttype::DocumentType;
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId};
use dom::element::{HTMLStyleElementTypeId};
+use dom::eventtarget::EventTarget;
use dom::nodelist::{NodeList};
use dom::htmlimageelement::HTMLImageElement;
use dom::htmliframeelement::HTMLIFrameElement;
@@ -63,7 +64,7 @@ pub struct AbstractNodeChildrenIterator<View> {
/// `LayoutData`.
pub struct Node<View> {
/// The JavaScript reflector for this node.
- reflector_: Reflector,
+ eventtarget: EventTarget,
/// The type of node that this is.
type_id: NodeTypeId,
@@ -521,7 +522,7 @@ impl Node<ScriptView> {
fn new_(type_id: NodeTypeId, doc: Option<AbstractDocument>) -> Node<ScriptView> {
Node {
- reflector_: Reflector::new(),
+ eventtarget: EventTarget::new(),
type_id: type_id,
abstract: None,
@@ -961,11 +962,11 @@ impl Node<ScriptView> {
impl Reflectable for Node<ScriptView> {
fn reflector<'a>(&'a self) -> &'a Reflector {
- &self.reflector_
+ self.eventtarget.reflector()
}
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
- &mut self.reflector_
+ self.eventtarget.mut_reflector()
}
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs
index 0a5bb19d3ec..46565b7fb09 100644
--- a/src/components/script/dom/window.rs
+++ b/src/components/script/dom/window.rs
@@ -6,6 +6,7 @@ use dom::bindings::codegen::WindowBinding;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::bindings::utils::{DOMString, null_str_as_empty, Traceable};
use dom::document::AbstractDocument;
+use dom::eventtarget::EventTarget;
use dom::node::{AbstractNode, ScriptView};
use dom::navigator::Navigator;
@@ -37,10 +38,10 @@ pub enum TimerControlMsg {
}
pub struct Window {
+ eventtarget: EventTarget,
page: @mut Page,
script_chan: ScriptChan,
compositor: @ScriptListener,
- reflector_: Reflector,
timer_chan: SharedChan<TimerControlMsg>,
navigator: Option<@mut Navigator>,
image_cache_task: ImageCacheTask,
@@ -140,11 +141,11 @@ impl Window {
impl Reflectable for Window {
fn reflector<'a>(&'a self) -> &'a Reflector {
- &self.reflector_
+ self.eventtarget.reflector()
}
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
- &mut self.reflector_
+ self.eventtarget.mut_reflector()
}
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
@@ -204,10 +205,10 @@ impl Window {
image_cache_task: ImageCacheTask)
-> @mut Window {
let win = @mut Window {
+ eventtarget: EventTarget::new(),
page: page,
script_chan: script_chan.clone(),
compositor: compositor,
- reflector_: Reflector::new(),
timer_chan: {
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
let id = page.id.clone();
diff --git a/src/components/script/script.rc b/src/components/script/script.rc
index bef239a5ec9..675796e2c47 100644
--- a/src/components/script/script.rc
+++ b/src/components/script/script.rc
@@ -28,6 +28,7 @@ pub mod dom {
pub mod element;
pub mod node;
pub mod utils;
+ pub mod callback;
pub mod conversions;
pub mod proxyhandler;
pub mod codegen {
diff --git a/src/support/spidermonkey/rust-mozjs b/src/support/spidermonkey/rust-mozjs
-Subproject 1df26877d82d9722785de91ff59ab069a5acc18
+Subproject 566c2af971abaa5e8c51b59fa400a7e07835b25
diff --git a/src/test/html/content/test_event_listener.html b/src/test/html/content/test_event_listener.html
new file mode 100644
index 00000000000..5feeda8a374
--- /dev/null
+++ b/src/test/html/content/test_event_listener.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<script src="harness.js"></script>
+</head>
+<body>
+<script>
+ function onFoopy() {
+ window.removeEventListener('foopy', onFoopy);
+ finish();
+ }
+ window.addEventListener('foopy', onFoopy);
+ var ev = document.createEvent('Event');
+ ev.initEvent('foopy', true, true);
+ window.dispatchEvent(ev);
+</script>
+</body>
+</html>