Bug 816187 - Make WebIDL accept nullable dictionary retvals; let getContextAttributes's retval be nullable. r=bz, a=lsblakk
authorBenoit Jacob <bjacob@mozilla.com>
Fri, 30 Nov 2012 18:30:05 -0500
changeset 121866 0c97e6c40f6c42e8320bc3d753318383e2925d42
parent 121865 6952c37a602f5aec19a61288af9cbcc2c66ed1bc
child 121867 269946c84e11fa6425c799365e5fd687dda226e7
push idunknown
push userunknown
push dateunknown
reviewersbz, lsblakk
bugs816187
milestone19.0a2
Bug 816187 - Make WebIDL accept nullable dictionary retvals; let getContextAttributes's retval be nullable. r=bz, a=lsblakk
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_dictionary.py
dom/webidl/WebGLRenderingContext.webidl
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -870,24 +870,23 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
     canvasLayer->Updated();
 
     mResetLayer = false;
 
     return canvasLayer.forget().get();
 }
 
 void
-WebGLContext::GetContextAttributes(dom::WebGLContextAttributes &result)
+WebGLContext::GetContextAttributes(Nullable<dom::WebGLContextAttributesInitializer> &retval)
 {
+    retval.SetNull();
     if (!IsContextStable())
-    {
-        // XXXbz spec says we should still return our attributes in
-        // this case!  Should we store them all in mOptions?
         return;
-    }
+
+    dom::WebGLContextAttributes& result = retval.SetValue();
 
     gl::ContextFormat cf = gl->ActualFormat();
     result.alpha = cf.alpha > 0;
     result.depth = cf.depth > 0;
     result.stencil = cf.stencil > 0;
     result.antialias = cf.samples > 1;
     result.premultipliedAlpha = mOptions.premultipliedAlpha;
     result.preserveDrawingBuffer = mOptions.preserveDrawingBuffer;
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -91,16 +91,17 @@ class WebGLMemoryPressureObserver;
 class WebGLRectangleObject;
 class WebGLContextBoundObject;
 class WebGLActiveInfo;
 class WebGLShaderPrecisionFormat;
 class WebGLExtensionBase;
 
 namespace dom {
 struct WebGLContextAttributes;
+struct WebGLContextAttributesInitializer;
 }
 
 enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
 
 struct VertexAttrib0Status {
     enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
 };
 
@@ -646,17 +647,17 @@ public:
         return mWidth;
     }
     WebGLsizei DrawingBufferHeight() const {
         if (!IsContextStable())
             return 0;
         return mHeight;
     }
         
-    void GetContextAttributes(dom::WebGLContextAttributes& retval);
+    void GetContextAttributes(dom::Nullable<dom::WebGLContextAttributesInitializer>& retval);
     bool IsContextLost() const { return !IsContextStable(); }
     void GetSupportedExtensions(JSContext *cx, dom::Nullable< nsTArray<nsString> > &retval);
     JSObject* GetExtension(JSContext* cx, const nsAString& aName, ErrorResult& rv);
     void ActiveTexture(WebGLenum texture);
     void AttachShader(WebGLProgram* program, WebGLShader* shader);
     void BindAttribLocation(WebGLProgram* program, WebGLuint location,
                             const nsAString& name);
     void BindBuffer(WebGLenum target, WebGLBuffer* buf);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3250,42 +3250,42 @@ if (!%(resultStr)s) {
         # to wrap here.
         if type.nullable():
             toValue = "JS::ObjectOrNullValue(%s)"
         else:
             toValue = "JS::ObjectValue(*%s)"
         # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
         return (setValue(toValue % result, True), False)
 
-    if type.isDictionary():
-        assert not type.nullable()
-        return (wrapAndSetPtr("%s.ToObject(cx, ${obj}, ${jsvalPtr})" % result),
-                False)
-
     if type.isUnion():
         if type.nullable():
             prefix = "%s->"
         else:
             prefix = "%s."
         return (wrapAndSetPtr((prefix % result) +
                               "ToJSVal(cx, ${obj}, ${jsvalPtr})"), False)
 
-    if not type.isPrimitive():
+    if not (type.isPrimitive() or type.isDictionary()):
         raise TypeError("Need to learn to wrap %s" % type)
 
     if type.nullable():
         (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
                                                          "%s.Value()" % result, successCode,
                                                          isCreator, exceptionCode)
         return ("if (%s.IsNull()) {\n" % result +
                 CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
                 "}\n" + recTemplate, recInfal)
-    
+
+    if type.isDictionary():
+        return (wrapAndSetPtr("%s.ToObject(cx, ${obj}, ${jsvalPtr})" % result),
+                False)
+
+
     tag = type.tag()
-    
+
     if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
                IDLType.Tags.uint16, IDLType.Tags.int32]:
         return (setValue("INT_TO_JSVAL(int32_t(%s))" % result), True)
 
     elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float,
                  IDLType.Tags.double]:
         # XXXbz will cast to double do the "even significand" thing that webidl
         # calls for for 64-bit ints?  Do we care?
