auto merge of #3941 : mukilan/servo/timeout-arguments, r=Ms2ger

This commit is contained in:
bors-servo 2014-11-15 11:09:32 -07:00
commit 43b452f3b8
15 changed files with 186 additions and 376 deletions

View file

@ -601,11 +601,13 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
if descriptor.interface.isCallback():
name = descriptor.nativeType
declType = CGGeneric("Option<%s>" % name);
conversion = ("Some(%s::new((${val}).to_object()))" % name)
declType = CGGeneric(name)
template = "%s::new((${val}).to_object())" % name
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=">")
template = wrapObjectTemplate("Some(%s)" % template, isDefinitelyObject, type,
failureCode)
template = wrapObjectTemplate(conversion, isDefinitelyObject, type,
failureCode)
return handleOptional(template, declType, handleDefaultNull("None"))
if isMember:
@ -983,15 +985,14 @@ class CGArgumentConverter(CGThing):
needsRooting)
seqType = CGTemplatedType("Vec", declType)
variadicConversion = string.Template(
"{\n"
" let mut vector: ${seqType} = Vec::with_capacity((${argc} - ${index}) as uint);\n"
" for variadicArg in range(${index}, ${argc}) {\n"
"let mut vector: ${seqType} = Vec::with_capacity((${argc} - ${index}) as uint);\n"
"for variadicArg in range(${index}, ${argc}) {\n"
"${inner}\n"
" vector.push(slot);\n"
" }\n"
" vector\n"
"}"
"}\n"
"vector"
).substitute({
"index": index,
"argc": argc,
@ -999,6 +1000,10 @@ class CGArgumentConverter(CGThing):
"inner": CGIndenter(innerConverter, 4).define(),
})
variadicConversion = CGIfElseWrapper(condition,
CGGeneric(variadicConversion),
CGGeneric("Vec::new()")).define()
self.converter = instantiateJSToNativeConversionTemplate(
variadicConversion, replacementVariables, seqType, "arg%d" % index,
False)
@ -3993,44 +3998,14 @@ class CGInterfaceTrait(CGThing):
def __init__(self, descriptor):
CGThing.__init__(self)
def argument_type(ty, optional=False, defaultValue=None, variadic=False):
_, _, declType, _ = getJSToNativeConversionTemplate(
ty, descriptor, isArgument=True)
if variadic:
declType = CGWrapper(declType, pre="Vec<", post=">")
elif optional and not defaultValue:
declType = CGWrapper(declType, pre="Option<", post=">")
if ty.isDictionary():
declType = CGWrapper(declType, pre="&")
return declType.define()
def attribute_arguments(needCx, argument=None):
if needCx:
yield "cx", "*mut JSContext"
if argument:
yield "value", argument_type(argument)
yield "value", argument_type(descriptor, argument)
def method_arguments(returnType, arguments, trailing=None):
if needCx(returnType, arguments, True):
yield "cx", "*mut JSContext"
for argument in arguments:
ty = argument_type(argument.type, argument.optional,
argument.defaultValue, argument.variadic)
yield CGDictionary.makeMemberName(argument.identifier.name), ty
if trailing:
yield trailing
def return_type(rettype, infallible):
result = getRetvalDeclarationForType(rettype, descriptor)
if not infallible:
result = CGWrapper(result, pre="Fallible<", post=">")
return result.define()
def members():
for m in descriptor.interface.members:
@ -4039,14 +4014,14 @@ class CGInterfaceTrait(CGThing):
name = CGSpecializedMethod.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m)
for idx, (rettype, arguments) in enumerate(m.signatures()):
arguments = method_arguments(rettype, arguments)
rettype = return_type(rettype, infallible)
arguments = method_arguments(descriptor, rettype, arguments)
rettype = return_type(descriptor, rettype, infallible)
yield name + ('_' * idx), arguments, rettype
elif m.isAttr() and not m.isStatic():
name = CGSpecializedGetter.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True)
needCx = typeNeedsCx(m.type)
yield name, attribute_arguments(needCx), return_type(m.type, infallible)
yield name, attribute_arguments(needCx), return_type(descriptor, m.type, infallible)
if not m.readonly:
name = CGSpecializedSetter.makeNativeName(descriptor, m)
@ -4067,10 +4042,10 @@ class CGInterfaceTrait(CGThing):
infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
if operation.isGetter():
arguments = method_arguments(rettype, arguments, ("found", "&mut bool"))
arguments = method_arguments(descriptor, rettype, arguments, trailing=("found", "&mut bool"))
else:
arguments = method_arguments(rettype, arguments)
rettype = return_type(rettype, infallible)
arguments = method_arguments(descriptor, rettype, arguments)
rettype = return_type(descriptor, rettype, infallible)
yield name, arguments, rettype
def fmt(arguments):
@ -4573,6 +4548,38 @@ class CGBindingRoot(CGThing):
def define(self):
return stripTrailingWhitespace(self.root.define())
def argument_type(descriptorProvdider, ty, optional=False, defaultValue=None, variadic=False):
_, _, declType, _ = getJSToNativeConversionTemplate(
ty, descriptorProvdider, isArgument=True)
if variadic:
declType = CGWrapper(declType, pre="Vec<", post=">")
elif optional and not defaultValue:
declType = CGWrapper(declType, pre="Option<", post=">")
if ty.isDictionary():
declType = CGWrapper(declType, pre="&")
return declType.define()
def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None):
if needCx(returnType, arguments, passJSBits):
yield "cx", "*mut JSContext"
for argument in arguments:
ty = argument_type(descriptorProvider, argument.type, argument.optional,
argument.defaultValue, argument.variadic)
yield CGDictionary.makeMemberName(argument.identifier.name), ty
if trailing:
yield trailing
def return_type(descriptorProvider, rettype, infallible):
result = getRetvalDeclarationForType(rettype, descriptorProvider)
if not infallible:
result = CGWrapper(result, pre="Fallible<", post=">")
return result.define()
class CGNativeMember(ClassMethod):
def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
@ -4592,7 +4599,7 @@ class CGNativeMember(ClassMethod):
self.variadicIsSequence = variadicIsSequence
breakAfterSelf = "\n" if breakAfter else ""
ClassMethod.__init__(self, name,
self.getReturnType(signature[0], False),
self.getReturnType(signature[0]),
self.getArgs(signature[0], signature[1]),
static=member.isStatic(),
# Mark our getters, which are attrs that
@ -4603,274 +4610,16 @@ class CGNativeMember(ClassMethod):
breakAfterSelf=breakAfterSelf,
visibility=visibility)
def getReturnType(self, type, isMember):
return self.getRetvalInfo(type, isMember)[0]
def getRetvalInfo(self, type, isMember):
"""
Returns a tuple:
The first element is the type declaration for the retval
The second element is a template for actually returning a value stored in
"${declName}". This means actually returning it if
we're not outparam, else assigning to the "retval" outparam. If
isMember is true, this can be None, since in that case the caller will
never examine this value.
"""
if type.isVoid():
typeDecl, template = "", ""
elif type.isPrimitive() and type.tag() in builtinNames:
result = CGGeneric(builtinNames[type.tag()])
if type.nullable():
raise TypeError("Nullable primitives are not supported here.")
typeDecl, template = result.define(), "return Ok(${declName});"
elif type.isDOMString():
if isMember:
# No need for a third element in the isMember case
typeDecl, template = "nsString", None
# Outparam
else:
typeDecl, template = "void", "retval = ${declName};"
elif type.isByteString():
if isMember:
# No need for a third element in the isMember case
typeDecl, template = "nsCString", None
# Outparam
typeDecl, template = "void", "retval = ${declName};"
elif type.isEnum():
enumName = type.unroll().inner.identifier.name
if type.nullable():
enumName = CGTemplatedType("Nullable",
CGGeneric(enumName)).define()
typeDecl, template = enumName, "return ${declName};"
elif type.isGeckoInterface():
iface = type.unroll().inner;
nativeType = self.descriptorProvider.getDescriptor(
iface.identifier.name).nativeType
# Now trim off unnecessary namespaces
nativeType = nativeType.split("::")
if nativeType[0] == "mozilla":
nativeType.pop(0)
if nativeType[0] == "dom":
nativeType.pop(0)
result = CGWrapper(CGGeneric("::".join(nativeType)), post="*")
# 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.
typeDecl, template = result.define(), "return ${declName}.forget();"
elif type.isCallback():
typeDecl, template = \
("already_AddRefed<%s>" % type.unroll().identifier.name,
"return ${declName}.forget();")
elif type.isAny():
typeDecl, template = "JSVal", "return Ok(${declName});"
elif type.isObject():
typeDecl, template = "JSObject*", "return ${declName};"
elif type.isSpiderMonkeyInterface():
if type.nullable():
returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
else:
returnCode = "return ${declName}.Obj();"
typeDecl, template = "JSObject*", 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...
assert not isMember
# Outparam.
if type.nullable():
returnCode = ("if (${declName}.IsNull()) {\n"
" retval.SetNull();\n"
"} else {\n"
" retval.SetValue().SwapElements(${declName}.Value());\n"
"}")
else:
returnCode = "retval.SwapElements(${declName});"
typeDecl, template = "void", returnCode
elif type.isDate():
result = CGGeneric("Date")
if type.nullable():
result = CGTemplatedType("Nullable", result)
typeDecl, template = 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 template:
template = "return Ok(());"
return typeDecl, template
def getReturnType(self, type):
infallible = 'infallible' in self.extendedAttrs
typeDecl = return_type(self.descriptorProvider, type, infallible)
return typeDecl
def getArgs(self, returnType, argList):
args = [self.getArg(arg) for arg in argList]
# Now the outparams
if returnType.isDOMString():
args.append(Argument("nsString&", "retval"))
if returnType.isByteString():
args.append(Argument("nsCString&", "retval"))
elif returnType.isSequence():
nullable = returnType.nullable()
if nullable:
returnType = returnType.inner
# And now the actual underlying type
elementDecl = self.getReturnType(returnType.inner, True)
type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
if nullable:
type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "retval"))
# The legacycaller thisval
if self.member.isMethod() and self.member.isLegacycaller():
# If it has an identifier, we can't deal with it yet
assert self.member.isIdentifierLess()
args.insert(0, Argument("JS::Value", "aThisVal"))
# And jscontext bits.
if needCx(returnType, argList, self.passJSBitsAsNeeded):
args.insert(0, Argument("JSContext*", "cx"))
# And if we're static, a global
if self.member.isStatic():
args.insert(0, Argument("const GlobalObject&", "global"))
return args
def doGetArgType(self, type, optional, isMember):
"""
The main work of getArgType. Returns a string type decl, whether this
is a const ref, as well as whether the type should be wrapped in
Nullable as needed.
isMember can be false or one of the strings "Sequence" or "Variadic"
"""
if type.isArray():
raise TypeError("Can't handle array arguments yet")
if type.isSequence():
nullable = type.nullable()
if nullable:
type = type.inner
elementType = type.inner
argType = self.getArgType(elementType, False, "Sequence")[0]
decl = CGTemplatedType("Sequence", argType)
return decl.define(), True, True
if type.isUnion():
return union_native_type(type), False, True
if type.isGeckoInterface() and not type.isCallbackInterface():
iface = type.unroll().inner
argIsPointer = type.nullable()
forceOwningType = iface.isCallback() or isMember
if argIsPointer:
if (optional or isMember) and forceOwningType:
typeDecl = "nsRefPtr<%s>"
else:
typeDecl = "*%s"
else:
if optional or isMember:
if forceOwningType:
typeDecl = "OwningNonNull<%s>"
else:
typeDecl = "NonNull<%s>"
else:
typeDecl = "%s"
descriptor = self.descriptorProvider.getDescriptor(iface.identifier.name)
return (typeDecl % descriptor.argumentType,
False, False)
if type.isSpiderMonkeyInterface():
if self.jsObjectsArePtr:
return "JSObject*", False, False
return type.name, True, True
if type.isDOMString():
declType = "DOMString"
return declType, True, False
if type.isByteString():
declType = "nsCString"
return declType, True, False
if type.isEnum():
return type.unroll().inner.identifier.name, False, True
if type.isCallback() or type.isCallbackInterface():
forceOwningType = optional or isMember
if type.nullable():
if forceOwningType:
declType = "nsRefPtr<%s>"
else:
declType = "%s*"
else:
if forceOwningType:
declType = "OwningNonNull<%s>"
else:
declType = "%s&"
if type.isCallback():
name = type.unroll().identifier.name
else:
name = type.unroll().inner.identifier.name
return declType % name, False, False
if type.isAny():
# Don't do the rooting stuff for variadics for now
if isMember:
declType = "JS::Value"
else:
declType = "JSVal"
return declType, False, False
if type.isObject():
if isMember:
declType = "JSObject*"
else:
declType = "JS::Handle<JSObject*>"
return declType, False, False
if type.isDictionary():
typeName = CGDictionary.makeDictionaryName(type.inner)
return typeName, True, True
if type.isDate():
return "Date", False, True
assert type.isPrimitive()
return builtinNames[type.tag()], False, True
def getArgType(self, type, optional, isMember):
"""
Get the type of an argument declaration. Returns the type CGThing, and
whether this should be a const ref.
isMember can be False, "Sequence", or "Variadic"
"""
(decl, ref, handleNullable) = self.doGetArgType(type, optional,
isMember)
decl = CGGeneric(decl)
if handleNullable and type.nullable():
decl = CGTemplatedType("Nullable", decl)
if isMember == "Variadic":
arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
decl = CGTemplatedType(arrayType, decl)
elif optional:
# Note: All variadic args claim to be optional, but we can just use
# empty arrays to represent them not being present.
decl = CGTemplatedType("Option", decl)
return decl
def getArg(self, arg):
"""
Get the full argument declaration for an argument
"""
decl = self.getArgType(arg.type,
arg.optional and not arg.defaultValue,
"Variadic" if arg.variadic else False)
return Argument(decl.define(), arg.identifier.name)
return [Argument(arg[1], arg[0]) for arg in method_arguments(self.descriptorProvider,
returnType,
argList,
self.passJSBitsAsNeeded)]
class CGCallback(CGClass):
def __init__(self, idlObject, descriptorProvider, baseName, methods,
@ -5052,8 +4801,8 @@ class CallbackMember(CGNativeMember):
lastArg = args[self.argCount-1]
if lastArg.variadic:
self.argCountStr = (
"(%d - 1) + %s.Length()" % (self.argCount,
lastArg.identifier.name))
"(%d - 1) + %s.len()" % (self.argCount,
lastArg.identifier.name))
else:
self.argCountStr = "%d" % self.argCount
self.needThisHandling = needThisHandling
@ -5111,7 +4860,6 @@ class CallbackMember(CGNativeMember):
def getResultConversion(self):
replacements = {
"val": "rval",
"declName": "rvalDecl",
}
template, _, declType, needsRooting = getJSToNativeConversionTemplate(
@ -5125,10 +4873,12 @@ class CallbackMember(CGNativeMember):
convertType = instantiateJSToNativeConversionTemplate(
template, replacements, declType, "rvalDecl", needsRooting)
assignRetval = string.Template(
self.getRetvalInfo(self.retvalType,
False)[1]).substitute(replacements)
return convertType.define() + "\n" + assignRetval + "\n"
if self.retvalType is None or self.retvalType.isVoid():
retval = "()"
else:
retval = "rvalDecl"
return "%s\nOk(%s)\n" % (convertType.define(), retval)
def getArgConversions(self):
# Just reget the arglist from self.originalSig, because our superclasses
@ -5139,12 +4889,7 @@ class CallbackMember(CGNativeMember):
# Do them back to front, so our argc modifications will work
# correctly, because we examine trailing arguments first.
argConversions.reverse();
# 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="loop {\n",
post="\nbreak;}\n")
for c in argConversions]
argConversions = [CGGeneric(c) for c in argConversions]
if self.argCount > 0:
argConversions.insert(0, self.getArgcDecl())
# And slap them together.
@ -5163,13 +4908,13 @@ class CallbackMember(CGNativeMember):
conversion = wrapForType("argv[%s]" % jsvalIndex,
result=argval,
successCode="continue;" if arg.variadic else "break;")
successCode="")
if arg.variadic:
conversion = string.Template(
"for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {\n" +
"for idx in range(0, ${arg}.len()) {\n" +
CGIndenter(CGGeneric(conversion)).define() + "\n"
"}\n"
"break;").substitute({ "arg": arg.identifier.name })
).substitute({ "arg": arg.identifier.name })
elif arg.optional and not arg.defaultValue:
conversion = (
CGIfWrapper(CGGeneric(conversion),
@ -5220,7 +4965,7 @@ class CallbackMember(CGNativeMember):
})
def getArgcDecl(self):
return CGGeneric("let mut argc = %su32;" % self.argCountStr);
return CGGeneric("let mut argc = %s as u32;" % self.argCountStr);
@staticmethod
def ensureASCIIName(idlObject):

View file

@ -146,7 +146,7 @@ impl DedicatedWorkerGlobalScope {
Worker::handle_release(addr)
},
Ok(FireTimerMsg(FromWorker, timer_id)) => {
scope.handle_fire_timer(timer_id, js_context.ptr);
scope.handle_fire_timer(timer_id);
}
Ok(_) => panic!("Unexpected message"),
Err(_) => break,

View file

@ -5,6 +5,8 @@
use dom::bindings::codegen::Bindings::TestBindingBinding::TestBindingMethods;
use dom::bindings::codegen::Bindings::TestBindingBinding::TestEnum;
use dom::bindings::codegen::Bindings::TestBindingBinding::TestEnumValues::_empty;
use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::UnionTypes::BlobOrString::BlobOrString;
use dom::bindings::codegen::UnionTypes::EventOrString::{EventOrString, eString};
use dom::bindings::codegen::UnionTypes::HTMLElementOrLong::{HTMLElementOrLong, eLong};
@ -164,6 +166,8 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> {
fn PassUnion2(self, _: EventOrString) {}
fn PassUnion3(self, _: BlobOrString) {}
fn PassAny(self, _: *mut JSContext, _: JSVal) {}
fn PassCallbackFunction(self, _: Function) {}
fn PassCallbackInterface(self, _: EventListener) {}
fn PassNullableBoolean(self, _: Option<bool>) {}
fn PassNullableByte(self, _: Option<i8>) {}
@ -182,6 +186,8 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> {
fn PassNullableInterface(self, _: Option<JSRef<Blob>>) {}
fn PassNullableUnion(self, _: Option<HTMLElementOrLong>) {}
fn PassNullableUnion2(self, _: Option<EventOrString>) {}
fn PassNullableCallbackFunction(self, _: Option<Function>) {}
fn PassNullableCallbackInterface(self, _: Option<EventListener>) {}
fn PassOptionalBoolean(self, _: Option<bool>) {}
fn PassOptionalByte(self, _: Option<i8>) {}
@ -201,6 +207,8 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> {
fn PassOptionalUnion(self, _: Option<HTMLElementOrLong>) {}
fn PassOptionalUnion2(self, _: Option<EventOrString>) {}
fn PassOptionalAny(self, _: *mut JSContext, _: JSVal) {}
fn PassOptionalCallbackFunction(self, _: Option<Function>) {}
fn PassOptionalCallbackInterface(self, _: Option<EventListener>) {}
fn PassOptionalNullableBoolean(self, _: Option<Option<bool>>) {}
fn PassOptionalNullableByte(self, _: Option<Option<i8>>) {}
@ -219,6 +227,8 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> {
fn PassOptionalNullableInterface(self, _: Option<Option<JSRef<Blob>>>) {}
fn PassOptionalNullableUnion(self, _: Option<Option<HTMLElementOrLong>>) {}
fn PassOptionalNullableUnion2(self, _: Option<Option<EventOrString>>) {}
fn PassOptionalNullableCallbackFunction(self, _: Option<Option<Function>>) {}
fn PassOptionalNullableCallbackInterface(self, _: Option<Option<EventListener>>) {}
fn PassOptionalBooleanWithDefault(self, _: bool) {}
fn PassOptionalByteWithDefault(self, _: i8) {}
@ -249,6 +259,8 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> {
fn PassOptionalNullableInterfaceWithDefault(self, _: Option<JSRef<Blob>>) {}
fn PassOptionalNullableUnionWithDefault(self, _: Option<HTMLElementOrLong>) {}
fn PassOptionalNullableUnion2WithDefault(self, _: Option<EventOrString>) {}
// fn PassOptionalNullableCallbackFunctionWithDefault(self, _: Option<Function>) {}
fn PassOptionalNullableCallbackInterfaceWithDefault(self, _: Option<EventListener>) {}
fn PassOptionalAnyWithDefault(self, _: *mut JSContext, _: JSVal) {}
fn PassOptionalNullableBooleanWithNonNullDefault(self, _: Option<bool>) {}

View file

@ -0,0 +1,14 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://www.whatwg.org/specs/web-apps/current-work/#functiocn
*
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
callback Function = any(any... arguments);

View file

@ -148,6 +148,8 @@ interface TestBinding {
void passUnion2((Event or DOMString) data);
void passUnion3((Blob or DOMString) data);
void passAny(any arg);
void passCallbackFunction(Function fun);
void passCallbackInterface(EventListener listener);
void passNullableBoolean(boolean? arg);
void passNullableByte(byte? arg);
@ -166,6 +168,8 @@ interface TestBinding {
void passNullableInterface(Blob? arg);
void passNullableUnion((HTMLElement or long)? arg);
void passNullableUnion2((Event or DOMString)? data);
void passNullableCallbackFunction(Function? fun);
void passNullableCallbackInterface(EventListener? listener);
void passOptionalBoolean(optional boolean arg);
void passOptionalByte(optional byte arg);
@ -185,6 +189,8 @@ interface TestBinding {
void passOptionalUnion(optional (HTMLElement or long) arg);
void passOptionalUnion2(optional (Event or DOMString) data);
void passOptionalAny(optional any arg);
void passOptionalCallbackFunction(optional Function fun);
void passOptionalCallbackInterface(optional EventListener listener);
void passOptionalNullableBoolean(optional boolean? arg);
void passOptionalNullableByte(optional byte? arg);
@ -203,6 +209,8 @@ interface TestBinding {
void passOptionalNullableInterface(optional Blob? arg);
void passOptionalNullableUnion(optional (HTMLElement or long)? arg);
void passOptionalNullableUnion2(optional (Event or DOMString)? data);
void passOptionalNullableCallbackFunction(optional Function? fun);
void passOptionalNullableCallbackInterface(optional EventListener? listener);
void passOptionalBooleanWithDefault(optional boolean arg = false);
void passOptionalByteWithDefault(optional byte arg = 0);
@ -233,6 +241,8 @@ interface TestBinding {
void passOptionalNullableInterfaceWithDefault(optional Blob? arg = null);
void passOptionalNullableUnionWithDefault(optional (HTMLElement or long)? arg = null);
void passOptionalNullableUnion2WithDefault(optional (Event or DOMString)? data = null);
// void passOptionalNullableCallbackFunctionWithDefault(optional Function? fun = null);
void passOptionalNullableCallbackInterfaceWithDefault(optional EventListener? listener = null);
void passOptionalAnyWithDefault(optional any arg = null);
void passOptionalNullableBooleanWithNonNullDefault(optional boolean? arg = false);

View file

@ -64,13 +64,11 @@ Window implements WindowEventHandlers;
// http://www.whatwg.org/html/#windowtimers
[NoInterfaceObject/*, Exposed=Window,Worker*/]
interface WindowTimers {
//long setTimeout(Function handler, optional long timeout = 0, any... arguments);
long setTimeout(Function handler, optional long timeout = 0, any... arguments);
//long setTimeout(DOMString handler, optional long timeout = 0, any... arguments);
long setTimeout(any handler, optional long timeout = 0);
void clearTimeout(optional long handle = 0);
//long setInterval(Function handler, optional long timeout = 0, any... arguments);
long setInterval(Function handler, optional long timeout = 0, any... arguments);
//long setInterval(DOMString handler, optional long timeout = 0, any... arguments);
long setInterval(any handler, optional long timeout = 0);
void clearInterval(optional long handle = 0);
};
Window implements WindowTimers;

View file

@ -4,6 +4,7 @@
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerNonNull, EventHandlerNonNull};
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::Bindings::WindowBinding;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
@ -223,8 +224,9 @@ impl<'a> WindowMethods for JSRef<'a, Window> {
self.navigator.get().unwrap()
}
fn SetTimeout(self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
fn SetTimeout(self, _cx: *mut JSContext, callback: Function, timeout: i32, args: Vec<JSVal>) -> i32 {
self.timers.set_timeout_or_interval(callback,
args,
timeout,
false, // is_interval
FromWindow(self.page.id.clone()),
@ -235,8 +237,9 @@ impl<'a> WindowMethods for JSRef<'a, Window> {
self.timers.clear_timeout_or_interval(handle);
}
fn SetInterval(self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
fn SetInterval(self, _cx: *mut JSContext, callback: Function, timeout: i32, args: Vec<JSVal>) -> i32 {
self.timers.set_timeout_or_interval(callback,
args,
timeout,
true, // is_interval
FromWindow(self.page.id.clone()),
@ -317,7 +320,7 @@ pub trait WindowHelpers {
fn wait_until_safe_to_modify_dom(self);
fn init_browser_context(self, doc: JSRef<Document>);
fn load_url(self, href: DOMString);
fn handle_fire_timer(self, timer_id: TimerId, cx: *mut JSContext);
fn handle_fire_timer(self, timer_id: TimerId);
fn evaluate_js_with_result(self, code: &str) -> JSVal;
fn evaluate_script_with_result(self, code: &str, filename: &str) -> JSVal;
}
@ -380,9 +383,8 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
}
}
fn handle_fire_timer(self, timer_id: TimerId, cx: *mut JSContext) {
let this_value = self.reflector().get_jsobject();
self.timers.fire_timer(timer_id, this_value, cx);
fn handle_fire_timer(self, timer_id: TimerId) {
self.timers.fire_timer(timer_id, self.clone());
self.flush_layout();
}
}

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::error::{ErrorResult, Fallible, Syntax, Network, FailureUnknown};
use dom::bindings::global;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary, OptionalSettable};
@ -155,8 +156,9 @@ impl<'a> WorkerGlobalScopeMethods for JSRef<'a, WorkerGlobalScope> {
base64_atob(atob)
}
fn SetTimeout(self, _cx: *mut JSContext, handler: JSVal, timeout: i32) -> i32 {
self.timers.set_timeout_or_interval(handler,
fn SetTimeout(self, _cx: *mut JSContext, callback: Function, timeout: i32, args: Vec<JSVal>) -> i32 {
self.timers.set_timeout_or_interval(callback,
args,
timeout,
false, // is_interval
FromWorker,
@ -167,8 +169,9 @@ impl<'a> WorkerGlobalScopeMethods for JSRef<'a, WorkerGlobalScope> {
self.timers.clear_timeout_or_interval(handle);
}
fn SetInterval(self, _cx: *mut JSContext, handler: JSVal, timeout: i32) -> i32 {
self.timers.set_timeout_or_interval(handler,
fn SetInterval(self, _cx: *mut JSContext, callback: Function, timeout: i32, args: Vec<JSVal>) -> i32 {
self.timers.set_timeout_or_interval(callback,
args,
timeout,
true, // is_interval
FromWorker,
@ -181,14 +184,13 @@ impl<'a> WorkerGlobalScopeMethods for JSRef<'a, WorkerGlobalScope> {
}
pub trait WorkerGlobalScopeHelpers {
fn handle_fire_timer(self, timer_id: TimerId, cx: *mut JSContext);
fn handle_fire_timer(self, timer_id: TimerId);
}
impl<'a> WorkerGlobalScopeHelpers for JSRef<'a, WorkerGlobalScope> {
fn handle_fire_timer(self, timer_id: TimerId, cx: *mut JSContext) {
let this_value = self.reflector().get_jsobject();
self.timers.fire_timer(timer_id, this_value, cx);
fn handle_fire_timer(self, timer_id: TimerId) {
self.timers.fire_timer(timer_id, self.clone());
}
}

View file

@ -665,7 +665,7 @@ impl ScriptTask {
pipeline ID not associated with this script task. This is a bug.");
let frame = page.frame();
let window = frame.as_ref().unwrap().window.root();
window.handle_fire_timer(timer_id, self.get_cx());
window.handle_fire_timer(timer_id);
}
/// Handles a notification that reflow completed.

View file

@ -3,16 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::cell::DOMRefCell;
use dom::bindings::callback::ReportExceptions;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::js::JSRef;
use dom::bindings::utils::Reflectable;
use script_task::{FireTimerMsg, ScriptChan};
use script_task::{TimerSource, FromWindow, FromWorker};
use servo_util::task::spawn_named;
use js::jsapi::JS_CallFunctionValue;
use js::jsapi::{JSContext, JSObject};
use js::jsval::{JSVal, NullValue};
use js::rust::with_compartment;
use js::jsval::JSVal;
use std::cell::Cell;
use std::cmp;
@ -21,7 +22,6 @@ use std::comm::{channel, Sender};
use std::comm::Select;
use std::hash::{Hash, sip};
use std::io::timer::Timer;
use std::ptr;
use std::time::duration::Duration;
#[deriving(PartialEq, Eq)]
@ -69,11 +69,14 @@ impl Drop for TimerManager {
// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
// to the function when calling it)
// TODO: Handle rooting during fire_timer when movable GC is turned on
#[jstraceable]
#[privatize]
#[deriving(Clone)]
struct TimerData {
is_interval: bool,
funval: JSVal,
funval: Function,
args: Vec<JSVal>
}
impl TimerManager {
@ -85,7 +88,8 @@ impl TimerManager {
}
pub fn set_timeout_or_interval(&self,
callback: JSVal,
callback: Function,
arguments: Vec<JSVal>,
timeout: i32,
is_interval: bool,
source: TimerSource,
@ -142,6 +146,7 @@ impl TimerManager {
data: TimerData {
is_interval: is_interval,
funval: callback,
args: arguments
}
};
self.active_timers.borrow_mut().insert(timer_id, timer);
@ -156,21 +161,15 @@ impl TimerManager {
}
}
pub fn fire_timer(&self, timer_id: TimerId, this: *mut JSObject, cx: *mut JSContext) {
pub fn fire_timer<T: Reflectable>(&self, timer_id: TimerId, this: JSRef<T>) {
let data = match self.active_timers.borrow().get(&timer_id) {
None => return,
Some(timer_handle) => timer_handle.data,
Some(timer_handle) => timer_handle.data.clone(),
};
// TODO: Support extra arguments. This requires passing a `*JSVal` array as `argv`.
with_compartment(cx, this, || {
let mut rval = NullValue();
unsafe {
JS_CallFunctionValue(cx, this, data.funval,
0, ptr::null_mut(), &mut rval);
}
});
// TODO: Must handle rooting of funval and args when movable GC is turned on
let _ = data.funval.Call_(this, data.args, ReportExceptions);
if !data.is_interval {
self.active_timers.borrow_mut().remove(&timer_id);

View file

@ -9948,3 +9948,27 @@
[HTMLFontElement interface: document.createElement("font") must inherit property "size" with the proper type (2)]
expected: FAIL
[Window interface: operation setTimeout(Function,long,any)]
expected: FAIL
[Window interface: operation setTimeout(DOMString,long,any)]
expected: FAIL
[Window interface: operation setInterval(Function,long,any)]
expected: FAIL
[Window interface: operation setInterval(DOMString,long,any)]
expected: FAIL
[WorkerGlobalScope interface: operation setTimeout(Function,long,any)]
expected: FAIL
[WorkerGlobalScope interface: operation setTimeout(DOMString,long,any)]
expected: FAIL
[WorkerGlobalScope interface: operation setInterval(Function,long,any)]
expected: FAIL
[WorkerGlobalScope interface: operation setInterval(DOMString,long,any)]
expected: FAIL

View file

@ -1,8 +1,9 @@
[compile-error-in-setInterval.html]
type: testharness
expected: TIMEOUT
[window.onerror - compile error in setInterval]
expected: FAIL
expected: NOTRUN
[window.onerror - compile error in setInterval (column)]
expected: FAIL
expected: NOTRUN

View file

@ -1,8 +1,9 @@
[compile-error-in-setTimeout.html]
type: testharness
expected: TIMEOUT
[window.onerror - compile error in setTimeout]
expected: FAIL
expected: NOTRUN
[window.onerror - compile error in setTimeout (column)]
expected: FAIL
expected: NOTRUN

View file

@ -1,8 +1,9 @@
[runtime-error-in-setInterval.html]
type: testharness
expected: TIMEOUT
[window.onerror - runtime error in setInterval]
expected: FAIL
expected: NOTRUN
[window.onerror - runtime error in setInterval (column)]
expected: FAIL
expected: NOTRUN

View file

@ -1,8 +1,9 @@
[runtime-error-in-setTimeout.html]
type: testharness
expected: TIMEOUT
[window.onerror - runtime error in setTimeout]
expected: FAIL
expected: NOTRUN
[window.onerror - runtime error in setTimeout (column)]
expected: FAIL
expected: NOTRUN