Bug 721569 - Support default values for Web IDL dictionaries. r=khuey CLOBBER BUILD
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Mon, 12 Mar 2012 21:44:48 -0700
changeset 88818 4d64d2d31843f0f9b7b2385c6b100eb6a636e18b
parent 88817 5a7686f1119b038eddbff7d49a169ef1c78f5391
child 88819 c7f4e6a7f6274b1fbdcb6f6b60f3d58eb767df46
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerskhuey
bugs721569
milestone13.0a1
Bug 721569 - Support default values for Web IDL dictionaries. r=khuey CLOBBER BUILD
content/events/test/test_eventctors.html
dom/indexedDB/nsIIDBDatabase.idl
dom/indexedDB/nsIIDBObjectStore.idl
dom/interfaces/events/nsIDOMCloseEvent.idl
dom/interfaces/events/nsIDOMCustomEvent.idl
dom/interfaces/events/nsIDOMEvent.idl
dom/interfaces/events/nsIDOMHashChangeEvent.idl
dom/interfaces/events/nsIDOMMouseEvent.idl
dom/interfaces/events/nsIDOMPageTransitionEvent.idl
dom/interfaces/events/nsIDOMPopStateEvent.idl
dom/interfaces/events/nsIDOMUIEvent.idl
dom/interfaces/storage/nsIDOMStorageEvent.idl
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/dictionary_helper_gen.conf
js/xpconnect/src/dictionary_helper_gen.py
xpcom/idl-parser/xpidl.py
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -321,58 +321,20 @@ ok(e.type, "hello", "Wrong event type!")
 ok(!e.isTrusted, "Event shouldn't be trusted!");
 ok(e.bubbles, "Event should bubble!");
 ok(e.cancelable, "Event should be cancelable!");
 is(e.detail, 1, "detail should be 1");
 is(e.view, window, "view should be window");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
-// StorageEvent
+// UIEvent
 
 try {
-  e = new StorageEvent();
-} catch(exp) {
-  ex = true;
-}
-ok(ex, "First parameter is required!");
-ex = false;
-
-e = new StorageEvent("hello");
-ok(e.type, "hello", "Wrong event type!");
-ok(!e.isTrusted, "Event shouldn't be trusted!");
-ok(!e.bubbles, "Event shouldn't bubble!");
-ok(!e.cancelable, "Event shouldn't be cancelable!");
-is(e.key, "", "key should be ''");
-is(e.oldValue, null, "oldValue should be null");
-is(e.newValue, null, "newValue should be null");
-is(e.url, "", "url should be ''");
-document.dispatchEvent(e);
-is(receivedEvent, e, "Wrong event!");
-
-e = new StorageEvent("hello",
-  { bubbles: true, cancelable: true, key: "key",
-    oldValue: "oldValue", newValue: "newValue", url: "url",
-    storageArea: localStorage });
-ok(e.type, "hello", "Wrong event type!");
-ok(!e.isTrusted, "Event shouldn't be trusted!");
-ok(e.bubbles, "Event should bubble!");
-ok(e.cancelable, "Event should be cancelable!");
-is(e.key, "key", "Wrong value");
-is(e.oldValue, "oldValue", "Wrong value");
-is(e.newValue, "newValue", "Wrong value");
-is(e.url, "url", "Wrong value");
-is(e.storageArea, localStorage, "Wrong value");
-document.dispatchEvent(e);
-is(receivedEvent, e, "Wrong event!");
-
-// MouseEvent
-
-try {
-  e = new MouseEvent();
+  e = new UIEvent();
 } catch(exp) {
   ex = true;
 }
 ok(ex, "First parameter is required!");
 ex = false;
 
 e = new MouseEvent("hello");
 ok(e.type, "hello", "Wrong event type!");
--- a/dom/indexedDB/nsIIDBDatabase.idl
+++ b/dom/indexedDB/nsIIDBDatabase.idl
@@ -40,21 +40,20 @@
 #include "nsISupports.idl"
 
 interface nsIIDBObjectStore;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 interface nsIDOMEventListener;
 
-[scriptable, uuid(fb143548-08d1-43b4-95f2-a1cd58f8db76)]
-interface nsIIDBObjectStoreParameters : nsISupports
+dictionary IDBObjectStoreParameters
 {
-  attribute jsval keyPath;
-  attribute boolean autoIncrement;
+  jsval keyPath;
+  boolean autoIncrement;
 };
 
 /**
  * IDBDatabase interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
  * for more information.
  */
 [scriptable, builtinclass, uuid(bedee48a-f47f-44f2-ba1e-d8fe595bbfee)]
--- a/dom/indexedDB/nsIIDBObjectStore.idl
+++ b/dom/indexedDB/nsIIDBObjectStore.idl
@@ -40,21 +40,20 @@
 #include "nsISupports.idl"
 
 interface nsIIDBIndex;
 interface nsIIDBKeyRange;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 
-[scriptable, uuid(450e02fd-a87a-47d4-beaf-321417dad781)]
-interface nsIIDBIndexParameters : nsISupports
+dictionary IDBIndexParameters
 {
-  attribute boolean unique;
-  attribute boolean multiEntry;
+  boolean unique;
+  boolean multiEntry;
 };
 
 /**
  * nsIIDBObjectStore interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore
  * for more information.
  */
 [scriptable, builtinclass, uuid(43157a3c-bed1-4ce7-98c0-11365b852560)]
