mirror of
https://github.com/servo/servo.git
synced 2025-06-17 04:44:28 +00:00
Generate code for handling callbacks. Implement add/removeEventListener and hacky dispatchEvent proof-of-concept.
This commit is contained in:
parent
06b1db8818
commit
7ecf5abbbd
18 changed files with 491 additions and 331 deletions
105
src/components/script/dom/bindings/callback.rs
Normal file
105
src/components/script/dom/bindings/callback.rs
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -184,26 +184,12 @@ DOMInterfaces = {
|
||||||
'Event': {
|
'Event': {
|
||||||
},
|
},
|
||||||
|
|
||||||
'EventListener': [
|
'EventListener': {
|
||||||
{
|
'nativeType': 'EventListenerBinding::EventListener',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'workers': True,
|
|
||||||
}],
|
|
||||||
|
|
||||||
'EventTarget': [
|
'EventTarget': {
|
||||||
{
|
|
||||||
# 'nativeType': 'nsDOMEventTargetHelper',
|
|
||||||
# 'hasInstanceInterface': 'nsIDOMEventTarget',
|
|
||||||
# 'concrete': False,
|
|
||||||
# 'prefable': True,
|
|
||||||
},
|
},
|
||||||
#{
|
|
||||||
# 'workers': True,
|
|
||||||
# 'headerFile': 'mozilla/dom/workers/bindings/EventTarget.h',
|
|
||||||
# 'concrete': False
|
|
||||||
#}
|
|
||||||
],
|
|
||||||
|
|
||||||
'FileList': [
|
'FileList': [
|
||||||
{
|
{
|
||||||
|
|
|
@ -525,7 +525,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
||||||
# failureCode will prevent pending exceptions from being set in cases when
|
# failureCode will prevent pending exceptions from being set in cases when
|
||||||
# they really should be!
|
# they really should be!
|
||||||
if exceptionCode is None:
|
if exceptionCode is None:
|
||||||
exceptionCode = "return false;"
|
exceptionCode = "return 0;"
|
||||||
# We often want exceptionCode to be indented, since it often appears in an
|
# We often want exceptionCode to be indented, since it often appears in an
|
||||||
# if body.
|
# if body.
|
||||||
exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
|
exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
|
||||||
|
@ -915,19 +915,14 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
type.unroll().inner.identifier.name)
|
type.unroll().inner.identifier.name)
|
||||||
|
|
||||||
if descriptor.interface.isCallback():
|
if descriptor.interface.isCallback():
|
||||||
name = descriptor.interface.identifier.name
|
name = descriptor.nativeType
|
||||||
if type.nullable() or isCallbackReturnValue:
|
declType = CGGeneric("Option<%s>" % name);
|
||||||
declType = CGGeneric("nsRefPtr<%s>" % name);
|
conversion = (" ${declName} = Some(%s::new(JSVAL_TO_OBJECT(${val})));\n" % name)
|
||||||
else:
|
|
||||||
declType = CGGeneric("OwningNonNull<%s>" % name)
|
|
||||||
conversion = (
|
|
||||||
" ${declName} = new %s(&${val}.toObject());\n" % name)
|
|
||||||
|
|
||||||
template = wrapObjectTemplate(conversion, type,
|
template = wrapObjectTemplate(conversion, type,
|
||||||
"${declName} = nullptr",
|
"${declName} = None",
|
||||||
failureCode)
|
failureCode)
|
||||||
return JSToNativeConversionInfo(template, declType=declType,
|
return (template, declType, None, isOptional, None)
|
||||||
dealWithOptional=isOptional)
|
|
||||||
|
|
||||||
# This is an interface that we implement as a concrete class
|
# This is an interface that we implement as a concrete class
|
||||||
# or an XPCOM interface.
|
# or an XPCOM interface.
|
||||||
|
@ -980,13 +975,6 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
"JSVAL_TO_OBJECT(${val})",
|
"JSVAL_TO_OBJECT(${val})",
|
||||||
"${declName}",
|
"${declName}",
|
||||||
isOptional or argIsPointer or type.nullable()))
|
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:
|
elif descriptor.workers:
|
||||||
templateBody += "${declName} = &${val}.toObject();"
|
templateBody += "${declName} = &${val}.toObject();"
|
||||||
else:
|
else:
|
||||||
|
@ -1265,7 +1253,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
assert not isOptional
|
assert not isOptional
|
||||||
# This one only happens for return values, and its easy: Just
|
# This one only happens for return values, and its easy: Just
|
||||||
# ignore the jsval.
|
# ignore the jsval.
|
||||||
return JSToNativeConversionInfo("")
|
return ("", None, None, False, None)
|
||||||
|
|
||||||
if not type.isPrimitive():
|
if not type.isPrimitive():
|
||||||
raise TypeError("Need conversion for argument type '%s'" % str(type))
|
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():
|
if type.nullable():
|
||||||
dataLoc = "${declName}.SetValue()"
|
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):
|
if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
|
||||||
nullCondition = "!(${haveValue}) || " + nullCondition
|
nullCondition = "!(${haveValue}) || " + nullCondition
|
||||||
|
#XXXjdm support conversionBehavior here
|
||||||
template = (
|
template = (
|
||||||
"if (%s) {\n"
|
"if (%s) {\n"
|
||||||
" ${declName}.SetNull();\n"
|
" ${declName} = None;\n"
|
||||||
"} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
|
"} else {\n"
|
||||||
" return false;\n"
|
" match JSValConvertible::from_jsval(${val}) {\n"
|
||||||
"}" % (nullCondition, typeName, conversionBehavior, dataLoc))
|
" Some(val_) => ${declName} = Some(val_),\n"
|
||||||
declType = CGGeneric("Nullable<" + typeName + ">")
|
" None => return 0\n"
|
||||||
|
" }\n"
|
||||||
|
"}" % nullCondition)
|
||||||
|
declType = CGGeneric("Option<" + typeName + ">")
|
||||||
else:
|
else:
|
||||||
assert(defaultValue is None or
|
assert(defaultValue is None or
|
||||||
not isinstance(defaultValue, IDLNullValue))
|
not isinstance(defaultValue, IDLNullValue))
|
||||||
|
@ -1317,10 +1309,10 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
" %s = %s;\n"
|
" %s = %s;\n"
|
||||||
"}" % (dataLoc, defaultStr))).define()
|
"}" % (dataLoc, defaultStr))).define()
|
||||||
|
|
||||||
if typeName != "bool":
|
initialVal = "false" if typeName == "bool" else ("0 as %s" % typeName)
|
||||||
return (template, declType, None, isOptional, "0 as %s" % typeName)
|
if type.nullable():
|
||||||
else:
|
initialVal = "Some(%s)" % initialVal
|
||||||
return (template, declType, None, isOptional, "false")
|
return (template, declType, None, isOptional, initialVal)
|
||||||
|
|
||||||
def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
|
def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
|
||||||
argcAndIndex=None):
|
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
|
# Non-prefable bindings can only fail to wrap as a new-binding object
|
||||||
# if they already threw an exception. Same thing for
|
# if they already threw an exception. Same thing for
|
||||||
# non-prefable bindings.
|
# non-prefable bindings.
|
||||||
failed = ("//MOZ_ASSERT(JS_IsExceptionPending(cx));\n" +
|
failed = ("assert!(unsafe { JS_IsExceptionPending(cx) != 0 });\n" +
|
||||||
"return 0;")
|
"%s" % exceptionCode)
|
||||||
else:
|
else:
|
||||||
if descriptor.notflattened:
|
if descriptor.notflattened:
|
||||||
raise TypeError("%s is prefable but not flattened; "
|
raise TypeError("%s is prefable but not flattened; "
|
||||||
|
@ -2423,9 +2415,10 @@ class Argument():
|
||||||
self.name = name
|
self.name = name
|
||||||
self.default = default
|
self.default = default
|
||||||
def declare(self):
|
def declare(self):
|
||||||
string = self.argType + ' ' + self.name
|
string = self.name + ((': ' + self.argType) if self.argType else '')
|
||||||
if self.default is not None:
|
#XXXjdm Support default arguments somehow :/
|
||||||
string += " = " + self.default
|
#if self.default is not None:
|
||||||
|
# string += " = " + self.default
|
||||||
return string
|
return string
|
||||||
def define(self):
|
def define(self):
|
||||||
return self.argType + ' ' + self.name
|
return self.argType + ' ' + self.name
|
||||||
|
@ -2470,7 +2463,7 @@ class CGAbstractMethod(CGThing):
|
||||||
self.pub = pub;
|
self.pub = pub;
|
||||||
self.unsafe = unsafe
|
self.unsafe = unsafe
|
||||||
def _argstring(self, declare):
|
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):
|
def _template(self):
|
||||||
if self.templateArgs is None:
|
if self.templateArgs is None:
|
||||||
return ''
|
return ''
|
||||||
|
@ -3575,7 +3568,7 @@ class ClassItem:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
class ClassBase(ClassItem):
|
class ClassBase(ClassItem):
|
||||||
def __init__(self, name, visibility='public'):
|
def __init__(self, name, visibility='pub'):
|
||||||
ClassItem.__init__(self, name, visibility)
|
ClassItem.__init__(self, name, visibility)
|
||||||
def declare(self, cgClass):
|
def declare(self, cgClass):
|
||||||
return '%s %s' % (self.visibility, self.name)
|
return '%s %s' % (self.visibility, self.name)
|
||||||
|
@ -3595,11 +3588,11 @@ class ClassMethod(ClassItem):
|
||||||
assert not override or virtual
|
assert not override or virtual
|
||||||
self.returnType = returnType
|
self.returnType = returnType
|
||||||
self.args = args
|
self.args = args
|
||||||
self.inline = inline or bodyInHeader
|
self.inline = False
|
||||||
self.static = static
|
self.static = static
|
||||||
self.virtual = virtual
|
self.virtual = virtual
|
||||||
self.const = const
|
self.const = const
|
||||||
self.bodyInHeader = bodyInHeader
|
self.bodyInHeader = True
|
||||||
self.templateArgs = templateArgs
|
self.templateArgs = templateArgs
|
||||||
self.body = body
|
self.body = body
|
||||||
self.breakAfterReturnDecl = breakAfterReturnDecl
|
self.breakAfterReturnDecl = breakAfterReturnDecl
|
||||||
|
@ -3608,7 +3601,7 @@ class ClassMethod(ClassItem):
|
||||||
ClassItem.__init__(self, name, visibility)
|
ClassItem.__init__(self, name, visibility)
|
||||||
|
|
||||||
def getDecorators(self, declaring):
|
def getDecorators(self, declaring):
|
||||||
decorators = []
|
decorators = ['#[fixed_stack_segment]']
|
||||||
if self.inline:
|
if self.inline:
|
||||||
decorators.append('inline')
|
decorators.append('inline')
|
||||||
if declaring:
|
if declaring:
|
||||||
|
@ -3626,62 +3619,32 @@ class ClassMethod(ClassItem):
|
||||||
return self.body
|
return self.body
|
||||||
|
|
||||||
def declare(self, cgClass):
|
def declare(self, cgClass):
|
||||||
templateClause = 'template <%s>\n' % ', '.join(self.templateArgs) \
|
templateClause = '<%s>' % ', '.join(self.templateArgs) \
|
||||||
if self.bodyInHeader and self.templateArgs else ''
|
if self.bodyInHeader and self.templateArgs else ''
|
||||||
args = ', '.join([a.declare() for a in self.args])
|
args = ', '.join([a.declare() for a in self.args])
|
||||||
if self.bodyInHeader:
|
if self.bodyInHeader:
|
||||||
body = CGIndenter(CGGeneric(self.getBody())).define()
|
body = CGIndenter(CGGeneric(self.getBody())).define()
|
||||||
body = '\n{\n' + body + '\n}'
|
body = ' {\n' + body + '\n}'
|
||||||
else:
|
else:
|
||||||
body = ';'
|
body = ';'
|
||||||
|
|
||||||
return string.Template("${templateClause}${decorators}${returnType}%s"
|
return string.Template("${decorators}%s"
|
||||||
"${name}(${args})${const}${override}${body}%s" %
|
"${visibility}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" %
|
||||||
(self.breakAfterReturnDecl, self.breakAfterSelf)
|
(self.breakAfterReturnDecl, self.breakAfterSelf)
|
||||||
).substitute({
|
).substitute({
|
||||||
'templateClause': templateClause,
|
'templateClause': templateClause,
|
||||||
'decorators': self.getDecorators(True),
|
'decorators': self.getDecorators(True),
|
||||||
'returnType': self.returnType,
|
'returnType': (" -> %s" % self.returnType) if self.returnType else "",
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
'const': ' const' if self.const else '',
|
'const': ' const' if self.const else '',
|
||||||
'override': ' MOZ_OVERRIDE' if self.override else '',
|
'override': ' MOZ_OVERRIDE' if self.override else '',
|
||||||
'args': args,
|
'args': args,
|
||||||
'body': body
|
'body': body,
|
||||||
|
'visibility': self.visibility + ' ' if self.visibility is not 'priv' else ''
|
||||||
})
|
})
|
||||||
|
|
||||||
def define(self, cgClass):
|
def define(self, cgClass):
|
||||||
if self.bodyInHeader:
|
pass
|
||||||
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 })
|
|
||||||
|
|
||||||
class ClassUsingDeclaration(ClassItem):
|
class ClassUsingDeclaration(ClassItem):
|
||||||
""""
|
""""
|
||||||
|
@ -3729,10 +3692,10 @@ class ClassConstructor(ClassItem):
|
||||||
body contains a string with the code for the constructor, defaults to empty.
|
body contains a string with the code for the constructor, defaults to empty.
|
||||||
"""
|
"""
|
||||||
def __init__(self, args, inline=False, bodyInHeader=False,
|
def __init__(self, args, inline=False, bodyInHeader=False,
|
||||||
visibility="private", explicit=False, baseConstructors=None,
|
visibility="priv", explicit=False, baseConstructors=None,
|
||||||
body=""):
|
body=""):
|
||||||
self.args = args
|
self.args = args
|
||||||
self.inline = inline or bodyInHeader
|
self.inline = False
|
||||||
self.bodyInHeader = bodyInHeader
|
self.bodyInHeader = bodyInHeader
|
||||||
self.explicit = explicit
|
self.explicit = explicit
|
||||||
self.baseConstructors = baseConstructors or []
|
self.baseConstructors = baseConstructors or []
|
||||||
|
@ -3761,21 +3724,22 @@ class ClassConstructor(ClassItem):
|
||||||
return '\n : ' + ',\n '.join(items)
|
return '\n : ' + ',\n '.join(items)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def getBody(self):
|
def getBody(self, cgClass):
|
||||||
return self.body
|
initializers = [" parent: %s" % str(self.baseConstructors[0])]
|
||||||
|
return (self.body + (
|
||||||
|
"%s {\n"
|
||||||
|
"%s\n"
|
||||||
|
"}") % (cgClass.name, '\n'.join(initializers)))
|
||||||
|
|
||||||
def declare(self, cgClass):
|
def declare(self, cgClass):
|
||||||
args = ', '.join([a.declare() for a in self.args])
|
args = ', '.join([a.declare() for a in self.args])
|
||||||
if self.bodyInHeader:
|
body = ' ' + self.getBody(cgClass);
|
||||||
body = ' ' + self.getBody();
|
body = stripTrailingWhitespace(body.replace('\n', '\n '))
|
||||||
body = stripTrailingWhitespace(body.replace('\n', '\n '))
|
if len(body) > 0:
|
||||||
if len(body) > 0:
|
body += '\n'
|
||||||
body += '\n'
|
body = ' {\n' + body + '}'
|
||||||
body = self.getInitializationList(cgClass) + '\n{\n' + body + '}'
|
|
||||||
else:
|
|
||||||
body = ';'
|
|
||||||
|
|
||||||
return string.Template("""${decorators}${className}(${args})${body}
|
return string.Template("""pub fn ${decorators}new(${args}) -> ${className}${body}
|
||||||
""").substitute({ 'decorators': self.getDecorators(True),
|
""").substitute({ 'decorators': self.getDecorators(True),
|
||||||
'className': cgClass.getNameString(),
|
'className': cgClass.getNameString(),
|
||||||
'args': args,
|
'args': args,
|
||||||
|
@ -3870,7 +3834,7 @@ ${className}::~${className}()
|
||||||
'body': body })
|
'body': body })
|
||||||
|
|
||||||
class ClassMember(ClassItem):
|
class ClassMember(ClassItem):
|
||||||
def __init__(self, name, type, visibility="private", static=False,
|
def __init__(self, name, type, visibility="priv", static=False,
|
||||||
body=None):
|
body=None):
|
||||||
self.type = type;
|
self.type = type;
|
||||||
self.static = static
|
self.static = static
|
||||||
|
@ -3878,8 +3842,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 %s;\n' % ('static ' if self.static else '', self.type,
|
return '%s: %s,\n' % (self.name, self.type)
|
||||||
self.name)
|
|
||||||
|
|
||||||
def define(self, cgClass):
|
def define(self, cgClass):
|
||||||
if not self.static:
|
if not self.static:
|
||||||
|
@ -3962,7 +3925,7 @@ class CGClass(CGThing):
|
||||||
self.isStruct = isStruct
|
self.isStruct = isStruct
|
||||||
self.disallowCopyConstruction = disallowCopyConstruction
|
self.disallowCopyConstruction = disallowCopyConstruction
|
||||||
self.indent = indent
|
self.indent = indent
|
||||||
self.defaultVisibility ='public' if isStruct else 'private'
|
self.defaultVisibility ='pub' if isStruct else 'priv'
|
||||||
self.decorators = decorators
|
self.decorators = decorators
|
||||||
self.extradeclarations = extradeclarations
|
self.extradeclarations = extradeclarations
|
||||||
self.extradefinitions = extradefinitions
|
self.extradefinitions = extradefinitions
|
||||||
|
@ -3983,68 +3946,36 @@ class CGClass(CGThing):
|
||||||
result = result + self.indent + 'template <%s>\n' \
|
result = result + self.indent + 'template <%s>\n' \
|
||||||
% ','.join([str(a) for a in templateArgs])
|
% ','.join([str(a) for a in templateArgs])
|
||||||
|
|
||||||
type = 'struct' if self.isStruct else 'class'
|
|
||||||
|
|
||||||
if self.templateSpecialization:
|
if self.templateSpecialization:
|
||||||
specialization = \
|
specialization = \
|
||||||
'<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
|
'<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
|
||||||
else:
|
else:
|
||||||
specialization = ''
|
specialization = ''
|
||||||
|
|
||||||
myself = '%s%s %s%s' % (self.indent, type, self.name, specialization)
|
myself = ''
|
||||||
if self.decorators != '':
|
if self.decorators != '':
|
||||||
myself += " " + self.decorators
|
myself += self.decorators + '\n'
|
||||||
|
myself += '%spub struct %s%s' % (self.indent, self.name, specialization)
|
||||||
result += myself
|
result += myself
|
||||||
|
|
||||||
if self.bases:
|
assert len(self.bases) == 1 #XXjdm Can we support multiple inheritance?
|
||||||
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
|
result += '{\n%s\n' % self.indent
|
||||||
|
|
||||||
|
if self.bases:
|
||||||
|
self.members = [ClassMember("parent", self.bases[0].name, "pub")] + self.members
|
||||||
|
|
||||||
result += CGIndenter(CGGeneric(self.extradeclarations),
|
result += CGIndenter(CGGeneric(self.extradeclarations),
|
||||||
len(self.indent)).define()
|
len(self.indent)).define()
|
||||||
|
|
||||||
def declareMembers(cgClass, memberList, defaultVisibility, itemCount,
|
def declareMembers(cgClass, memberList):
|
||||||
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' ]
|
|
||||||
|
|
||||||
result = ''
|
result = ''
|
||||||
|
|
||||||
lastVisibility = defaultVisibility
|
for member in memberList:
|
||||||
for visibility in order:
|
declaration = member.declare(cgClass)
|
||||||
list = members[visibility]
|
declaration = CGIndenter(CGGeneric(declaration)).define()
|
||||||
if list:
|
result = result + declaration
|
||||||
if visibility != lastVisibility:
|
return result
|
||||||
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)
|
|
||||||
|
|
||||||
if self.disallowCopyConstruction:
|
if self.disallowCopyConstruction:
|
||||||
class DisallowedCopyConstructor(object):
|
class DisallowedCopyConstructor(object):
|
||||||
|
@ -4059,47 +3990,32 @@ class CGClass(CGThing):
|
||||||
disallowedCopyConstructors = []
|
disallowedCopyConstructors = []
|
||||||
|
|
||||||
order = [(self.enums, ''), (self.unions, ''),
|
order = [(self.enums, ''), (self.unions, ''),
|
||||||
(self.typedefs, ''), (self.members, ''),
|
(self.typedefs, ''), (self.members, '')]
|
||||||
(self.constructors + disallowedCopyConstructors, '\n'),
|
|
||||||
(self.destructors, '\n'), (self.methods, '\n')]
|
|
||||||
|
|
||||||
lastVisibility = self.defaultVisibility
|
|
||||||
itemCount = 0
|
|
||||||
for (memberList, separator) in order:
|
for (memberList, separator) in order:
|
||||||
(memberString, lastVisibility, itemCount) = \
|
memberString = declareMembers(self, memberList)
|
||||||
declareMembers(self, memberList, lastVisibility, itemCount,
|
|
||||||
separator)
|
|
||||||
if self.indent:
|
if self.indent:
|
||||||
memberString = CGIndenter(CGGeneric(memberString),
|
memberString = CGIndenter(CGGeneric(memberString),
|
||||||
len(self.indent)).define()
|
len(self.indent)).define()
|
||||||
result = result + memberString
|
result = result + memberString
|
||||||
|
|
||||||
result = result + self.indent + '};\n'
|
result += self.indent + '}\n\n'
|
||||||
|
result += 'impl %s {\n' % self.name
|
||||||
|
|
||||||
|
order = [(self.constructors + disallowedCopyConstructors, '\n'),
|
||||||
|
(self.destructors, '\n'), (self.methods, '\n)')]
|
||||||
|
for (memberList, separator) in order:
|
||||||
|
memberString = declareMembers(self, memberList)
|
||||||
|
if self.indent:
|
||||||
|
memberString = CGIndenter(CGGeneric(memberString),
|
||||||
|
len(self.indent)).define()
|
||||||
|
result = result + memberString
|
||||||
|
|
||||||
|
result += "}"
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def define(self):
|
def define(self):
|
||||||
def defineMembers(cgClass, memberList, itemCount, separator=''):
|
return ''
|
||||||
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
|
|
||||||
for (memberList, separator) in order:
|
|
||||||
(memberString, itemCount) = defineMembers(self, memberList,
|
|
||||||
itemCount, separator)
|
|
||||||
result = result + memberString
|
|
||||||
return result
|
|
||||||
|
|
||||||
class CGXrayHelper(CGAbstractExternMethod):
|
class CGXrayHelper(CGAbstractExternMethod):
|
||||||
def __init__(self, descriptor, name, args, properties):
|
def __init__(self, descriptor, name, args, properties):
|
||||||
|
@ -5301,10 +5217,10 @@ class CGBindingRoot(CGThing):
|
||||||
'js::glue::*',
|
'js::glue::*',
|
||||||
'dom::types::*',
|
'dom::types::*',
|
||||||
'dom::bindings::utils::*',
|
'dom::bindings::utils::*',
|
||||||
|
'dom::bindings::callback::*',
|
||||||
'dom::bindings::conversions::*',
|
'dom::bindings::conversions::*',
|
||||||
'dom::bindings::codegen::*', #XXXjdm
|
'dom::bindings::codegen::*', #XXXjdm
|
||||||
'script_task::{JSPageInfo, page_from_context}',
|
'script_task::{JSPageInfo, page_from_context}',
|
||||||
'dom::bindings::utils::EnumEntry',
|
|
||||||
'dom::bindings::proxyhandler',
|
'dom::bindings::proxyhandler',
|
||||||
'dom::bindings::proxyhandler::*',
|
'dom::bindings::proxyhandler::*',
|
||||||
'dom::document::AbstractDocument',
|
'dom::document::AbstractDocument',
|
||||||
|
@ -5383,29 +5299,31 @@ class CGNativeMember(ClassMethod):
|
||||||
never examine this value.
|
never examine this value.
|
||||||
"""
|
"""
|
||||||
if type.isVoid():
|
if type.isVoid():
|
||||||
return "void", "", ""
|
typeDecl, errorDefault, template = "", "", ""
|
||||||
if 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()])
|
||||||
defaultReturnArg = "0"
|
defaultReturnArg = "0"
|
||||||
if type.nullable():
|
if type.nullable():
|
||||||
result = CGTemplatedType("Nullable", result)
|
result = CGTemplatedType("Nullable", result)
|
||||||
defaultReturnArg = ""
|
defaultReturnArg = ""
|
||||||
return (result.define(),
|
typeDecl, errorDefault, template = \
|
||||||
"%s(%s)" % (result.define(), defaultReturnArg),
|
(result.define(),
|
||||||
"return ${declName};")
|
"%s(%s)" % (result.define(), defaultReturnArg),
|
||||||
if type.isDOMString():
|
"return ${declName};")
|
||||||
|
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
|
||||||
return "nsString", None, None
|
typeDecl, errorDefault, template = "nsString", None, None
|
||||||
# Outparam
|
# Outparam
|
||||||
return "void", "", "retval = ${declName};"
|
else:
|
||||||
if type.isByteString():
|
typeDecl, errorDefault, template = "void", "", "retval = ${declName};"
|
||||||
|
elif type.isByteString():
|
||||||
if isMember:
|
if isMember:
|
||||||
# No need for a third element in the isMember case
|
# No need for a third element in the isMember case
|
||||||
return "nsCString", None, None
|
typeDecl, errorDefault, template = "nsCString", None, None
|
||||||
# Outparam
|
# Outparam
|
||||||
return "void", "", "retval = ${declName};"
|
typeDecl, errorDefault, template = "void", "", "retval = ${declName};"
|
||||||
if type.isEnum():
|
elif type.isEnum():
|
||||||
enumName = type.unroll().inner.identifier.name
|
enumName = type.unroll().inner.identifier.name
|
||||||
if type.nullable():
|
if type.nullable():
|
||||||
enumName = CGTemplatedType("Nullable",
|
enumName = CGTemplatedType("Nullable",
|
||||||
|
@ -5413,8 +5331,8 @@ class CGNativeMember(ClassMethod):
|
||||||
defaultValue = "%s()" % enumName
|
defaultValue = "%s()" % enumName
|
||||||
else:
|
else:
|
||||||
defaultValue = "%s(0)" % enumName
|
defaultValue = "%s(0)" % enumName
|
||||||
return enumName, defaultValue, "return ${declName};"
|
typeDecl, errorDefault, template = enumName, defaultValue, "return ${declName};"
|
||||||
if type.isGeckoInterface():
|
elif type.isGeckoInterface():
|
||||||
iface = type.unroll().inner;
|
iface = type.unroll().inner;
|
||||||
nativeType = self.descriptorProvider.getDescriptor(
|
nativeType = self.descriptorProvider.getDescriptor(
|
||||||
iface.identifier.name).nativeType
|
iface.identifier.name).nativeType
|
||||||
|
@ -5442,21 +5360,25 @@ class CGNativeMember(ClassMethod):
|
||||||
# Since we always force an owning type for callback return values,
|
# Since we always force an owning type for callback return values,
|
||||||
# our ${declName} is an OwningNonNull or nsRefPtr. So we can just
|
# our ${declName} is an OwningNonNull or nsRefPtr. So we can just
|
||||||
# .forget() to get our already_AddRefed.
|
# .forget() to get our already_AddRefed.
|
||||||
return result.define(), "nullptr", "return ${declName}.forget();"
|
typeDecl, errorDefault, template = \
|
||||||
if type.isCallback():
|
result.define(), "nullptr", "return ${declName}.forget();"
|
||||||
return ("already_AddRefed<%s>" % type.unroll().identifier.name,
|
elif type.isCallback():
|
||||||
"nullptr", "return ${declName}.forget();")
|
typeDecl, errorDefault, template = \
|
||||||
if type.isAny():
|
("already_AddRefed<%s>" % type.unroll().identifier.name,
|
||||||
return "JS::Value", "JS::UndefinedValue()", "return ${declName};"
|
"nullptr", "return ${declName}.forget();")
|
||||||
if type.isObject():
|
elif type.isAny():
|
||||||
return "JSObject*", "nullptr", "return ${declName};"
|
typeDecl, errorDefault, template = \
|
||||||
if type.isSpiderMonkeyInterface():
|
"JS::Value", "JS::UndefinedValue()", "return ${declName};"
|
||||||
|
elif type.isObject():
|
||||||
|
typeDecl, errorDefault, template = \
|
||||||
|
"JSObject*", "nullptr", "return ${declName};"
|
||||||
|
elif type.isSpiderMonkeyInterface():
|
||||||
if type.nullable():
|
if type.nullable():
|
||||||
returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
|
returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
|
||||||
else:
|
else:
|
||||||
returnCode = "return ${declName}.Obj();"
|
returnCode = "return ${declName}.Obj();"
|
||||||
return "JSObject*", "nullptr", returnCode
|
typeDecl, errorDefault, template = "JSObject*", "nullptr", returnCode
|
||||||
if type.isSequence():
|
elif type.isSequence():
|
||||||
# If we want to handle sequence-of-sequences return values, we're
|
# If we want to handle sequence-of-sequences return values, we're
|
||||||
# going to need to fix example codegen to not produce nsTArray<void>
|
# going to need to fix example codegen to not produce nsTArray<void>
|
||||||
# for the relevant argument...
|
# for the relevant argument...
|
||||||
|
@ -5470,15 +5392,26 @@ class CGNativeMember(ClassMethod):
|
||||||
"}")
|
"}")
|
||||||
else:
|
else:
|
||||||
returnCode = "retval.SwapElements(${declName});"
|
returnCode = "retval.SwapElements(${declName});"
|
||||||
return "void", "", returnCode
|
typeDecl, errorDefault, template = "void", "", returnCode
|
||||||
if type.isDate():
|
elif type.isDate():
|
||||||
result = CGGeneric("Date")
|
result = CGGeneric("Date")
|
||||||
if type.nullable():
|
if type.nullable():
|
||||||
result = CGTemplatedType("Nullable", result)
|
result = CGTemplatedType("Nullable", result)
|
||||||
return (result.define(), "%s()" % result.define(),
|
typeDecl, errorDefault, template = \
|
||||||
"return ${declName};")
|
(result.define(), "%s()" % result.define(), "return ${declName};")
|
||||||
raise TypeError("Don't know how to declare return value for %s" %
|
else:
|
||||||
type)
|
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):
|
def getArgs(self, returnType, argList):
|
||||||
args = [self.getArg(arg) for arg in argList]
|
args = [self.getArg(arg) for arg in argList]
|
||||||
|
@ -5497,10 +5430,6 @@ class CGNativeMember(ClassMethod):
|
||||||
if nullable:
|
if nullable:
|
||||||
type = CGTemplatedType("Nullable", type)
|
type = CGTemplatedType("Nullable", type)
|
||||||
args.append(Argument("%s&" % type.define(), "retval"))
|
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
|
# The legacycaller thisval
|
||||||
if self.member.isMethod() and self.member.isLegacycaller():
|
if self.member.isMethod() and self.member.isLegacycaller():
|
||||||
# If it has an identifier, we can't deal with it yet
|
# 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:
|
if (optional or isMember) and forceOwningType:
|
||||||
typeDecl = "nsRefPtr<%s>"
|
typeDecl = "nsRefPtr<%s>"
|
||||||
else:
|
else:
|
||||||
typeDecl = "%s*"
|
typeDecl = "*%s"
|
||||||
else:
|
else:
|
||||||
if optional or isMember:
|
if optional or isMember:
|
||||||
if forceOwningType:
|
if forceOwningType:
|
||||||
|
@ -5560,9 +5489,9 @@ class CGNativeMember(ClassMethod):
|
||||||
else:
|
else:
|
||||||
typeDecl = "NonNull<%s>"
|
typeDecl = "NonNull<%s>"
|
||||||
else:
|
else:
|
||||||
typeDecl = "%s&"
|
typeDecl = "%s%s"
|
||||||
return ((typeDecl %
|
descriptor = self.descriptorProvider.getDescriptor(iface.identifier.name)
|
||||||
self.descriptorProvider.getDescriptor(iface.identifier.name).nativeType),
|
return (typeDecl % (descriptor.pointerType, descriptor.nativeType),
|
||||||
False, False)
|
False, False)
|
||||||
|
|
||||||
if type.isSpiderMonkeyInterface():
|
if type.isSpiderMonkeyInterface():
|
||||||
|
@ -5692,16 +5621,17 @@ class CGCallback(CGClass):
|
||||||
CGClass.__init__(self, name,
|
CGClass.__init__(self, name,
|
||||||
bases=[ClassBase(baseName)],
|
bases=[ClassBase(baseName)],
|
||||||
constructors=self.getConstructors(),
|
constructors=self.getConstructors(),
|
||||||
methods=realMethods+getters+setters)
|
methods=realMethods+getters+setters,
|
||||||
|
decorators="#[deriving(Eq,Clone)]")
|
||||||
|
|
||||||
def getConstructors(self):
|
def getConstructors(self):
|
||||||
return [ClassConstructor(
|
return [ClassConstructor(
|
||||||
[Argument("JSObject*", "aCallback")],
|
[Argument("*JSObject", "aCallback")],
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
visibility="public",
|
visibility="pub",
|
||||||
explicit=True,
|
explicit=False,
|
||||||
baseConstructors=[
|
baseConstructors=[
|
||||||
"%s(aCallback)" % self.baseName
|
"%s::new(aCallback)" % self.baseName
|
||||||
])]
|
])]
|
||||||
|
|
||||||
def getMethodImpls(self, method):
|
def getMethodImpls(self, method):
|
||||||
|
@ -5709,14 +5639,14 @@ class CGCallback(CGClass):
|
||||||
args = list(method.args)
|
args = list(method.args)
|
||||||
# Strip out the JSContext*/JSObject* args
|
# Strip out the JSContext*/JSObject* args
|
||||||
# that got added.
|
# that got added.
|
||||||
assert args[0].name == "cx" and args[0].argType == "JSContext*"
|
assert args[0].name == "cx" and args[0].argType == "*JSContext"
|
||||||
assert args[1].name == "aThisObj" and args[1].argType == "JS::Handle<JSObject*>"
|
assert args[1].name == "aThisObj" and args[1].argType == "*JSObject"
|
||||||
args = args[2:]
|
args = args[2:]
|
||||||
# Record the names of all the arguments, so we can use them when we call
|
# Record the names of all the arguments, so we can use them when we call
|
||||||
# the private method.
|
# the private method.
|
||||||
argnames = [arg.name for arg in args]
|
argnames = [arg.name for arg in args]
|
||||||
argnamesWithThis = ["s.GetContext()", "thisObjJS"] + argnames
|
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
|
# Now that we've recorded the argnames for our call to our private
|
||||||
# method, insert our optional argument for deciding whether the
|
# method, insert our optional argument for deciding whether the
|
||||||
# CallSetup should re-throw exceptions on aRv.
|
# CallSetup should re-throw exceptions on aRv.
|
||||||
|
@ -5724,63 +5654,52 @@ class CGCallback(CGClass):
|
||||||
"eReportExceptions"))
|
"eReportExceptions"))
|
||||||
# And now insert our template argument.
|
# And now insert our template argument.
|
||||||
argsWithoutThis = list(args)
|
argsWithoutThis = list(args)
|
||||||
args.insert(0, Argument("const T&", "thisObj"))
|
args.insert(0, Argument("@mut T", "thisObj"))
|
||||||
|
|
||||||
setupCall = ("CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
|
# And the self argument
|
||||||
"if (!s.GetContext()) {\n"
|
method.args.insert(0, Argument(None, "&self"))
|
||||||
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
args.insert(0, Argument(None, "&self"))
|
||||||
|
argsWithoutThis.insert(0, Argument(None, "&self"))
|
||||||
|
|
||||||
|
setupCall = ("let s = CallSetup::new(cx_for_dom_object(${cxProvider}), aExceptionHandling);\n"
|
||||||
|
"if s.GetContext().is_null() {\n"
|
||||||
" return${errorReturn};\n"
|
" return${errorReturn};\n"
|
||||||
"}\n")
|
"}\n")
|
||||||
|
|
||||||
bodyWithThis = string.Template(
|
bodyWithThis = string.Template(
|
||||||
setupCall+
|
setupCall+
|
||||||
"JS::Rooted<JSObject*> thisObjJS(s.GetContext(),\n"
|
"let thisObjJS = WrapCallThisObject(s.GetContext(), ptr::null() /*XXXjdm proper scope*/, thisObj);\n"
|
||||||
" WrapCallThisObject(s.GetContext(), CallbackPreserveColor(), thisObj));\n"
|
"if thisObjJS.is_null() {\n"
|
||||||
"if (!thisObjJS) {\n"
|
|
||||||
" aRv.Throw(NS_ERROR_FAILURE);\n"
|
|
||||||
" return${errorReturn};\n"
|
" return${errorReturn};\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"return ${methodName}(${callArgs});").substitute({
|
"return ${methodName}(${callArgs});").substitute({
|
||||||
"errorReturn" : method.getDefaultRetval(),
|
"errorReturn" : method.getDefaultRetval(),
|
||||||
"callArgs" : ", ".join(argnamesWithThis),
|
"callArgs" : ", ".join(argnamesWithThis),
|
||||||
"methodName": method.name,
|
"methodName": 'self.' + method.name,
|
||||||
|
"cxProvider": 'thisObj'
|
||||||
})
|
})
|
||||||
bodyWithoutThis = string.Template(
|
bodyWithoutThis = string.Template(
|
||||||
setupCall +
|
setupCall +
|
||||||
"return ${methodName}(${callArgs});").substitute({
|
"return ${methodName}(${callArgs});").substitute({
|
||||||
"errorReturn" : method.getDefaultRetval(),
|
"errorReturn" : method.getDefaultRetval(),
|
||||||
"callArgs" : ", ".join(argnamesWithoutThis),
|
"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,
|
bodyInHeader=True,
|
||||||
templateArgs=["typename T"],
|
templateArgs=["T: 'static+CallbackContainer+Reflectable"],
|
||||||
body=bodyWithThis),
|
body=bodyWithThis,
|
||||||
ClassMethod(method.name, method.returnType, argsWithoutThis,
|
visibility='pub'),
|
||||||
|
ClassMethod(method.name+'__', method.returnType, argsWithoutThis,
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
body=bodyWithoutThis),
|
body=bodyWithoutThis,
|
||||||
|
visibility='pub'),
|
||||||
method]
|
method]
|
||||||
|
|
||||||
def deps(self):
|
def deps(self):
|
||||||
return self._deps
|
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
|
# We're always fallible
|
||||||
def callbackGetterName(attr):
|
def callbackGetterName(attr):
|
||||||
return "Get" + MakeNativeName(attr.identifier.name)
|
return "Get" + MakeNativeName(attr.identifier.name)
|
||||||
|
@ -5799,7 +5718,7 @@ class CGCallbackFunction(CGCallback):
|
||||||
ClassConstructor(
|
ClassConstructor(
|
||||||
[Argument("CallbackFunction*", "aOther")],
|
[Argument("CallbackFunction*", "aOther")],
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
visibility="public",
|
visibility="pub",
|
||||||
explicit=True,
|
explicit=True,
|
||||||
baseConstructors=[
|
baseConstructors=[
|
||||||
"CallbackFunction(aOther)"
|
"CallbackFunction(aOther)"
|
||||||
|
@ -5865,7 +5784,7 @@ class CallbackMember(CGNativeMember):
|
||||||
self.needThisHandling = needThisHandling
|
self.needThisHandling = needThisHandling
|
||||||
# If needThisHandling, we generate ourselves as private and the caller
|
# If needThisHandling, we generate ourselves as private and the caller
|
||||||
# will handle generating public versions that handle the "this" stuff.
|
# 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
|
self.rethrowContentException = rethrowContentException
|
||||||
# We don't care, for callback codegen, whether our original member was
|
# We don't care, for callback codegen, whether our original member was
|
||||||
# a method or attribute or whatnot. Just always pass FakeMember()
|
# a method or attribute or whatnot. Just always pass FakeMember()
|
||||||
|
@ -5878,8 +5797,7 @@ class CallbackMember(CGNativeMember):
|
||||||
jsObjectsArePtr=True)
|
jsObjectsArePtr=True)
|
||||||
# We have to do all the generation of our body now, because
|
# We have to do all the generation of our body now, because
|
||||||
# the caller relies on us throwing if we can't manage it.
|
# the caller relies on us throwing if we can't manage it.
|
||||||
self.exceptionCode=("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
self.exceptionCode= "return Err(FailureUnknown);\n"
|
||||||
"return%s;" % self.getDefaultRetval())
|
|
||||||
self.body = self.getImpl()
|
self.body = self.getImpl()
|
||||||
|
|
||||||
def getImpl(self):
|
def getImpl(self):
|
||||||
|
@ -5894,11 +5812,7 @@ class CallbackMember(CGNativeMember):
|
||||||
if self.argCount > 0:
|
if self.argCount > 0:
|
||||||
replacements["argCount"] = self.argCountStr
|
replacements["argCount"] = self.argCountStr
|
||||||
replacements["argvDecl"] = string.Template(
|
replacements["argvDecl"] = string.Template(
|
||||||
"JS::AutoValueVector argv(cx);\n"
|
"let mut argv = vec::from_elem(${argCount}, JSVAL_VOID);\n"
|
||||||
"if (!argv.resize(${argCount})) {\n"
|
|
||||||
" aRv.Throw(NS_ERROR_OUT_OF_MEMORY);\n"
|
|
||||||
" return${errorReturn};\n"
|
|
||||||
"}\n"
|
|
||||||
).substitute(replacements)
|
).substitute(replacements)
|
||||||
else:
|
else:
|
||||||
# Avoid weird 0-sized arrays
|
# Avoid weird 0-sized arrays
|
||||||
|
@ -5929,13 +5843,13 @@ class CallbackMember(CGNativeMember):
|
||||||
isCallbackReturnValue = "JSImpl"
|
isCallbackReturnValue = "JSImpl"
|
||||||
else:
|
else:
|
||||||
isCallbackReturnValue = "Callback"
|
isCallbackReturnValue = "Callback"
|
||||||
convertType = instantiateJSToNativeConversion(
|
convertType = instantiateJSToNativeConversionTemplate(
|
||||||
getJSToNativeConversionInfo(self.retvalType,
|
getJSToNativeConversionTemplate(self.retvalType,
|
||||||
self.descriptorProvider,
|
self.descriptorProvider,
|
||||||
exceptionCode=self.exceptionCode,
|
exceptionCode=self.exceptionCode,
|
||||||
isCallbackReturnValue=isCallbackReturnValue,
|
isCallbackReturnValue=isCallbackReturnValue,
|
||||||
# XXXbz we should try to do better here
|
# XXXbz we should try to do better here
|
||||||
sourceDescription="return value"),
|
sourceDescription="return value"),
|
||||||
replacements)
|
replacements)
|
||||||
assignRetval = string.Template(
|
assignRetval = string.Template(
|
||||||
self.getRetvalInfo(self.retvalType,
|
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
|
# 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.
|
# also so that we can just "break;" for our successCode.
|
||||||
argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
|
argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
|
||||||
pre="do {\n",
|
pre="loop {\n",
|
||||||
post="\n} while (0);")
|
post="\nbreak;}\n")
|
||||||
for c in argConversions]
|
for c in argConversions]
|
||||||
if self.argCount > 0:
|
if self.argCount > 0:
|
||||||
argConversions.insert(0, self.getArgcDecl())
|
argConversions.insert(0, self.getArgcDecl())
|
||||||
|
@ -5989,10 +5903,11 @@ class CallbackMember(CGNativeMember):
|
||||||
'successCode' : "continue;" if arg.variadic else "break;",
|
'successCode' : "continue;" if arg.variadic else "break;",
|
||||||
'jsvalRef' : "argv.handleAt(%s)" % jsvalIndex,
|
'jsvalRef' : "argv.handleAt(%s)" % jsvalIndex,
|
||||||
'jsvalHandle' : "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',
|
# XXXbz we don't have anything better to use for 'obj',
|
||||||
# really... It's OK to use CallbackPreserveColor because
|
# really... It's OK to use CallbackPreserveColor because
|
||||||
# CallSetup already handled the unmark-gray bits for us.
|
# CallSetup already handled the unmark-gray bits for us.
|
||||||
'obj' : 'CallbackPreserveColor()',
|
'obj' : 'ptr::null() /*XXXjdm proper scope*/', #XXXjdm 'CallbackPreserveColor()',
|
||||||
'returnsNewObject': False,
|
'returnsNewObject': False,
|
||||||
'exceptionCode' : self.exceptionCode
|
'exceptionCode' : self.exceptionCode
|
||||||
})
|
})
|
||||||
|
@ -6033,8 +5948,8 @@ class CallbackMember(CGNativeMember):
|
||||||
return args
|
return args
|
||||||
# We want to allow the caller to pass in a "this" object, as
|
# We want to allow the caller to pass in a "this" object, as
|
||||||
# well as a JSContext.
|
# well as a JSContext.
|
||||||
return [Argument("JSContext*", "cx"),
|
return [Argument("*JSContext", "cx"),
|
||||||
Argument("JS::Handle<JSObject*>", "aThisObj")] + args
|
Argument("*JSObject", "aThisObj")] + args
|
||||||
|
|
||||||
def getCallSetup(self):
|
def getCallSetup(self):
|
||||||
if self.needThisHandling:
|
if self.needThisHandling:
|
||||||
|
@ -6052,7 +5967,6 @@ class CallbackMember(CGNativeMember):
|
||||||
"${callSetup}\n"
|
"${callSetup}\n"
|
||||||
"JSContext* cx = s.GetContext();\n"
|
"JSContext* cx = s.GetContext();\n"
|
||||||
"if (!cx) {\n"
|
"if (!cx) {\n"
|
||||||
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
|
||||||
" return${errorReturn};\n"
|
" return${errorReturn};\n"
|
||||||
"}\n").substitute({
|
"}\n").substitute({
|
||||||
"callSetup": callSetup,
|
"callSetup": callSetup,
|
||||||
|
@ -6060,7 +5974,7 @@ class CallbackMember(CGNativeMember):
|
||||||
})
|
})
|
||||||
|
|
||||||
def getArgcDecl(self):
|
def getArgcDecl(self):
|
||||||
return CGGeneric("unsigned argc = %s;" % self.argCountStr);
|
return CGGeneric("let argc = %su32;" % self.argCountStr);
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ensureASCIIName(idlObject):
|
def ensureASCIIName(idlObject):
|
||||||
|
@ -6082,7 +5996,7 @@ class CallbackMethod(CallbackMember):
|
||||||
CallbackMember.__init__(self, sig, name, descriptorProvider,
|
CallbackMember.__init__(self, sig, name, descriptorProvider,
|
||||||
needThisHandling, rethrowContentException)
|
needThisHandling, rethrowContentException)
|
||||||
def getRvalDecl(self):
|
def getRvalDecl(self):
|
||||||
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
|
return "let mut rval = JSVAL_VOID;\n"
|
||||||
|
|
||||||
def getCall(self):
|
def getCall(self):
|
||||||
replacements = {
|
replacements = {
|
||||||
|
@ -6091,15 +6005,14 @@ class CallbackMethod(CallbackMember):
|
||||||
"getCallable": self.getCallableDecl()
|
"getCallable": self.getCallableDecl()
|
||||||
}
|
}
|
||||||
if self.argCount > 0:
|
if self.argCount > 0:
|
||||||
replacements["argv"] = "argv.begin()"
|
replacements["argv"] = "&argv[0]"
|
||||||
replacements["argc"] = "argc"
|
replacements["argc"] = "argc"
|
||||||
else:
|
else:
|
||||||
replacements["argv"] = "nullptr"
|
replacements["argv"] = "nullptr"
|
||||||
replacements["argc"] = "0"
|
replacements["argc"] = "0"
|
||||||
return string.Template("${getCallable}"
|
return string.Template("${getCallable}"
|
||||||
"if (!JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
|
"if unsafe { JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
|
||||||
" ${argc}, ${argv}, rval.address())) {\n"
|
" ${argc}, ${argv}, &rval) == 0 } {\n"
|
||||||
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
|
||||||
" return${errorReturn};\n"
|
" return${errorReturn};\n"
|
||||||
"}\n").substitute(replacements)
|
"}\n").substitute(replacements)
|
||||||
|
|
||||||
|
@ -6125,11 +6038,11 @@ class CallbackOperationBase(CallbackMethod):
|
||||||
|
|
||||||
def getThisObj(self):
|
def getThisObj(self):
|
||||||
if not self.singleOperation:
|
if not self.singleOperation:
|
||||||
return "mCallback"
|
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 "isCallable ? aThisObj.get() : mCallback"
|
return "if isCallable { aThisObj } else { self.parent.callback }"
|
||||||
|
|
||||||
def getCallableDecl(self):
|
def getCallableDecl(self):
|
||||||
replacements = {
|
replacements = {
|
||||||
|
@ -6137,17 +6050,16 @@ class CallbackOperationBase(CallbackMethod):
|
||||||
"methodName": self.methodName
|
"methodName": self.methodName
|
||||||
}
|
}
|
||||||
getCallableFromProp = string.Template(
|
getCallableFromProp = string.Template(
|
||||||
'if (!GetCallableProperty(cx, "${methodName}", &callable)) {\n'
|
'if "${methodName}".to_c_str().with_ref(|name| !self.parent.GetCallableProperty(cx, name, &mut callable)) {\n'
|
||||||
' aRv.Throw(NS_ERROR_UNEXPECTED);\n'
|
|
||||||
' return${errorReturn};\n'
|
' return${errorReturn};\n'
|
||||||
'}\n').substitute(replacements)
|
'}\n').substitute(replacements)
|
||||||
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 (
|
||||||
'bool isCallable = JS_ObjectIsCallable(cx, mCallback);\n'
|
'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback) != 0 };\n'
|
||||||
'JS::Rooted<JS::Value> callable(cx);\n'
|
'let mut callable = JSVAL_VOID;\n'
|
||||||
'if (isCallable) {\n'
|
'if isCallable {\n'
|
||||||
' callable = JS::ObjectValue(*mCallback);\n'
|
' callable = unsafe { RUST_OBJECT_TO_JSVAL(self.parent.callback) };\n'
|
||||||
'} else {\n'
|
'} else {\n'
|
||||||
'%s'
|
'%s'
|
||||||
'}\n' % CGIndenter(CGGeneric(getCallableFromProp)).define())
|
'}\n' % CGIndenter(CGGeneric(getCallableFromProp)).define())
|
||||||
|
@ -6304,7 +6216,12 @@ class GlobalGenRoots():
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def InterfaceTypes(config):
|
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 = CGList([CGGeneric(declare="pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors])
|
||||||
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
|
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
|
||||||
return curr
|
return curr
|
||||||
|
|
|
@ -58,8 +58,8 @@ interface Document : Node {
|
||||||
[Throws]
|
[Throws]
|
||||||
Node adoptNode(Node node);*/
|
Node adoptNode(Node node);*/
|
||||||
|
|
||||||
// [Creator, Throws]
|
[Creator, Throws]
|
||||||
// Event createEvent(DOMString interface_);
|
Event createEvent(DOMString interface_);
|
||||||
|
|
||||||
/*[Creator, Throws]
|
/*[Creator, Throws]
|
||||||
Range createRange();*/
|
Range createRange();*/
|
||||||
|
|
|
@ -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);
|
||||||
|
};
|
||||||
|
|
|
@ -11,4 +11,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface EventTarget {
|
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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
interface URI;
|
interface URI;
|
||||||
interface UserDataHandler;*/
|
interface UserDataHandler;*/
|
||||||
|
|
||||||
interface Node /*: EventTarget*/ {
|
interface Node : EventTarget {
|
||||||
const unsigned short ELEMENT_NODE = 1;
|
const unsigned short ELEMENT_NODE = 1;
|
||||||
const unsigned short ATTRIBUTE_NODE = 2; // historical
|
const unsigned short ATTRIBUTE_NODE = 2; // historical
|
||||||
const unsigned short TEXT_NODE = 3;
|
const unsigned short TEXT_NODE = 3;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[NamedPropertiesObject]
|
[NamedPropertiesObject]
|
||||||
/*sealed*/ interface Window /*: EventTarget*/ {
|
/*sealed*/ interface Window : EventTarget {
|
||||||
// the current browsing context
|
// the current browsing context
|
||||||
/*[Unforgeable] readonly attribute WindowProxy window;
|
/*[Unforgeable] readonly attribute WindowProxy window;
|
||||||
[Replaceable] readonly attribute WindowProxy self;*/
|
[Replaceable] readonly attribute WindowProxy self;*/
|
||||||
|
|
|
@ -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.parent_node, "parent");
|
||||||
trace_node(tracer, self.first_child, "first child");
|
trace_node(tracer, self.first_child, "first child");
|
||||||
trace_node(tracer, self.last_child, "last child");
|
trace_node(tracer, self.last_child, "last child");
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::PrototypeList;
|
use dom::bindings::codegen::PrototypeList;
|
||||||
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
|
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
|
||||||
use dom::window;
|
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
|
use dom::window;
|
||||||
|
|
||||||
use std::libc::c_uint;
|
use std::libc::c_uint;
|
||||||
use std::cast;
|
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_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction, JS_GetGlobalObject};
|
||||||
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
||||||
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength};
|
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_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject};
|
||||||
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
||||||
use js::jsapi::{JS_NewUCStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
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::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
||||||
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JS_NewGlobalObject, JS_InitStandardClasses};
|
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JS_NewGlobalObject, JS_InitStandardClasses};
|
||||||
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
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_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER};
|
||||||
use js::{JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE};
|
use js::{JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE};
|
||||||
use js::{JS_THIS_OBJECT, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY};
|
use js::{JS_THIS_OBJECT, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY};
|
||||||
|
@ -819,6 +820,13 @@ pub fn HasPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid) -> boo
|
||||||
return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found;
|
return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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]
|
#[fixed_stack_segment]
|
||||||
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -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
|
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
|
||||||
/// for details.
|
/// for details.
|
||||||
pub fn is_valid_element_name(name: &str) -> bool {
|
pub fn is_valid_element_name(name: &str) -> bool {
|
||||||
|
|
|
@ -10,6 +10,7 @@ use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable, n
|
||||||
use dom::documentfragment::DocumentFragment;
|
use dom::documentfragment::DocumentFragment;
|
||||||
use dom::element::{Element};
|
use dom::element::{Element};
|
||||||
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
||||||
|
use dom::event::Event;
|
||||||
use dom::htmlcollection::HTMLCollection;
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::htmldocument::HTMLDocument;
|
use dom::htmldocument::HTMLDocument;
|
||||||
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
|
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
|
||||||
|
@ -255,6 +256,11 @@ impl Document {
|
||||||
Comment::new(null_str_as_word_null(data), abstract_self)
|
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 {
|
pub fn Title(&self, _: AbstractDocument) -> DOMString {
|
||||||
let mut title = ~"";
|
let mut title = ~"";
|
||||||
match self.doctype {
|
match self.doctype {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dom::eventtarget::EventTarget;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::bindings::codegen::EventBinding;
|
use dom::bindings::codegen::EventBinding;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
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 geom::point::Point2D;
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
|
@ -23,7 +23,7 @@ pub enum Event_ {
|
||||||
|
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
type_: DOMString,
|
type_: ~str,
|
||||||
default_prevented: bool,
|
default_prevented: bool,
|
||||||
cancelable: bool,
|
cancelable: bool,
|
||||||
bubbles: bool,
|
bubbles: bool,
|
||||||
|
@ -34,7 +34,7 @@ impl Event {
|
||||||
pub fn new_inherited(type_: &DOMString) -> Event {
|
pub fn new_inherited(type_: &DOMString) -> Event {
|
||||||
Event {
|
Event {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
type_: (*type_).clone(),
|
type_: null_str_as_word_null(type_),
|
||||||
default_prevented: false,
|
default_prevented: false,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
|
@ -51,7 +51,7 @@ impl Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Type(&self) -> DOMString {
|
pub fn Type(&self) -> DOMString {
|
||||||
self.type_.clone()
|
Some(self.type_.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetTarget(&self) -> Option<@mut EventTarget> {
|
pub fn GetTarget(&self) -> Option<@mut EventTarget> {
|
||||||
|
@ -92,7 +92,7 @@ impl Event {
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
bubbles: bool,
|
bubbles: bool,
|
||||||
cancelable: bool) -> ErrorResult {
|
cancelable: bool) -> ErrorResult {
|
||||||
self.type_ = (*type_).clone();
|
self.type_ = type_.to_str();
|
||||||
self.cancelable = cancelable;
|
self.cancelable = cancelable;
|
||||||
self.bubbles = bubbles;
|
self.bubbles = bubbles;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -2,26 +2,96 @@
|
||||||
* 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::eReportExceptions;
|
||||||
use dom::bindings::codegen::EventTargetBinding;
|
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 script_task::page_from_context;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
|
use std::hashmap::HashMap;
|
||||||
|
|
||||||
pub struct EventTarget {
|
pub struct EventTarget {
|
||||||
reflector_: Reflector
|
reflector_: Reflector,
|
||||||
|
capturing_handlers: HashMap<~str, ~[EventListener]>,
|
||||||
|
bubbling_handlers: HashMap<~str, ~[EventListener]>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventTarget {
|
impl EventTarget {
|
||||||
pub fn new() -> ~EventTarget {
|
pub fn new() -> EventTarget {
|
||||||
~EventTarget {
|
EventTarget {
|
||||||
reflector_: Reflector::new()
|
reflector_: Reflector::new(),
|
||||||
|
capturing_handlers: HashMap::new(),
|
||||||
|
bubbling_handlers: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
self.wrap_object_shared(cx, scope);
|
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 {
|
impl Reflectable for EventTarget {
|
||||||
|
|
|
@ -12,6 +12,7 @@ use dom::document::{AbstractDocument, DocumentTypeId};
|
||||||
use dom::documenttype::DocumentType;
|
use dom::documenttype::DocumentType;
|
||||||
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId};
|
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId};
|
||||||
use dom::element::{HTMLStyleElementTypeId};
|
use dom::element::{HTMLStyleElementTypeId};
|
||||||
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::nodelist::{NodeList};
|
use dom::nodelist::{NodeList};
|
||||||
use dom::htmlimageelement::HTMLImageElement;
|
use dom::htmlimageelement::HTMLImageElement;
|
||||||
use dom::htmliframeelement::HTMLIFrameElement;
|
use dom::htmliframeelement::HTMLIFrameElement;
|
||||||
|
@ -63,7 +64,7 @@ pub struct AbstractNodeChildrenIterator<View> {
|
||||||
/// `LayoutData`.
|
/// `LayoutData`.
|
||||||
pub struct Node<View> {
|
pub struct Node<View> {
|
||||||
/// The JavaScript reflector for this node.
|
/// The JavaScript reflector for this node.
|
||||||
reflector_: Reflector,
|
eventtarget: EventTarget,
|
||||||
|
|
||||||
/// The type of node that this is.
|
/// The type of node that this is.
|
||||||
type_id: NodeTypeId,
|
type_id: NodeTypeId,
|
||||||
|
@ -521,7 +522,7 @@ impl Node<ScriptView> {
|
||||||
|
|
||||||
fn new_(type_id: NodeTypeId, doc: Option<AbstractDocument>) -> Node<ScriptView> {
|
fn new_(type_id: NodeTypeId, doc: Option<AbstractDocument>) -> Node<ScriptView> {
|
||||||
Node {
|
Node {
|
||||||
reflector_: Reflector::new(),
|
eventtarget: EventTarget::new(),
|
||||||
type_id: type_id,
|
type_id: type_id,
|
||||||
|
|
||||||
abstract: None,
|
abstract: None,
|
||||||
|
@ -961,11 +962,11 @@ impl Node<ScriptView> {
|
||||||
|
|
||||||
impl Reflectable for Node<ScriptView> {
|
impl Reflectable for Node<ScriptView> {
|
||||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
&self.reflector_
|
self.eventtarget.reflector()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mut_reflector<'a>(&'a mut self) -> &'a mut 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 {
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use dom::bindings::codegen::WindowBinding;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::bindings::utils::{DOMString, null_str_as_empty, Traceable};
|
use dom::bindings::utils::{DOMString, null_str_as_empty, Traceable};
|
||||||
use dom::document::AbstractDocument;
|
use dom::document::AbstractDocument;
|
||||||
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use dom::navigator::Navigator;
|
use dom::navigator::Navigator;
|
||||||
|
|
||||||
|
@ -37,10 +38,10 @@ pub enum TimerControlMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
eventtarget: EventTarget,
|
||||||
page: @mut Page,
|
page: @mut Page,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
compositor: @ScriptListener,
|
compositor: @ScriptListener,
|
||||||
reflector_: Reflector,
|
|
||||||
timer_chan: SharedChan<TimerControlMsg>,
|
timer_chan: SharedChan<TimerControlMsg>,
|
||||||
navigator: Option<@mut Navigator>,
|
navigator: Option<@mut Navigator>,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
|
@ -140,11 +141,11 @@ impl Window {
|
||||||
|
|
||||||
impl Reflectable for Window {
|
impl Reflectable for Window {
|
||||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
&self.reflector_
|
self.eventtarget.reflector()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mut_reflector<'a>(&'a mut self) -> &'a mut 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 {
|
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||||
|
@ -204,10 +205,10 @@ impl Window {
|
||||||
image_cache_task: ImageCacheTask)
|
image_cache_task: ImageCacheTask)
|
||||||
-> @mut Window {
|
-> @mut Window {
|
||||||
let win = @mut Window {
|
let win = @mut Window {
|
||||||
|
eventtarget: EventTarget::new(),
|
||||||
page: page,
|
page: page,
|
||||||
script_chan: script_chan.clone(),
|
script_chan: script_chan.clone(),
|
||||||
compositor: compositor,
|
compositor: compositor,
|
||||||
reflector_: Reflector::new(),
|
|
||||||
timer_chan: {
|
timer_chan: {
|
||||||
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
|
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
|
||||||
let id = page.id.clone();
|
let id = page.id.clone();
|
||||||
|
|
|
@ -28,6 +28,7 @@ pub mod dom {
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod callback;
|
||||||
pub mod conversions;
|
pub mod conversions;
|
||||||
pub mod proxyhandler;
|
pub mod proxyhandler;
|
||||||
pub mod codegen {
|
pub mod codegen {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1df26877d82d9722785de91ff59ab069a5acc180
|
Subproject commit 566c2af971abaa5e8c51b59fa400a7e07835b257
|
17
src/test/html/content/test_event_listener.html
Normal file
17
src/test/html/content/test_event_listener.html
Normal file
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue