Bug 820665 part 3. WebIDL spec updates to changes in how callback interfaces work. r=khuey
Specifically, any object that's not a Date or RegExp can implement a callback interface.
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -228,16 +228,22 @@ IsConvertibleToDictionary(JSContext* cx,
MOZ_ALWAYS_INLINE bool
IsConvertibleToDictionary(JSContext* cx, JS::Value val)
{
return val.isNullOrUndefined() ||
(val.isObject() && IsConvertibleToDictionary(cx, &val.toObject()));
}
+MOZ_ALWAYS_INLINE bool
+IsConvertibleToCallbackInterface(JSContext* cx, JSObject* obj)
+{
+ return IsNotDateOrRegExp(cx, obj);
+}
+
inline bool
IsPlatformObject(JSContext* cx, JSObject* obj)
{
MOZ_ASSERT(obj);
// Fast-path the common cases
JSClass* clasp = js::GetObjectJSClass(obj);
if (js::Valueify(clasp) == &js::ObjectClass) {
return false;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1931,22 +1931,26 @@ class CallbackObjectUnwrapper:
'%s' % (descriptor.name, exceptionCode))
self.descriptor = descriptor
self.substitution = { "nativeType" : descriptor.nativeType,
"source" : source,
"target" : target,
"codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure)).define() }
def __str__(self):
+ checkObjectType = CGIfWrapper(
+ CGGeneric(self.substitution["codeOnFailure"]),
+ "!IsConvertibleToCallbackInterface(cx, %(source)s)" %
+ self.substitution).define() + "\n\n"
if self.descriptor.workers:
- return string.Template(
+ return checkObjectType + string.Template(
"${target} = ${source};"
).substitute(self.substitution)
- return string.Template(
+ return checkObjectType + string.Template(
"""nsresult rv;
XPCCallContext ccx(JS_CALLER, cx);
if (!ccx.IsValid()) {
rv = NS_ERROR_XPC_BAD_CONVERT_JS;
${codeOnFailure}
}
const nsIID& iid = NS_GET_IID(${nativeType});
@@ -2343,21 +2347,16 @@ for (uint32_t i = 0; i < length; ++i) {
assert len(callbackMemberTypes) == 1
memberType = callbackMemberTypes[0]
name = memberType.name
callbackObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${obj}, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
names.append(name)
else:
callbackObject = None
- if callbackObject and callbackMemberTypes[0].isCallbackInterface():
- callbackObject = CGWrapper(CGIndenter(callbackObject),
- pre="if (!IsPlatformObject(cx, &argObj)) {\n",
- post="\n}")
-
dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
if len(dictionaryMemberTypes) > 0:
raise TypeError("No support for unwrapping dictionaries as member "
"of a union")
else:
dictionaryObject = None
objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
@@ -4027,26 +4026,23 @@ class CGMethodCall(CGThing):
# Now check for distinguishingArg being various kinds of objects.
# The spec says to check for the following things in order:
# 1) A platform object that's not a platform array object, being
# passed to an interface or "object" arg.
# 2) A Date object being passed to a Date or "object" arg.
# 3) A RegExp object being passed to a RegExp or "object" arg.
# 4) A callable object being passed to a callback or "object" arg.
# 5) Any non-Date and non-RegExp object being passed to a
- # dictionary or array or sequence or "object" arg.
- # 6) Some other kind of object being passed to a callback
- # interface or "object" arg.
+ # array or sequence or callback interface dictionary or
+ # "object" arg.
#
- # Unfortunately, we cannot push the "some other kind of object"
- # check down into case 6, because callbacks interfaces _can_ normally be
- # initialized from platform objects. But we can coalesce the other
- # five cases together, as long as we make sure to check whether our
- # object works as an interface argument before checking whether it
- # works as an arraylike or dictionary or callback function.
+ # We can can coalesce these five cases together, as long as we make
+ # sure to check whether our object works as an interface argument
+ # before checking whether it works as an arraylike or dictionary or
+ # callback function or callback interface.
# First grab all the overloads that have a non-callback interface
# (which includes typed arrays and arraybuffers) at the
# distinguishing index. We can also include the ones that have an
# "object" here, since if those are present no other object-typed
# argument will be.
objectSigs = [
s for s in possibleSignatures
@@ -4057,21 +4053,22 @@ class CGMethodCall(CGThing):
objectSigs.extend(s for s in possibleSignatures
if distinguishingType(s).isDate())
# And all the overloads that take callbacks
objectSigs.extend(s for s in possibleSignatures
if distinguishingType(s).isCallback())
# Now append all the overloads that take an array or sequence or
- # dictionary:
+ # dictionary or callback interface:
objectSigs.extend(s for s in possibleSignatures
if (distinguishingType(s).isArray() or
distinguishingType(s).isSequence() or
- distinguishingType(s).isDictionary()))
+ distinguishingType(s).isDictionary() or
+ distinguishingType(s).isCallbackInterface()))
# There might be more than one thing in objectSigs; we need to check
# which ones we unwrap to.
if len(objectSigs) > 0:
# Here it's enough to guard on our argument being an object. The
# code for unwrapping non-callback interfaces, typed arrays,
# sequences, arrays, and Dates will just bail out and move on to
# the next overload if the object fails to unwrap correctly,
@@ -4087,21 +4084,16 @@ class CGMethodCall(CGThing):
caseBody.append(CGIndenter(CGGeneric("do {")));
# Indent by 4, since we need to indent further
# than our "do" statement
tryCall(sig, 4, isDefinitelyObject=True)
caseBody.append(CGIndenter(CGGeneric("} while (0);")))
caseBody.append(CGGeneric("}"))
- # Check for vanilla JS objects
- pickFirstSignature("%s.isObject() && !IsPlatformObject(cx, &%s.toObject())" %
- (distinguishingArg, distinguishingArg),
- lambda s: distinguishingType(s).isCallbackInterface())
-
# The remaining cases are mutually exclusive. The
# pickFirstSignature calls are what change caseBody
# Check for strings or enums
if pickFirstSignature(None,
lambda s: (distinguishingType(s).isString() or
distinguishingType(s).isEnum())):
pass
# Check for primitives
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -477,18 +477,25 @@ public:
// Static methods and attributes
static void StaticMethod(nsISupports*, bool);
static bool StaticAttribute(nsISupports*);
static void SetStaticAttribute(nsISupports*, bool);
// Overload resolution tests
bool Overload1(TestInterface&);
TestInterface* Overload1(const nsAString&, TestInterface&);
+ void Overload2(TestInterface&);
void Overload2(const Dict&);
void Overload2(const nsAString&);
+ void Overload3(TestInterface&);
+ void Overload3(const TestCallback&);
+ void Overload3(const nsAString&);
+ void Overload4(TestInterface&);
+ void Overload4(TestCallbackInterface&);
+ void Overload4(const nsAString&);
// Variadic handling
void PassVariadicThirdArg(const nsAString&, int32_t,
const Sequence<OwningNonNull<TestInterface> >&);
// Miscellania
int32_t AttrWithLenientThis();
void SetAttrWithLenientThis(int32_t);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -427,18 +427,25 @@ interface TestInterface {
// Static methods and attributes
static attribute boolean staticAttribute;
static void staticMethod(boolean arg);
// Overload resolution tests
//void overload1(DOMString... strs);
boolean overload1(TestInterface arg);
TestInterface overload1(DOMString strs, TestInterface arg);
+ void overload2(TestInterface arg);
void overload2(optional Dict arg);
void overload2(DOMString arg);
+ void overload3(TestInterface arg);
+ void overload3(TestCallback arg);
+ void overload3(DOMString arg);
+ void overload4(TestInterface arg);
+ void overload4(TestCallbackInterface arg);
+ void overload4(DOMString arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
// Miscellania
[LenientThis] attribute long attrWithLenientThis;
[Unforgeable] readonly attribute long unforgeableAttr;
[Unforgeable, ChromeOnly] readonly attribute long unforgeableAttr2;
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -346,18 +346,25 @@ interface TestExampleInterface {
// Static methods and attributes
static attribute boolean staticAttribute;
static void staticMethod(boolean arg);
// Overload resolution tests
//void overload1(DOMString... strs);
boolean overload1(TestInterface arg);
TestInterface overload1(DOMString strs, TestInterface arg);
+ void overload2(TestInterface arg);
void overload2(optional Dict arg);
void overload2(DOMString arg);
+ void overload3(TestInterface arg);
+ void overload3(TestCallback arg);
+ void overload3(DOMString arg);
+ void overload4(TestInterface arg);
+ void overload4(TestCallbackInterface arg);
+ void overload4(DOMString arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
// Miscellania
[LenientThis] attribute long attrWithLenientThis;
[Unforgeable] readonly attribute long unforgeableAttr;
[Unforgeable, ChromeOnly] readonly attribute long unforgeableAttr2;