--- a/dom/interfaces/events/nsIDOMCloseEvent.idl
+++ b/dom/interfaces/events/nsIDOMCloseEvent.idl
@@ -55,15 +55,14 @@ interface nsIDOMCloseEvent : nsIDOMEvent
   void initCloseEvent(in DOMString aType,
                       in boolean aCanBubble,
                       in boolean aCancelable,
                       in boolean aWasClean,
                       in unsigned short aReasonCode,
                       in DOMString aReason);
 };
 
-[scriptable, uuid(148ed08e-14f1-4be5-b2f8-23f765738379)]
-interface nsICloseEventInit : nsIEventInit
+dictionary CloseEventInit : EventInit
 {
-  attribute boolean wasClean;
-  attribute unsigned short code;
-  attribute DOMString reason;
+  boolean wasClean;
+  unsigned short code;
+  DOMString reason;
 };
--- a/dom/interfaces/events/nsIDOMCustomEvent.idl
+++ b/dom/interfaces/events/nsIDOMCustomEvent.idl
@@ -45,13 +45,12 @@ interface nsIDOMCustomEvent : nsIDOMEven
   readonly attribute nsIVariant detail;
 
   void initCustomEvent(in DOMString  typeArg, 
                        in boolean    canBubbleArg, 
                        in boolean    cancelableArg, 
                        in nsIVariant detailArg);
 };
 
-[scriptable, uuid(8c166794-06af-4eac-b76b-bc132e421b06)]
-interface nsICustomEventInit : nsIEventInit
+dictionary CustomEventInit : EventInit
 {
-  attribute nsIVariant detail;
+  nsIVariant detail;
 };
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -177,14 +177,13 @@ interface nsIDOMEvent : nsISupports
 
   /**
    * Prevents other event listeners from being triggered and,
    * unlike Event.stopPropagation() its effect is immediate.
    */
   void                       stopImmediatePropagation();
 };
 
-[scriptable, uuid(fe864f0f-45df-404a-bb27-83c5d08be8d1)]
-interface nsIEventInit : nsISupports
+dictionary EventInit
 {
-  attribute boolean bubbles;
-  attribute boolean cancelable;
+  boolean bubbles;
+  boolean cancelable;
 };
--- a/dom/interfaces/events/nsIDOMHashChangeEvent.idl
+++ b/dom/interfaces/events/nsIDOMHashChangeEvent.idl
@@ -42,14 +42,13 @@ interface nsIDOMHashChangeEvent : nsIDOM
 
   void initHashChangeEvent(in DOMString typeArg,
                            in boolean canBubbleArg,
                            in boolean cancelableArg,
                            in DOMString oldURLArg,
                            in DOMString newURLArg);
 };
 
-[scriptable, uuid(e56881c1-3714-45bb-bca3-1453ea24ee90)]
-interface nsIHashChangeEventInit : nsIEventInit
+dictionary HashChangeEventInit : EventInit
 {
-  attribute DOMString oldURL;
-  attribute DOMString newURL;
+  DOMString oldURL;
+  DOMString newURL;
 };
--- a/dom/interfaces/events/nsIDOMMouseEvent.idl
+++ b/dom/interfaces/events/nsIDOMMouseEvent.idl
@@ -109,23 +109,22 @@ interface nsIDOMMouseEvent : nsIDOMUIEve
                                        in boolean shiftKeyArg,
                                        in boolean metaKeyArg,
                                        in unsigned short buttonArg,
                                        in nsIDOMEventTarget relatedTargetArg,
                                        in float pressure,
                                        in unsigned short inputSourceArg);
 };
 
-[scriptable, uuid(9495a977-5c9e-4b34-8d51-22bfd9b4fcf6)]
-interface nsIMouseEventInit : nsIUIEventInit
+dictionary MouseEventInit : UIEventInit
 {
-  attribute long screenX;
-  attribute long screenY;
-  attribute long clientX;
-  attribute long clientY;
-  attribute boolean ctrlKey;
-  attribute boolean shiftKey;
-  attribute boolean altKey;
-  attribute boolean metaKey;
-  attribute unsigned short button;
-  // attribute unsigned short buttons; is not supported yet.
-  attribute nsIDOMEventTarget relatedTarget;
+  long screenX;
+  long screenY;
+  long clientX;
+  long clientY;
+  boolean ctrlKey;
+  boolean shiftKey;
+  boolean altKey;
+  boolean metaKey;
+  unsigned short button;
+  // unsigned short buttons; is not supported yet.
+  nsIDOMEventTarget relatedTarget;
 };
--- a/dom/interfaces/events/nsIDOMPageTransitionEvent.idl
+++ b/dom/interfaces/events/nsIDOMPageTransitionEvent.idl
@@ -56,13 +56,12 @@ interface nsIDOMPageTransitionEvent : ns
 
   /* Initialize a new pageshow or pagehide event. */
   void initPageTransitionEvent(in DOMString typeArg,
                                in boolean canBubbleArg,
                                in boolean canCancelArg,
                                in boolean persisted);
 };
 
-[scriptable, uuid(bf3eaa61-5048-48c4-b8b9-9bf833ca63d6)]
-interface nsIPageTransitionEventInit : nsIEventInit
+dictionary PageTransitionEventInit : EventInit
 {
-  attribute boolean persisted;
+  boolean persisted;
 };
--- a/dom/interfaces/events/nsIDOMPopStateEvent.idl
+++ b/dom/interfaces/events/nsIDOMPopStateEvent.idl
@@ -45,13 +45,12 @@ interface nsIDOMPopStateEvent : nsIDOMEv
   readonly attribute nsIVariant state;
 
   void initPopStateEvent(in DOMString typeArg,
                          in boolean canBubbleArg,
                          in boolean cancelableArg,
                          in nsIVariant stateArg);
 };
 
