From f642f5c9cdffe23043fd93149a0e0b3c224adae1 Mon Sep 17 00:00:00 2001 From: Nicholas Cameron Date: Thu, 26 Jul 2012 14:31:26 +1200 Subject: [PATCH] Bug 776685; throw TypeError exceptions from Azure canvas bindings. r=bz --- content/canvas/test/test_canvas.html | 99 +++++++++++++++++++++++----- dom/bindings/Codegen.py | 41 +++++++----- dom/bindings/Errors.msg | 5 +- 3 files changed, 112 insertions(+), 33 deletions(-) diff --git a/content/canvas/test/test_canvas.html b/content/canvas/test/test_canvas.html index 967024618076..22e357e475c9 100644 --- a/content/canvas/test/test_canvas.html +++ b/content/canvas/test/test_canvas.html @@ -3538,8 +3538,13 @@ var ctx = canvas.getContext('2d'); var _thrown = undefined; try { ctx.drawImage(null, 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} } @@ -3715,17 +3720,39 @@ var ctx = canvas.getContext('2d'); var _thrown = undefined; try { ctx.drawImage(undefined, 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} + var _thrown = undefined; try { ctx.drawImage(0, 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} + var _thrown = undefined; try { ctx.drawImage("", 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} + var _thrown = undefined; try { ctx.drawImage(document.createElement('p'), 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); - +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} } @@ -7696,7 +7723,12 @@ var ctx = canvas.getContext('2d'); var _thrown = undefined; try { ctx.createImageData(null); -} catch (e) { _thrown = e }; todo(_thrown && _thrown instanceof TypeError, "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} } @@ -9207,8 +9239,12 @@ var ctx = canvas.getContext('2d'); var _thrown = undefined; try { ctx.putImageData(null, 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); - +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} } @@ -9319,13 +9355,31 @@ var ctx = canvas.getContext('2d'); var imgdata = { width: 1, height: 1, data: [255, 0, 0, 255] }; var _thrown = undefined; try { ctx.putImageData(imgdata, 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} + var _thrown = undefined; try { ctx.putImageData("cheese", 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} + var _thrown = undefined; try { ctx.putImageData(42, 0, 0); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} + } @@ -15131,7 +15185,12 @@ var ctx = canvas.getContext('2d'); var _thrown = undefined; try { ctx.createPattern(null, 'repeat'); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} } @@ -15150,7 +15209,12 @@ var ctx = canvas.getContext('2d'); var _thrown = undefined; try { ctx.createPattern('image_red.png', 'repeat'); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} } @@ -15169,7 +15233,12 @@ var ctx = canvas.getContext('2d'); var _thrown = undefined; try { ctx.createPattern(undefined, 'repeat'); -} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} catch (e) { _thrown = e }; +if (IsAzureEnabled()) { + ok(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} else { + todo(_thrown && _thrown.name == "TypeError", "should throw TypeError"); +} } diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 397f748f9a60..f8a0ffbcbf65 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1513,13 +1513,16 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, # Also, we should not have a defaultValue if we know we're an object assert(not isDefinitelyObject or defaultValue is None) - # A helper function for dealing with failures due to the JS value being the + # Helper functions for dealing with failures due to the JS value being the # wrong type of value - def onFailure(failureCode, isWorker): + def onFailureNotAnObject(failureCode): return CGWrapper(CGGeneric( failureCode or - "return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);" - % toStringBool(isWorker)), post="\n") + 'return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n") + def onFailureBadType(failureCode, typeName): + return CGWrapper(CGGeneric( + failureCode or + 'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n") # A helper function for handling default values. Takes a template # body and the C++ code to set the default value and wraps the @@ -1547,7 +1550,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, # A helper function for wrapping up the template body for # possibly-nullable objecty stuff def wrapObjectTemplate(templateBody, isDefinitelyObject, type, - codeToSetNull, isWorker, failureCode=None): + codeToSetNull, failureCode=None): if not isDefinitelyObject: # Handle the non-object cases by wrapping up the whole # thing in an if cascade. @@ -1560,7 +1563,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, " %s;\n" % codeToSetNull) templateBody += ( "} else {\n" + - CGIndenter(onFailure(failureCode, isWorker)).define() + + CGIndenter(onFailureNotAnObject(failureCode)).define() + "}") if type.nullable(): templateBody = handleDefaultNull(templateBody, codeToSetNull) @@ -1646,8 +1649,7 @@ for (uint32_t i = 0; i < length; ++i) { templateBody += "\n}" templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject, type, - "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define(), - descriptorProvider.workers) + "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define()) return (templateBody, typeName, None, isOptional) if type.isUnion(): @@ -1666,6 +1668,7 @@ for (uint32_t i = 0; i < length; ++i) { unionArgumentObj += ".ref()" memberTypes = type.flatMemberTypes + names = [] interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes) if len(interfaceMemberTypes) > 0: @@ -1676,6 +1679,7 @@ for (uint32_t i = 0; i < length; ++i) { else: name = memberType.name interfaceObject.append(CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext" % (unionArgumentObj, name))) + names.append(name) interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True) else: interfaceObject = None @@ -1692,6 +1696,7 @@ for (uint32_t i = 0; i < length; ++i) { arrayObject = CGWrapper(CGIndenter(arrayObject), pre="if (IsArrayLike(cx, &argObj)) {\n", post="}") + names.append(name) else: arrayObject = None @@ -1705,6 +1710,7 @@ for (uint32_t i = 0; i < length; ++i) { dateObject = CGWrapper(CGIndenter(dateObject), pre="if (JS_ObjectIsDate(cx, &argObj)) {\n", post="\n}") + names.append(name) else: dateObject = None @@ -1714,6 +1720,7 @@ for (uint32_t i = 0; i < length; ++i) { memberType = callbackMemberTypes[0] name = memberType.name callbackObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name)) + names.append(name) else: callbackObject = None @@ -1783,6 +1790,7 @@ for (uint32_t i = 0; i < length; ++i) { else: name = memberType.name other = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name)) + names.append(name) if hasObjectTypes: other = CGWrapper(CGIndenter(other), "{\n", post="\n}") if object: @@ -1799,8 +1807,8 @@ for (uint32_t i = 0; i < length; ++i) { " return false;\n" "}\n" "if (!done) {\n" - " return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n" - "}" % toStringBool(descriptorProvider.workers)) + " return ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n" + "}" % ", ".join(names)) templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}") typeName = type.name @@ -1939,8 +1947,8 @@ for (uint32_t i = 0; i < length; ++i) { "jsval tmpVal = ${val};\n" + typePtr + " tmp;\n" "if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n") - templateBody += CGIndenter(onFailure(failureCode, - descriptor.workers)).define() + templateBody += CGIndenter(onFailureBadType(failureCode, + descriptor.interface.identifier.name)).define() templateBody += ("}\n" "MOZ_ASSERT(tmp);\n") @@ -1959,7 +1967,7 @@ for (uint32_t i = 0; i < length; ++i) { templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject, type, "${declName} = NULL", - descriptor.workers, failureCode) + failureCode) declType = CGGeneric(declType) if holderType is not None: @@ -1997,10 +2005,10 @@ for (uint32_t i = 0; i < length; ++i) { template = ( "%s.%s(cx, &${val}.toObject());\n" "if (!%s.%s().inited()) {\n" - "%s" # No newline here because onFailure() handles that + "%s" # No newline here because onFailureBadType() handles that "}\n" % (constructLoc, constructMethod, constructLoc, constructInternal, - CGIndenter(onFailure(failureCode, descriptorProvider.workers)).define())) + CGIndenter(onFailureBadType(failureCode, type.name)).define())) nullableTarget = "" if type.nullable(): if isOptional: @@ -2014,7 +2022,6 @@ for (uint32_t i = 0; i < length; ++i) { template += "${declName} = ${holderName}.addr();" template = wrapObjectTemplate(template, isDefinitelyObject, type, "%s = NULL" % nullableTarget, - descriptorProvider.workers, failureCode) if holderType is not None: @@ -2148,7 +2155,7 @@ for (uint32_t i = 0; i < length; ++i) { template = wrapObjectTemplate("${declName} = &${val}.toObject();", isDefinitelyObject, type, "${declName} = NULL", - descriptorProvider.workers, failureCode) + failureCode) if type.nullable(): declType = CGGeneric("JSObject*") else: diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index a4f7a1e841b7..0ce10da33857 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -19,5 +19,8 @@ * be replaced with a string value when the error is reported. */ -MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration '{1}'.") +MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration {1}.") MSG_DEF(MSG_MISSING_ARGUMENTS, 1, "Not enough arguments to {0}.") +MSG_DEF(MSG_NOT_OBJECT, 0, "Value not an object.") +MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 1, "Value does not implement interface {0}.") +MSG_DEF(MSG_NOT_IN_UNION, 1, "Value could not be converted to any of: {0}.")