@@ -3412,21 +3412,23 @@ def getRetvalDeclarationForType(returnTy
         (result, _) = getRetvalDeclarationForType(returnType.inner,
                                                   descriptorProvider,
                                                   resultAlreadyAddRefed)
         result = CGWrapper(result, pre="nsTArray< ", post=" >")
         if nullable:
             result = CGWrapper(result, pre="Nullable< ", post=" >")
         return result, True
     if returnType.isDictionary():
-        assert not returnType.nullable()
+        nullable = returnType.nullable()
         result = CGGeneric(
             CGDictionary.makeDictionaryName(returnType.unroll().inner,
                                             descriptorProvider.workers) +
             "Initializer")
+        if nullable:
+            result = CGWrapper(result, pre="Nullable< ", post=" >")
         return result, True
     if returnType.isUnion():
         raise TypeError("Need to sort out ownership model for union retvals");
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1166,27 +1166,16 @@ class IDLNullableType(IDLType):
             raise WebIDLError("The inner type of a nullable type must not be "
                               "a nullable type",
                               [self.location, self.inner.location])
         if self.inner.isUnion():
             if self.inner.hasNullableType:
                 raise WebIDLError("The inner type of a nullable type must not "
                                   "be a union type that itself has a nullable "
                                   "type as a member type", [self.location])
-            # Check for dictionaries in the union
-            for memberType in self.inner.flatMemberTypes:
-                if memberType.isDictionary():
-                    raise WebIDLError("The inner type of a nullable type must "
-                                      "not be a union type containing a "
-                                      "dictionary type",
-                                      [self.location, memberType.location])
-                    
-        if self.inner.isDictionary():
-            raise WebIDLError("The inner type of a nullable type must not be a "
-                              "dictionary type", [self.location])
 
         self.name = self.inner.name
         return self
 
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
@@ -2473,16 +2462,29 @@ class IDLMethod(IDLInterfaceMember, IDLS
                     # Dictionaries at the end of the list or followed by
                     # optional arguments must be optional.
                     if (not argument.optional and
                         (idx == len(arguments) - 1 or arguments[idx+1].optional)):
                         raise WebIDLError("Dictionary argument not followed by "
                                           "a required argument must be "
                                           "optional", [argument.location])
 
+                    # An argument cannot be a Nullable Dictionary
+                    if argument.type.nullable():
+                        raise WebIDLError("An argument cannot be a nullable dictionary",
+                                          [argument.location])
+
+                # An argument cannot be a nullable union containing a dictionary
+                if argument.type.isUnion() and argument.type.nullable():
+                    for memberType in argument.type.inner.flatMemberTypes:
+                        if memberType.isDictionary():
+                            raise WebIDLError("An argument cannot be a nullable union "
+                                              "containing a dictionary",
+                                              [argument.location, memberType.location])
+
                 # Only the last argument can be variadic
                 if variadicArgument:
                     raise WebIDLError("Variadic argument is not last argument",
                                       [variadicArgument.location])
                 # Once we see an optional argument, there can't be any non-optional
                 # arguments.
                 if inOptionalArguments and not argument.optional:
                     raise WebIDLError("Non-optional argument after optional "
--- a/dom/bindings/parser/tests/test_dictionary.py
+++ b/dom/bindings/parser/tests/test_dictionary.py
@@ -191,8 +191,21 @@ def WebIDLTest(parser, harness):
               void doFoo((A or long)? arg1);
             };
         """)
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw, "Dictionary arg must not be in a nullable union")
+
+    parser = parser.reset()
+    parser.parse("""
+        dictionary A {
+        };
+        interface X {
+          A? doFoo();
+        };
+    """)
+    results = parser.finish()
+
+    harness.ok(True, "Dictionary return value can be nullable")
+
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -498,17 +498,17 @@ interface WebGLRenderingContext {
     const GLenum UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
     const GLenum BROWSER_DEFAULT_WEBGL          = 0x9244;
 
     // The canvas might actually be null in some cases, apparently.
     readonly attribute HTMLCanvasElement? canvas;
     readonly attribute GLsizei drawingBufferWidth;
     readonly attribute GLsizei drawingBufferHeight;
 
-    [WebGLHandlesContextLoss] WebGLContextAttributes getContextAttributes();
+    [WebGLHandlesContextLoss] WebGLContextAttributes? getContextAttributes();
     [WebGLHandlesContextLoss] boolean isContextLost();
 
     sequence<DOMString>? getSupportedExtensions();
 
     [Throws]
     object? getExtension(DOMString name);
 
     void activeTexture(GLenum texture);