-[scriptable, uuid(2300bd68-f6e0-4c58-a1aa-45f94cdabfbd)]
-interface nsIPopStateEventInit : nsIEventInit
+dictionary PopStateEventInit : EventInit
 {
-  attribute nsIVariant state;
+  nsIVariant state;
 };
--- a/dom/interfaces/events/nsIDOMUIEvent.idl
+++ b/dom/interfaces/events/nsIDOMUIEvent.idl
@@ -69,14 +69,13 @@ interface nsIDOMUIEvent : nsIDOMEvent
   readonly attribute nsIDOMNode         rangeParent;
   readonly attribute long               rangeOffset;
 
            attribute boolean            cancelBubble;
 
   readonly attribute boolean            isChar;
 };
 
-[scriptable, uuid(610eb27e-9718-4acd-8ed1-7d1840bc6c7f)]
-interface nsIUIEventInit : nsIEventInit
+dictionary UIEventInit : EventInit
 {
-  attribute nsIDOMWindow view;
-  attribute long         detail;
+  nsIDOMWindow view;
+  long         detail;
 };
--- a/dom/interfaces/storage/nsIDOMStorageEvent.idl
+++ b/dom/interfaces/storage/nsIDOMStorageEvent.idl
@@ -90,17 +90,16 @@ interface nsIDOMStorageEvent : nsIDOMEve
                         in boolean cancelableArg, 
                         in DOMString keyArg,
                         in DOMString oldValueArg,
                         in DOMString newValueArg,
                         in DOMString urlArg,
                         in nsIDOMStorage storageAreaArg);
 };
 
-[scriptable, uuid(6335e5b5-13ce-4c8a-b452-5c5895f4e90e)]
-interface nsIStorageEventInit : nsIEventInit
+dictionary StorageEventInit : EventInit
 {
-  attribute DOMString key;
-  attribute DOMString oldValue;
-  attribute DOMString newValue;
-  attribute DOMString url;
-  attribute nsIDOMStorage storageArea;
+  DOMString key;
+  DOMString oldValue;
+  DOMString newValue;
+  DOMString url;
+  nsIDOMStorage storageArea;
 };
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2079,18 +2079,18 @@ XPCJSRuntime::newXPCJSRuntime(nsXPConnec
     }
 
     NS_RUNTIMEABORT("new XPCJSRuntime failed to initialize.");
 
     delete self;
     return nsnull;
 }
 
-// DefineStaticDictionaryJSVals is automatically generated.
-bool DefineStaticDictionaryJSVals(JSContext* aCx);
+// InternStaticDictionaryJSVals is automatically generated.
+bool InternStaticDictionaryJSVals(JSContext* aCx);
 
 JSBool
 XPCJSRuntime::OnJSContextNew(JSContext *cx)
 {
     NS_TIME_FUNCTION;
 
     // if it is our first context then we need to generate our string ids
     JSBool ok = true;
@@ -2110,17 +2110,17 @@ XPCJSRuntime::OnJSContextNew(JSContext *
                 mStrJSVals[i] = STRING_TO_JSVAL(str);
             }
         }
 
         ok = mozilla::dom::binding::DefineStaticJSVals(cx);
         if (!ok)
             return false;
 
-        ok = DefineStaticDictionaryJSVals(cx);
+        ok = InternStaticDictionaryJSVals(cx);
     }
     if (!ok)
         return false;
 
     XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
     if (!tls)
         return false;
 
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -1,25 +1,25 @@
 # Dictionary interface name, interface file name
 dictionaries = [
-     [ 'nsIEventInit', 'nsIDOMEvent.idl' ],
-     [ 'nsICustomEventInit', 'nsIDOMCustomEvent.idl' ],
-     [ 'nsIPopStateEventInit', 'nsIDOMPopStateEvent.idl' ],
-     [ 'nsIHashChangeEventInit', 'nsIDOMHashChangeEvent.idl' ],
-     [ 'nsIPageTransitionEventInit', 'nsIDOMPageTransitionEvent.idl' ],
-     [ 'nsICloseEventInit', 'nsIDOMCloseEvent.idl' ],
-     [ 'nsIUIEventInit', 'nsIDOMUIEvent.idl' ],
-     [ 'nsIMouseEventInit', 'nsIDOMMouseEvent.idl' ],
-     [ 'nsIIDBObjectStoreParameters', 'nsIIDBDatabase.idl' ],
-     [ 'nsIIDBIndexParameters', 'nsIIDBObjectStore.idl' ],
-     [ 'nsIStorageEventInit', 'nsIDOMStorageEvent.idl' ]
+     [ 'EventInit', 'nsIDOMEvent.idl' ],
+     [ 'CustomEventInit', 'nsIDOMCustomEvent.idl' ],
+     [ 'PopStateEventInit', 'nsIDOMPopStateEvent.idl' ],
+     [ 'HashChangeEventInit', 'nsIDOMHashChangeEvent.idl' ],
+     [ 'PageTransitionEventInit', 'nsIDOMPageTransitionEvent.idl' ],
+     [ 'CloseEventInit', 'nsIDOMCloseEvent.idl' ],
+     [ 'UIEventInit', 'nsIDOMUIEvent.idl' ],
+     [ 'MouseEventInit', 'nsIDOMMouseEvent.idl' ],
+     [ 'IDBObjectStoreParameters', 'nsIIDBDatabase.idl' ],
+     [ 'IDBIndexParameters', 'nsIIDBObjectStore.idl' ],
+     [ 'StorageEventInit', 'nsIDOMStorageEvent.idl' ]
    ]
 
 # include file names
 special_includes = [
     'nsContentUtils.h',
-    'nsIXPConnect.h'
+    'XPCQuickStubs.h'
   ]
 
 # name of the type to not include using #include "typename.h"
 exclude_automatic_type_include = [
     'nsISupports'
   ]
--- a/js/xpconnect/src/dictionary_helper_gen.py
+++ b/js/xpconnect/src/dictionary_helper_gen.py
@@ -98,61 +98,41 @@ class Configuration:
         self.exclude_automatic_type_include = config.get('exclude_automatic_type_include', [])
 
 def readConfigFile(filename):
     return Configuration(filename)
 
 def firstCap(str):
     return str[0].upper() + str[1:]
 
-def attributeGetterName(a):
-    binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
-    return "Get%s" % (binaryname)
-
-def attributeParamlist(prefix, a):
-    if a.realtype.nativeType('in').endswith('*'):
-        l = ["getter_AddRefs(%s%s)" % (prefix, a.name.strip('* '))]
-    elif a.realtype.nativeType('in').count("nsAString"):
-        l = ["%s%s" % (prefix, a.name)]
-    else:
-        l = ["&(%s%s)" % (prefix, a.name)]
-
-    if a.implicit_jscontext:
-        l.insert(0, "aCx")
-
-    return ", ".join(l)
-
 def attributeVariableTypeAndName(a):
     if a.realtype.nativeType('in').endswith('*'):
         l = ["nsCOMPtr<%s> %s" % (a.realtype.nativeType('in').strip('* '),
                    a.name)]
     elif a.realtype.nativeType('in').count("nsAString"):
         l = ["nsAutoString %s" % a.name]
     elif a.realtype.nativeType('in').count("JS::Value"):
         l = ["JS::Value %s" % a.name]
     else:
         l = ["%s%s" % (a.realtype.nativeType('in'),
                        a.name)]
 
     return ", ".join(l)
 
-def dict_name(iface):
-    return "%s" % strip_begin(iface, "nsI")
-
 def print_header(idl, fd, conf, dictname, dicts):
     for p in idl.productions:
-        if p.kind == 'interface' and p.name == dictname:
+        if p.kind == 'dictionary':
             interfaces = []
             base = p.base
-            baseiface = p.idl.getName(p.base, p.location)
-            while base != "nsISupports" and not base in dicts:
+            baseiface = p
+            while base is not None and not base in dicts:
+                baseiface = baseiface.idl.getName(baseiface.base, baseiface.location)
                 dicts.append(base)
                 interfaces.append(baseiface)
                 base = baseiface.base
-                baseiface = baseiface.idl.getName(baseiface.base, baseiface.location)
 
             interfaces.reverse()
             for iface in interfaces:
                 write_header(iface, fd)
 
             if not p.name in dicts:
                 dicts.append(p.name)
                 write_header(p, fd)
@@ -186,24 +166,24 @@ def print_header_file(fd, conf):
             idl = loadIDL(p, options.incdirs, d[1])
             print_header(idl, fd, conf, d[0], dicts)
     fd.write("}\n"
              "}\n"
              "#endif\n")
 
 def collect_names_and_non_primitive_attribute_types(idl, dictname, attrnames, forwards):
     for p in idl.productions:
-        if p.kind == 'interface' and p.name == dictname:
+        if p.kind == 'dictionary':
             interfaces = []
             base = p.base
-            baseiface = p.idl.getName(p.base, p.location)
-            while base != "nsISupports":
+            baseiface = p
+            while base is not None:
+                baseiface = baseiface.idl.getName(baseiface.base, baseiface.location)    
                 interfaces.append(baseiface)
                 base = baseiface.base
-                baseiface = baseiface.idl.getName(baseiface.base, baseiface.location)    
 
             interfaces.reverse()
             interfaces.append(p)
 
             for iface in interfaces:
                 collect_names_and_non_primitive_attribute_types_from_interface(iface, attrnames, forwards)
 
 def collect_names_and_non_primitive_attribute_types_from_interface(iface, attrnames, forwards):
@@ -213,25 +193,25 @@ def collect_names_and_non_primitive_attr
                 attrnames.append(member.name)
             if member.realtype.nativeType('in').endswith('*'):
                 t = member.realtype.nativeType('in').strip('* ')
                 if not t in forwards:
                     forwards.append(t)
 
 def print_cpp(idl, fd, conf, dictname, dicts):
     for p in idl.productions:
-        if p.kind == 'interface' and p.name == dictname:
+        if p.kind == 'dictionary':
             interfaces = []
             base = p.base
-            baseiface = p.idl.getName(p.base, p.location)
-            while base != "nsISupports" and not base in dicts:
+            baseiface = p
+            while base is not None and not base in dicts:
+                baseiface = baseiface.idl.getName(baseiface.base, baseiface.location)
                 dicts.append(base)
                 interfaces.append(baseiface)
                 base = baseiface.base
-                baseiface = baseiface.idl.getName(baseiface.base, baseiface.location)
 
             interfaces.reverse()
             for iface in interfaces:
                 write_cpp(iface, fd)
 
             if not p.name in dicts:
                 dicts.append(p.name)
                 write_cpp(p, fd)
@@ -263,148 +243,194 @@ def print_cpp_file(fd, conf):
 
     fd.write("\nusing namespace mozilla::dom;\n\n")
 
     for a in attrnames:
         fd.write("static jsid %s = JSID_VOID;\n"% get_jsid(a))
 
     fd.write("\n"
              "static bool\n"
-             "DefineStaticJSVal(JSContext* aCx, jsid &id, const char* aString)\n"
+             "InternStaticJSVal(JSContext* aCx, jsid &id, const char* aString)\n"
              "{\n"
              "  if (JSString* str = JS_InternString(aCx, aString)) {\n"
              "    id = INTERNED_STRING_TO_JSID(aCx, str);\n"
              "    return true;\n"
              "  }\n"
              "  return false;\n"
              "}\n\n"
              "bool\n"
-             "DefineStaticDictionaryJSVals(JSContext* aCx)\n"
+             "InternStaticDictionaryJSVals(JSContext* aCx)\n"
              "{\n"
              "  JSAutoRequest ar(aCx);\n"
              "  return\n")
     for a in attrnames:
-        fd.write("    DefineStaticJSVal(aCx, %s, \"%s\") &&\n"
+        fd.write("    InternStaticJSVal(aCx, %s, \"%s\") &&\n"
                  % (get_jsid(a), a))
 
     fd.write("    true;\n")
     fd.write("}\n\n")
 
     dicts = []
     for d in conf.dictionaries:
         if not d[0] in set(dicts):
             idl = p.parse(open(findIDL(options.incdirs, d[1])).read(), d[1])
             idl.resolve(options.incdirs, p)
             print_cpp(idl, fd, conf, d[0], dicts)
 
 def init_value(attribute):
     realtype = attribute.realtype.nativeType('in')
     realtype = realtype.strip(' ')
-    if realtype.endswith('*'):
-        return "nsnull"
-    if realtype == "bool":
-        return "false"
-    if realtype.count("nsAString"):
-        return "EmptyString()"
-    if realtype.count("nsACString"):
-        return "EmptyCString()"
-    if realtype.count("JS::Value"):
-        return "JSVAL_VOID"
-    return "0"
+    if attribute.defvalue is None:
+        if realtype.endswith('*'):
+            return "nsnull"
+        if realtype == "bool":
+            return "false"
+        if realtype.count("nsAString"):
+            return ""
+        if realtype.count("nsACString"):
+            return ""
+        if realtype.count("JS::Value"):
+            return "JSVAL_VOID"
+        return "0"
+    else:
+        if realtype.count("nsAString"):
+            return "NS_LITERAL_STRING(\"%s\")" % attribute.defvalue
+        if realtype.count("nsACString"):
+            return "NS_LITERAL_CSTRING(\"%s\")" % attribute.defvalue
+        raise IDLError("Default value is not supported for type %s" % realtype)
 
 def write_header(iface, fd):
     attributes = []
     for member in iface.members:
         if isinstance(member, xpidl.Attribute):
             attributes.append(member)
     
-    fd.write("class %s" % dict_name(iface.name))
-    if iface.base != "nsISupports":
-        fd.write(" : public %s" % dict_name(iface.base))
+    fd.write("class %s" % iface.name)
+    if iface.base is not None:
+        fd.write(" : public %s" % iface.base)
     fd.write("\n{\npublic:\n")
-    fd.write("  %s();\n" % dict_name(iface.name))
-    fd.write("  ~%s();\n\n" % dict_name(iface.name))
+    fd.write("  %s();\n" % iface.name)
+    fd.write("  ~%s();\n\n" % iface.name)
 
     fd.write("  // If aCx or aVal is null, NS_OK is returned and \n"
              "  // dictionary will use the default values. \n"
              "  nsresult Init(JSContext* aCx, const jsval* aVal);\n")
     
     fd.write("\n")
 
     for member in attributes:
         fd.write("  %s;\n" % attributeVariableTypeAndName(member))
 
     fd.write("};\n\n")
 
+def write_getter(a, iface, fd):
+    realtype = a.realtype.nativeType('in')
+    if realtype.count("JS::Value"):
+        fd.write("    NS_ENSURE_STATE(JS_GetPropertyById(aCx, aObj, %s, &aDict.%s));\n"
+                 % (get_jsid(a.name), a.name))
+    else:
+        fd.write("    NS_ENSURE_STATE(JS_GetPropertyById(aCx, aObj, %s, &v));\n"
+                 % get_jsid(a.name))
+    if realtype.count("bool"):
+        fd.write("    JSBool b;\n")
+        fd.write("    MOZ_ALWAYS_TRUE(JS_ValueToBoolean(aCx, v, &b));\n")
+        fd.write("    aDict.%s = b;\n" % a.name)
+    elif realtype.count("PRInt32"):
+        fd.write("    NS_ENSURE_STATE(JS_ValueToECMAInt32(aCx, v, &aDict.%s));\n" % a.name)
+    elif realtype.count("PRUint16"):
+        fd.write("    uint32_t u;\n")
+        fd.write("    NS_ENSURE_STATE(JS_ValueToECMAUint32(aCx, v, &u));\n")
+        fd.write("    aDict.%s = u;\n" % a.name)
+    elif realtype.count("nsAString"):
+        fd.write("    xpc_qsDOMString d(aCx, v, &v, xpc_qsDOMString::eStringify, xpc_qsDOMString::eStringify);\n")
+        fd.write("    NS_ENSURE_STATE(d.IsValid());\n")
+        fd.write("    aDict.%s = d;\n" % a.name)
+    elif realtype.count("nsIVariant"):
+        fd.write("    nsCOMPtr<nsIVariant> d(already_AddRefed<nsIVariant>(XPCVariant::newVariant(ccx, v)));\n")
+        fd.write("    NS_ENSURE_STATE(d);\n")
+        fd.write("    aDict.%s = d;\n" % a.name)
+    elif realtype.endswith('*'):
+        fd.write("    %s d;\n" % realtype)
+        fd.write("    xpc_qsSelfRef ref;\n")
+        fd.write("    nsresult rv = xpc_qsUnwrapArg<%s>(aCx, v, &d, &ref.ptr, &v);\n" % realtype.strip('* '))
+        fd.write("    NS_ENSURE_SUCCESS(rv, rv);\n")
+        fd.write("    aDict.%s = d;\n" % a.name)
+    elif not realtype.count("JS::Value"):
+        raise BaseException("Unsupported type %s found in dictionary %s" % (realtype, iface.name))
+
 def write_cpp(iface, fd):
     attributes = []
     for member in iface.members:
         if isinstance(member, xpidl.Attribute):
             attributes.append(member)
 
-    fd.write("%s::%s()" % (dict_name(iface.name), dict_name(iface.name)))
+    fd.write("%s::%s()" % (iface.name, iface.name))
 
-    if iface.base != "nsISupports" or len(attributes) > 0:
+    if iface.base is not None or len(attributes) > 0:
         fd.write(" :\n")
     
-    if iface.base != "nsISupports":
-        fd.write("  %s()" % dict_name(iface.base))
+    if iface.base is not None:
+        fd.write("  %s()" % iface.base)
         if len(attributes) > 0:
             fd.write(",\n")
 
     for i in range(len(attributes)):
         fd.write("  %s(%s)" % (attributes[i].name, init_value(attributes[i])))
         if i < (len(attributes) - 1):
             fd.write(",")
         fd.write("\n")
 
     fd.write("  {}\n\n")
-    fd.write("%s::~%s() {}\n\n" % (dict_name(iface.name), dict_name(iface.name)))
+    fd.write("%s::~%s() {}\n\n" % (iface.name, iface.name))
 
-    fd.write("static nsresult\n%s_InitInternal(%s& aDict, %s* aIfaceObject, JSContext* aCx, JSObject* aObj)\n" %
-             (dict_name(iface.name), dict_name(iface.name), iface.name))
+    fd.write("static nsresult\n%s_InitInternal(%s& aDict, JSContext* aCx, JSObject* aObj)\n" %
+             (iface.name, iface.name))
     fd.write("{\n")
-    if iface.base != "nsISupports":
-        fd.write("  nsresult rv = %s_InitInternal(aDict, aIfaceObject, aCx, aObj);\n" %
-                 dict_name(iface.base))
+    if iface.base is not None:
+        fd.write("  nsresult rv = %s_InitInternal(aDict, aCx, aObj);\n" %
+                 iface.base)
         fd.write("  NS_ENSURE_SUCCESS(rv, rv);\n")
 
     fd.write("  JSBool found = PR_FALSE;\n")
+    needjsval = False
+    needccx = False
+    for a in attributes:
+        if not a.realtype.nativeType('in').count("JS::Value"):
+            needjsval = True
+        if a.realtype.nativeType('in').count("nsIVariant"):
+            needccx = True
+    if needjsval:
+        fd.write("  jsval v = JSVAL_VOID;\n")
+    if needccx:
+        fd.write("  XPCCallContext ccx(NATIVE_CALLER, aCx);\n")
+        fd.write("  NS_ENSURE_STATE(ccx.IsValid());\n")
     for a in attributes:
         fd.write("  NS_ENSURE_STATE(JS_HasPropertyById(aCx, aObj, %s, &found));\n"
                  % get_jsid(a.name))
         fd.write("  if (found) {\n")
-        fd.write("    nsresult rv = aIfaceObject->%s(" % attributeGetterName(a))
-        fd.write("%s" % attributeParamlist("aDict.", a))
-        fd.write(");\n")
-        fd.write("    NS_ENSURE_SUCCESS(rv, rv);\n")
+        write_getter(a, iface, fd)
         fd.write("  }\n")
     fd.write("  return NS_OK;\n")
     fd.write("}\n\n")
     
-    fd.write("nsresult\n%s::Init(JSContext* aCx, const jsval* aVal)\n" % dict_name(iface.name))
+    fd.write("nsresult\n%s::Init(JSContext* aCx, const jsval* aVal)\n" % iface.name)
     fd.write("{\n"
              "  if (!aCx || !aVal) {\n"
              "    return NS_OK;\n"
              "  }\n"
              "  NS_ENSURE_STATE(aVal->isObject());\n\n"
              "  JSObject* obj = &aVal->toObject();\n"
              "  nsCxPusher pusher;\n"
              "  NS_ENSURE_STATE(pusher.Push(aCx, false));\n"
              "  JSAutoRequest ar(aCx);\n"
              "  JSAutoEnterCompartment ac;\n"
              "  NS_ENSURE_STATE(ac.enter(aCx, obj));\n")
-    fd.write("  nsCOMPtr<%s> dict;\n" % iface.name)
-    fd.write("  nsContentUtils::XPConnect()->WrapJS(aCx, obj,\n")
-    fd.write("                                      NS_GET_IID(%s),\n" % iface.name)
-    fd.write("                                      getter_AddRefs(dict));\n")
-    fd.write("  NS_ENSURE_TRUE(dict, NS_OK);\n")
 
-    fd.write("  return %s_InitInternal(*this, dict, aCx, obj);\n}\n\n" %
-                 dict_name(iface.name))
+    fd.write("  return %s_InitInternal(*this, aCx, obj);\n}\n\n" %
+                 iface.name)
 
 
 if __name__ == '__main__':
     from optparse import OptionParser
     o = OptionParser(usage="usage: %prog [options] configfile")
     o.add_option('-I', action='append', dest='incdirs', default=['.'],
                  help="Directory to search for imported files")
     o.add_option('-o', "--stub-output",
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -480,19 +480,17 @@ class Native(object):
             m = '*' + ((self.modifier == 'ptr' and calltype != 'in') and '*' or '')
         else:
             m = calltype != 'in' and '*' or ''
         return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
 
     def __str__(self):
         return "native %s(%s)\n" % (self.name, self.nativename)
 
-class Interface(object):
-    kind = 'interface'
-
+class BaseInterface(object):
     def __init__(self, name, attlist, base, members, location, doccomments):
         self.name = name
         self.attributes = InterfaceAttributes(attlist, location)
         self.base = base
         self.members = members
         self.location = location
         self.namemap = NameMap()
         self.doccomments = doccomments
@@ -538,18 +536,18 @@ class Interface(object):
                     if has_method:
                         raise IDLError("interface '%s' has multiple methods, but marked 'function'" % self.name, self.location)
                     else:
                         has_method = True
 
         parent.setName(self)
         if self.base is not None:
             realbase = parent.getName(self.base, self.location)
-            if realbase.kind != 'interface':
-                raise IDLError("interface '%s' inherits from non-interface type '%s'" % (self.name, self.base), self.location)
+            if realbase.kind != self.kind:
+                raise IDLError("%s '%s' inherits from non-%s type '%s'" % (self.kind, self.name, self.kind, self.base), self.location)
 
             if self.attributes.scriptable and not realbase.attributes.scriptable:
                 print >>sys.stderr, IDLError("interface '%s' is scriptable but derives from non-scriptable '%s'" % (self.name, self.base), self.location, warning=True)
 
         forwardedMembers = set()
         for member in self.members:
             member.resolve(self)
             if member.kind is 'method' and member.forward:
@@ -615,16 +613,31 @@ class Interface(object):
     def countEntries(self):
         ''' Returns the number of entries in the vtable for this interface. '''
         total = sum(member.count() for member in self.members)
         if self.base is not None:
             realbase = self.idl.getName(self.base, self.location)
             total += realbase.countEntries()
         return total
 
+class Interface(BaseInterface):
+    kind = 'interface'
+
+    def __init__(self, name, attlist, base, members, location, doccomments):
+        BaseInterface.__init__(self, name, attlist, base, members, location, doccomments)
+
+        if self.attributes.uuid is None:
+            raise IDLError("interface has no uuid", location)
+
+class Dictionary(BaseInterface):
+    kind = 'dictionary'
+
+    def __init__(self, name, attlist, base, members, location, doccomments):
+        BaseInterface.__init__(self, name, attlist, base, members, location, doccomments)
+
 class InterfaceAttributes(object):
     uuid = None
     scriptable = False
     builtinclass = False
     function = False
     deprecated = False
     noscript = False
 
@@ -670,19 +683,16 @@ class InterfaceAttributes(object):
                 action(self, val)
             else:
                 if val is not None:
                     raise IDLError("Unexpected value for attribute '%s'" % name,
                                    aloc)
 
                 action(self)
 
-        if self.uuid is None:
-            raise IDLError("interface has no uuid", location)
-
     def __str__(self):
         l = []
         if self.uuid:
             l.append("\tuuid: %s\n" % self.uuid)
         if self.scriptable:
             l.append("\tscriptable\n")
         if self.builtinclass:
             l.append("\tbuiltinclass\n")
@@ -725,22 +735,24 @@ class Attribute(object):
     notxpcom = False
     readonly = False
     implicit_jscontext = False
     nostdcall = False
     binaryname = None
     null = None
     undefined = None
     deprecated = False
+    defvalue = None
 
-    def __init__(self, type, name, attlist, readonly, location, doccomments):
+    def __init__(self, type, name, attlist, readonly, defvalue, location, doccomments):
         self.type = type
         self.name = name
         self.attlist = attlist
         self.readonly = readonly
+        self.defvalue = defvalue
         self.location = location
         self.doccomments = doccomments
 
         for name, value, aloc in attlist:
             if name == 'binaryname':
                 if value is None:
                     raise IDLError("binaryname attribute requires a value",
                                    aloc)
@@ -1056,16 +1068,17 @@ class Array(object):
     def nativeType(self, calltype, const=False):
         return "%s%s*" % (const and 'const ' or '',
                           self.type.nativeType(calltype))
 
 class IDLParser(object):
     keywords = {
         'const': 'CONST',
         'interface': 'INTERFACE',
+        'dictionary': 'DICTIONARY',
         'in': 'IN',
         'inout': 'INOUT',
         'out': 'OUT',
         'attribute': 'ATTRIBUTE',
         'raises': 'RAISES',
         'readonly': 'READONLY',
         'native': 'NATIVE',
         'typedef': 'TYPEDEF'
@@ -1076,16 +1089,17 @@ class IDLParser(object):
         'CDATA',
         'INCLUDE',
         'IID',
         'NUMBER',
         'HEXNUM',
         'LSHIFT',
         'RSHIFT',
         'NATIVEID',
+        'STRING',
         ]
 
     tokens.extend(keywords.values())
 
     states = (
         ('nativeid', 'exclusive'),
     )
 
@@ -1126,16 +1140,22 @@ class IDLParser(object):
         return t
 
     def t_INCLUDE(self, t):
         r'\#include[ \t]+"[^"\n]+"'
         inc, value, end = t.value.split('"')
         t.value = value
         return t
 
+    def t_STRING(self, t):
+        r'"[^"\n]+"'
+        begin, value, end = t.value.split('"')
+        t.value = value
+        return t
+
     def t_directive(self, t):
         r'\#(?P<directive>[a-zA-Z]+)[^\n]+'
         raise IDLError("Unrecognized directive %s" % t.lexer.lexmatch.group('directive'),
                        Location(lexer=self.lexer, lineno=self.lexer.lineno,
                                 lexpos=self.lexer.lexpos))
 
     def t_newline(self, t):
         r'\n+'
@@ -1177,16 +1197,17 @@ class IDLParser(object):
 
     def p_productions_include(self, p):
         """productions : INCLUDE productions"""
         p[0] = list(p[2])
         p[0].insert(0, Include(p[1], self.getLocation(p, 1)))
 
     def p_productions_interface(self, p):
         """productions : interface productions
+                       | dictionary productions
                        | typedef productions
                        | native productions"""
         p[0] = list(p[2])
         p[0].insert(0, p[1])
 
     def p_typedef(self, p):
         """typedef : TYPEDEF IDENTIFIER IDENTIFIER ';'"""
         p[0] = Typedef(type=p[2],
@@ -1354,28 +1375,29 @@ class IDLParser(object):
 
     def p_number_bitor(self, p):
         """number : number '|' number"""
         n1 = p[1]
         n2 = p[3]
         p[0] = lambda i: n1(i) | n2(i)
 
     def p_member_att(self, p):
-        """member : attributes optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
+        """member : attributes optreadonly ATTRIBUTE IDENTIFIER identifier ';'"""
         if 'doccomments' in p[1]:
             doccomments = p[1]['doccomments']
         elif p[2] is not None:
             doccomments = p[2]
         else:
             doccomments = p.slice[3].doccomments
 
         p[0] = Attribute(type=p[4],
                          name=p[5],
                          attlist=p[1]['attlist'],
                          readonly=p[2] is not None,
+                         defvalue=None,
                          location=self.getLocation(p, 3),
                          doccomments=doccomments)
 
     def p_member_method(self, p):
         """member : attributes IDENTIFIER IDENTIFIER '(' paramlist ')' raises ';'"""
         if 'doccomments' in p[1]:
             doccomments = p[1]['doccomments']
         else:
@@ -1403,17 +1425,17 @@ class IDLParser(object):
         p[0] = []
 
     def p_moreparams_continue(self, p):
         """moreparams : ',' param moreparams"""
         p[0] = list(p[3])
         p[0].insert(0, p[2])
 
     def p_param(self, p):
-        """param : attributes paramtype IDENTIFIER IDENTIFIER"""
+        """param : attributes paramtype IDENTIFIER identifier"""
         p[0] = Param(paramtype=p[2],
                      type=p[3],
                      name=p[4],
                      attlist=p[1]['attlist'],
                      location=self.getLocation(p, 3))
 
     def p_paramtype(self, p):
         """paramtype : IN
@@ -1424,16 +1446,77 @@ class IDLParser(object):
     def p_optreadonly(self, p):
         """optreadonly : READONLY
                        | """
         if len(p) > 1:
             p[0] = p.slice[1].doccomments
         else:
             p[0] = None
 
+    def p_dictionary(self, p):
+        """dictionary : attributes DICTIONARY IDENTIFIER ifacebase dictbody ';'"""
+        atts, DICTIONARY, name, base, body, SEMI = p[1:]
+        attlist = atts['attlist']
+        doccomments = []
+        if 'doccomments' in atts:
+            doccomments.extend(atts['doccomments'])
+        doccomments.extend(p.slice[2].doccomments)
+
+        l = lambda: self.getLocation(p, 2)
+
+        p[0] = Dictionary(name=name,
+                          attlist=attlist,
+                          base=base,
+                          members=body,
+                          location=l(),
+                          doccomments=doccomments)
+
+    def p_dictbody(self, p):
+        """dictbody : '{' dictmembers '}'
+                     | """
+        if len(p) > 1:
+            p[0] = p[2]
+
+    def p_dictmembers_start(self, p):
+        """dictmembers : """
+        p[0] = []
+
+    def p_dictmembers_continue(self, p):
+        """dictmembers : dictmember dictmembers"""
+        p[0] = list(p[2])
+        p[0].insert(0, p[1])
+
+    def p_dictmember(self, p):
+        """dictmember : attributes IDENTIFIER IDENTIFIER optdefvalue ';'"""
+        if 'doccomments' in p[1]:
+            doccomments = p[1]['doccomments']
+        else:
+            doccomments = p.slice[2].doccomments
+
+        p[0] = Attribute(type=p[2],
+                         name=p[3],
+                         attlist=p[1]['attlist'],
+                         readonly=False,
+                         defvalue=p[4],
+                         location=self.getLocation(p, 1),
+                         doccomments=doccomments)
+
+    def p_optdefvalue(self, p):
+        """optdefvalue : '=' STRING
+                       | """
+        if len(p) > 1:
+            p[0] = p[2]
+        else:
+            p[0] = None
+
+    def p_identifier(self, p):
+        """identifier : DICTIONARY
+                      | IDENTIFIER"""
+        p[0] = p[1]
+
     def p_raises(self, p):
         """raises : RAISES '(' idlist ')'
                   | """
         if len(p) == 1:
             p[0] = []
         else:
             p[0] = p[3]