Bug 709569, a tool for webidl dictionary-like interfaces, r=khuey,mrbkap
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sat, 24 Dec 2011 00:13:46 +0200
changeset 84468 33473863f42cb9a2f4913f89bac6428b9ace6b4e
parent 84467 c5b90ea7e475e362314174aeb8cbfdf0c7391572
child 84469 0697daa434137c0b12bc3d6b4dfaaec8a6ad7c62
push idunknown
push userunknown
push dateunknown
reviewerskhuey, mrbkap
bugs709569
milestone12.0a1
Bug 709569, a tool for webidl dictionary-like interfaces, r=khuey,mrbkap
content/events/src/nsDOMCloseEvent.cpp
content/events/src/nsDOMCloseEvent.h
content/events/src/nsDOMCustomEvent.cpp
content/events/src/nsDOMCustomEvent.h
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMHashChangeEvent.cpp
content/events/src/nsDOMHashChangeEvent.h
content/events/src/nsDOMMouseEvent.cpp
content/events/src/nsDOMMouseEvent.h
content/events/src/nsDOMPageTransitionEvent.cpp
content/events/src/nsDOMPageTransitionEvent.h
content/events/src/nsDOMPopStateEvent.cpp
content/events/src/nsDOMPopStateEvent.h
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/events/test/test_eventctors.html
js/xpconnect/src/Makefile.in
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/dictionary_helper_gen.conf
js/xpconnect/src/dictionary_helper_gen.py
--- a/content/events/src/nsDOMCloseEvent.cpp
+++ b/content/events/src/nsDOMCloseEvent.cpp
@@ -33,16 +33,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMCloseEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_ADDREF_INHERITED(nsDOMCloseEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMCloseEvent, nsDOMEvent)
 
 DOMCI_DATA(CloseEvent, nsDOMCloseEvent)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMCloseEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCloseEvent)
@@ -84,41 +85,24 @@ nsDOMCloseEvent::InitCloseEvent(const ns
   mWasClean = aWasClean;
   mReasonCode = aReasonCode;
   mReason = aReason;
 
   return NS_OK;
 }
 
 nsresult
-nsDOMCloseEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                              JSContext* aCx, JSObject* aObj)
+nsDOMCloseEvent::InitFromCtor(const nsAString& aType,
+                              JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsICloseEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  bool wasClean = false;
-  PRUint16 code = 0;
-  nsAutoString reason;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetWasClean(&wasClean);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCode(&code);
-    NS_ENSURE_SUCCESS(rv, rv);
-    JSBool found = JS_FALSE;
-    if (JS_HasProperty(aCx, aObj, "reason", &found) && found) {
-      rv = eventInit->GetReason(reason);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-  return InitCloseEvent(aType, bubbles, cancelable, wasClean, code, reason);
+  mozilla::dom::CloseEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitCloseEvent(aType, d.bubbles, d.cancelable, d.wasClean, d.code,
+                        d.reason);
 }
 
 nsresult
 NS_NewDOMCloseEvent(nsIDOMEvent** aInstancePtrResult,
                     nsPresContext* aPresContext,
                     nsEvent* aEvent) 
 {
   nsDOMCloseEvent* it = new nsDOMCloseEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMCloseEvent.h
+++ b/content/events/src/nsDOMCloseEvent.h
@@ -59,18 +59,17 @@ public:
                      
   NS_DECL_ISUPPORTS_INHERITED
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
   NS_DECL_NSIDOMCLOSEEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsICloseEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 private:
   bool mWasClean;
   PRUint16 mReasonCode;
   nsString mReason;
 };
 
 #endif // nsDOMCloseEvent_h__
--- a/content/events/src/nsDOMCustomEvent.cpp
+++ b/content/events/src/nsDOMCustomEvent.cpp
@@ -32,16 +32,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMCustomEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMCustomEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMCustomEvent, nsDOMEvent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDetail)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMCustomEvent, nsDOMEvent)
@@ -74,32 +75,23 @@ nsDOMCustomEvent::InitCustomEvent(const 
   nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mDetail = aDetail;
   return NS_OK;
 }
 
 nsresult
-nsDOMCustomEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                               JSContext* aCx, JSObject* aObj)
+nsDOMCustomEvent::InitFromCtor(const nsAString& aType,
+                               JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsICustomEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIVariant> detail;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetDetail(getter_AddRefs(detail));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitCustomEvent(aType, bubbles, cancelable, detail);
+  mozilla::dom::CustomEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitCustomEvent(aType, d.bubbles, d.cancelable, d.detail);
 }
 
 nsresult
 NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult,
                      nsPresContext* aPresContext,
                      nsEvent* aEvent) 
 {
   nsDOMCustomEvent* e = new nsDOMCustomEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMCustomEvent.h
+++ b/content/events/src/nsDOMCustomEvent.h
@@ -54,16 +54,15 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMCustomEvent, nsDOMEvent)
 
   NS_DECL_NSIDOMCUSTOMEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsICustomEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 private:
   nsCOMPtr<nsIVariant> mDetail;
 };
 
 #endif // nsDOMCustomEvent_h__
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -57,16 +57,17 @@
 #include "nsMutationEvent.h"
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 #include "nsDOMPopStateEvent.h"
 #include "mozilla/Preferences.h"
 #include "nsJSUtils.h"
+#include "DictionaryHelpers.h"
 
 using namespace mozilla;
 
 static const char* const sEventNames[] = {
   "mousedown", "mouseup", "click", "dblclick", "mouseenter", "mouseleave", "mouseover",
   "mouseout", "MozMouseHittest", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
   "focus", "blur", "load", "popstate", "beforescriptexecute",
   "afterscriptexecute", "beforeunload", "unload",
@@ -404,46 +405,32 @@ nsDOMEvent::Initialize(nsISupports* aOwn
   if (!jsstr) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   JS::Anchor<JSString*> deleteProtector(jsstr);
 
   nsDependentJSString type;
   NS_ENSURE_STATE(type.init(aCx, jsstr));
-  
-  nsCOMPtr<nsISupports> dict;
-  JSObject* obj = nsnull;
-  if (aArgc >= 2 && !JSVAL_IS_PRIMITIVE(aArgv[1])) {
-    obj = JSVAL_TO_OBJECT(aArgv[1]);
-    nsContentUtils::XPConnect()->WrapJS(aCx, obj,
-                                        EventInitIID(),
-                                        getter_AddRefs(dict));
-  }
-  nsresult rv = InitFromCtor(type, dict, aCx, obj);
+
+  nsresult rv = InitFromCtor(type, aCx, aArgc >= 2 ? &(aArgv[1]) : nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
 
   SetTrusted(trusted);
   return NS_OK;
 }
 
 nsresult
-nsDOMEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                         JSContext* aCx, JSObject* aObj)
+nsDOMEvent::InitFromCtor(const nsAString& aType,
+                         JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitEvent(aType, bubbles, cancelable);
+  mozilla::dom::EventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitEvent(aType, d.bubbles, d.cancelable);
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetEventPhase(PRUint16* aEventPhase)
 {
   // Note, remember to check that this works also
   // if or when Bug 235441 is fixed.
   if (mEvent->currentTarget == mEvent->target ||
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -222,19 +222,18 @@ public:
   NS_IMETHOD_(bool)    IsDispatchStopped();
   NS_IMETHOD_(nsEvent*)    GetInternalNSEvent();
   NS_IMETHOD    SetTrusted(bool aTrusted);
 
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
                         PRUint32 aArgc, jsval* aArgv);
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 
   void InitPresContextData(nsPresContext* aPresContext);
 
   virtual void Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType);
   virtual bool Deserialize(const IPC::Message* aMsg, void** aIter);
 
   static PopupControlState GetEventPopupControlState(nsEvent *aEvent);
 
--- a/content/events/src/nsDOMHashChangeEvent.cpp
+++ b/content/events/src/nsDOMHashChangeEvent.cpp
@@ -29,16 +29,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMHashChangeEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_ADDREF_INHERITED(nsDOMHashChangeEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMHashChangeEvent, nsDOMEvent)
 
 DOMCI_DATA(HashChangeEvent, nsDOMHashChangeEvent)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMHashChangeEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMHashChangeEvent)
@@ -74,41 +75,23 @@ nsDOMHashChangeEvent::InitHashChangeEven
   NS_ENSURE_SUCCESS(rv, rv);
 
   mOldURL.Assign(aOldURL);
   mNewURL.Assign(aNewURL);
   return NS_OK;
 }
 
 nsresult
-nsDOMHashChangeEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                   JSContext* aCx, JSObject* aObj)
+nsDOMHashChangeEvent::InitFromCtor(const nsAString& aType,
+                                   JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIHashChangeEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsAutoString oldURL;
-  nsAutoString newURL;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    JSBool found = JS_FALSE;
-    if (JS_HasProperty(aCx, aObj, "oldURL", &found) && found) {
-      rv = eventInit->GetOldURL(oldURL);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    found = JS_FALSE;
-    if (JS_HasProperty(aCx, aObj, "newURL", &found) && found) {
-      rv = eventInit->GetNewURL(newURL);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-  return InitHashChangeEvent(aType, bubbles, cancelable, oldURL, newURL);
+  mozilla::dom::HashChangeEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitHashChangeEvent(aType, d.bubbles, d.cancelable, d.oldURL, d.newURL);
 }
 
 nsresult NS_NewDOMHashChangeEvent(nsIDOMEvent** aInstancePtrResult,
                                 nsPresContext* aPresContext,
                                 nsEvent* aEvent)
 {
   nsDOMHashChangeEvent* event =
     new nsDOMHashChangeEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMHashChangeEvent.h
+++ b/content/events/src/nsDOMHashChangeEvent.h
@@ -53,17 +53,16 @@ public:
 
   virtual ~nsDOMHashChangeEvent();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMHASHCHANGEEVENT
 
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIHashChangeEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   nsString mOldURL;
   nsString mNewURL;
 };
 
 #endif // nsDOMHashChangeEvent_h__
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMMouseEvent.h"
 #include "nsGUIEvent.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 nsDOMMouseEvent::nsDOMMouseEvent(nsPresContext* aPresContext,
                                  nsInputEvent* aEvent)
   : nsDOMUIEvent(aPresContext, aEvent ? aEvent :
                  new nsMouseEvent(false, 0, nsnull,
                                   nsMouseEvent::eReal))
 {
   // There's no way to make this class' ctor allocate an nsMouseScrollEvent.
@@ -140,68 +141,27 @@ nsDOMMouseEvent::InitMouseEvent(const ns
     default:
        break;
   }
 
   return NS_OK;
 }   
 
 nsresult
-nsDOMMouseEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                              JSContext* aCx, JSObject* aObj)
+nsDOMMouseEvent::InitFromCtor(const nsAString& aType,
+                              JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIMouseEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIDOMWindow> view;
-  PRInt32 detail = 0;
-  PRInt32 screenX = 0;
-  PRInt32 screenY = 0;
-  PRInt32 clientX = 0;
-  PRInt32 clientY = 0;
-  bool ctrl = false;
-  bool alt = false;
-  bool shift = false;
-  bool meta = false;
-  PRUint16 button = 0;
-  nsCOMPtr<nsIDOMEventTarget> relatedTarget;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetView(getter_AddRefs(view));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetDetail(&detail);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetScreenX(&screenX);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetScreenY(&screenY);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetClientX(&clientX);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetClientY(&clientY);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCtrlKey(&ctrl);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetShiftKey(&shift);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetAltKey(&alt);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetMetaKey(&meta);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetButton(&button);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetRelatedTarget(getter_AddRefs(relatedTarget));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitMouseEvent(aType, bubbles, cancelable,
-                        view, detail, screenX, screenY, clientX, clientY, 
-                        ctrl, alt, shift, meta,
-                        button, relatedTarget);
+  mozilla::dom::MouseEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitMouseEvent(aType, d.bubbles, d.cancelable,
+                        d.view, d.detail, d.screenX, d.screenY,
+                        d.clientX, d.clientY, 
+                        d.ctrlKey, d.altKey, d.shiftKey, d.metaKey,
+                        d.button, d.relatedTarget);
 }
 
 NS_IMETHODIMP
 nsDOMMouseEvent::InitNSMouseEvent(const nsAString & aType, bool aCanBubble, bool aCancelable,
                                   nsIDOMWindow *aView, PRInt32 aDetail, PRInt32 aScreenX,
                                   PRInt32 aScreenY, PRInt32 aClientX, PRInt32 aClientY,
                                   bool aCtrlKey, bool aAltKey, bool aShiftKey,
                                   bool aMetaKey, PRUint16 aButton, nsIDOMEventTarget *aRelatedTarget,
--- a/content/events/src/nsDOMMouseEvent.h
+++ b/content/events/src/nsDOMMouseEvent.h
@@ -55,19 +55,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMMouseEvent Interface
   NS_DECL_NSIDOMMOUSEEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMUIEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIMouseEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   // Specific implementation for a mouse event.
   virtual nsresult Which(PRUint32* aWhich);
 };
 
 #define NS_FORWARD_TO_NSDOMMOUSEEVENT         \
   NS_FORWARD_NSIDOMMOUSEEVENT(nsDOMMouseEvent::) \
   NS_FORWARD_TO_NSDOMUIEVENT
--- a/content/events/src/nsDOMPageTransitionEvent.cpp
+++ b/content/events/src/nsDOMPageTransitionEvent.cpp
@@ -33,16 +33,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMPageTransitionEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 DOMCI_DATA(PageTransitionEvent, nsDOMPageTransitionEvent)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMPageTransitionEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMPageTransitionEvent)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PageTransitionEvent)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
 
@@ -65,32 +66,23 @@ nsDOMPageTransitionEvent::InitPageTransi
   nsresult rv = nsDOMEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mPersisted = aPersisted;
   return NS_OK;
 }
 
 nsresult
-nsDOMPageTransitionEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                       JSContext* aCx, JSObject* aObj)
+nsDOMPageTransitionEvent::InitFromCtor(const nsAString& aType,
+                                       JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIPageTransitionEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  bool persisted = false;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetPersisted(&persisted);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitPageTransitionEvent(aType, bubbles, cancelable, persisted);
+  mozilla::dom::PageTransitionEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitPageTransitionEvent(aType, d.bubbles, d.cancelable, d.persisted);
 }
 
 nsresult NS_NewDOMPageTransitionEvent(nsIDOMEvent** aInstancePtrResult,
                                       nsPresContext* aPresContext,
                                       nsEvent *aEvent) 
 {
   nsDOMPageTransitionEvent* it =
     new nsDOMPageTransitionEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMPageTransitionEvent.h
+++ b/content/events/src/nsDOMPageTransitionEvent.h
@@ -51,16 +51,15 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMPAGETRANSITIONEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIPageTransitionEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   bool mPersisted;
 };
 
 #endif // nsDOMPageTransitionEvent_h__
--- a/content/events/src/nsDOMPopStateEvent.cpp
+++ b/content/events/src/nsDOMPopStateEvent.cpp
@@ -32,16 +32,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMPopStateEvent.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIClassInfo.h"
 #include "nsIXPCScriptable.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMPopStateEvent)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mState)
@@ -79,32 +80,23 @@ nsDOMPopStateEvent::InitPopStateEvent(co
   nsresult rv = nsDOMEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mState = aStateArg;
   return NS_OK;
 }
 
 nsresult
-nsDOMPopStateEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                 JSContext* aCx, JSObject* aObj)
+nsDOMPopStateEvent::InitFromCtor(const nsAString& aType,
+                                 JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIPopStateEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIVariant> state;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetState(getter_AddRefs(state));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitPopStateEvent(aType, bubbles, cancelable, state);
+  mozilla::dom::PopStateEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitPopStateEvent(aType, d.bubbles, d.cancelable, d.state);
 }
 
 nsresult NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult,
                                 nsPresContext* aPresContext,
                                 nsEvent* aEvent)
 {
   nsDOMPopStateEvent* event =
     new nsDOMPopStateEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMPopStateEvent.h
+++ b/content/events/src/nsDOMPopStateEvent.h
@@ -55,16 +55,15 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
 
   NS_DECL_NSIDOMPOPSTATEEVENT
 
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIPopStateEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   nsCOMPtr<nsIVariant> mState;
 };
 
 #endif // nsDOMPopStateEvent_h__
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -46,16 +46,17 @@
 #include "nsIDOMWindow.h"
 #include "nsIDOMNode.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
 #include "nsEventStateManager.h"
 #include "nsIFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
+#include "DictionaryHelpers.h"
 
 nsDOMUIEvent::nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent)
   : nsDOMEvent(aPresContext, aEvent ?
                static_cast<nsEvent *>(aEvent) :
                static_cast<nsEvent *>(new nsUIEvent(false, 0, 0)))
   , mClientPoint(0, 0), mLayerPoint(0, 0), mPagePoint(0, 0)
 {
   if (aEvent) {
@@ -201,35 +202,23 @@ nsDOMUIEvent::InitUIEvent(const nsAStrin
   
   mDetail = detailArg;
   mView = viewArg;
 
   return NS_OK;
 }
 
 nsresult
-nsDOMUIEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                           JSContext* aCx, JSObject* aObj)
+nsDOMUIEvent::InitFromCtor(const nsAString& aType,
+                           JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIUIEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIDOMWindow> view;
-  PRInt32 detail = 0;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetView(getter_AddRefs(view));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetDetail(&detail);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitUIEvent(aType, bubbles, cancelable, view, detail);
+  mozilla::dom::UIEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitUIEvent(aType, d.bubbles, d.cancelable, d.view, d.detail);
 }
 
 // ---- nsDOMNSUIEvent implementation -------------------
 nsIntPoint
 nsDOMUIEvent::GetPagePoint()
 {
   if (mPrivateDataDuplicated) {
     return mPagePoint;
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -59,19 +59,18 @@ public:
   virtual void Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType);
   virtual bool Deserialize(const IPC::Message* aMsg, void** aIter);
   
   // Forward to nsDOMEvent
   NS_FORWARD_TO_NSDOMEVENT
 
   NS_FORWARD_NSIDOMNSEVENT(nsDOMEvent::)
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIUIEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   // Internal helper functions
   nsIntPoint GetClientPoint();
   nsIntPoint GetScreenPoint();
   nsIntPoint GetLayerPoint();
   nsIntPoint GetPagePoint();
 
   // Allow specializations.
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -28,16 +28,42 @@ var ex = false;
 try {
   e = new Event();
 } catch(exp) {
   ex = true;
 }
 ok(ex, "First parameter is required!");
 ex = false;
 
+try {
+  e = new Event("foo", 123);
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+try {
+  e = new Event("foo", "asdf");
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+
+try {
+  e = new Event("foo", false);
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+
 e = new Event("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!");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
@@ -89,21 +115,16 @@ ok(!e.bubbles, "Event shouldn't bubble!"
 ok(!e.cancelable, "Event shouldn't be cancelable!");
 
 var dict = { get detail() { return document.body } };
 e = new CustomEvent("hello", dict);
 is(e.detail, dict.detail, "Wrong event.detail!");
 ok(!e.bubbles, "Event shouldn't bubble!");
 ok(!e.cancelable, "Event shouldn't be cancelable!");
 
-e = new CustomEvent("hello", 1234);
-is(e.detail, null, "Wrong event.detail!");
-ok(!e.bubbles, "Event shouldn't bubble!");
-ok(!e.cancelable, "Event shouldn't be cancelable!");
-
 var dict = { get detail() { throw "foo"; } };
 
 try {
   e = new CustomEvent("hello", dict);
 } catch (exp) {
   ex = true;
 }
 ok(ex, "Should have thrown an exception!");
--- a/js/xpconnect/src/Makefile.in
+++ b/js/xpconnect/src/Makefile.in
@@ -81,16 +81,17 @@ CPPSRCS		= \
 		XPCWrappedNativeJSOps.cpp \
 		XPCWrappedNativeProto.cpp \
 		XPCWrappedNativeScope.cpp \
 		XPCJSWeakReference.cpp \
 		XPCWrapper.cpp \
 		XPCQuickStubs.cpp \
 		dom_quickstubs.cpp \
 		dombindings.cpp \
+		DictionaryHelpers.cpp \
 		$(NULL)
 
 include $(topsrcdir)/config/config.mk
 
 LOCAL_INCLUDES = \
 		-I$(srcdir)/../wrappers \
 		-I$(srcdir)/../loader \
 		-I$(topsrcdir)/js/src \
@@ -186,23 +187,68 @@ dombindings_gen.cpp: $(srcdir)/dombindin
 	  -I$(topsrcdir)/xpcom/idl-parser \
 	  $(srcdir)/dombindingsgen.py \
 	  --idlpath=$(DEPTH)/dist/idl \
 	  --cachedir=$(DEPTH)/xpcom/idl-parser/cache \
 	  --stub-output dombindings_gen.cpp \
 	  --makedepend-output $(MDDEPDIR)/dombindingsgen.pp \
 	  $(srcdir)/dombindings.conf
 
+DictionaryHelpers.$(OBJ_SUFFIX): DictionaryHelpers.h \
+                                 DictionaryHelpers.cpp
+
+DictionaryHelpers.h: $(srcdir)/dictionary_helper_gen.conf \
+                     $(srcdir)/dictionary_helper_gen.py \
+                     $(srcdir)/codegen.py \
+                     $(topsrcdir)/xpcom/idl-parser/header.py \
+                     $(topsrcdir)/xpcom/idl-parser/xpidl.py \
+                     $(DEPTH)/js/src/js-confdefs.h
+	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/other-licenses/ply \
+	  -I$(topsrcdir)/xpcom/idl-parser \
+	  $(srcdir)/dictionary_helper_gen.py \
+	  -I $(DEPTH)/dist/idl \
+	  --cachedir=$(DEPTH)/xpcom/idl-parser/cache \
+	  --header-output DictionaryHelpers.h \
+	  $(srcdir)/dictionary_helper_gen.conf
+
+DictionaryHelpers.cpp: $(srcdir)/dictionary_helper_gen.conf \
+                       $(srcdir)/dictionary_helper_gen.py \
+                       $(srcdir)/codegen.py \
+                       $(topsrcdir)/xpcom/idl-parser/header.py \
+                       $(topsrcdir)/xpcom/idl-parser/xpidl.py \
+                       $(DEPTH)/js/src/js-confdefs.h
+	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/other-licenses/ply \
+	  -I$(topsrcdir)/xpcom/idl-parser \
+	  $(srcdir)/dictionary_helper_gen.py \
+	  -I $(DEPTH)/dist/idl \
+	  --cachedir=$(DEPTH)/xpcom/idl-parser/cache \
+	  --header-output DictionaryHelpers.h \
+	  --stub-output DictionaryHelpers.cpp \
+	  --makedepend-output $(MDDEPDIR)/dictionary_helper_gen.pp \
+	  $(srcdir)/dictionary_helper_gen.conf
+
+_EXTRA_EXPORT_FILES = \
+  DictionaryHelpers.h \
+  $(NULL)
+
+libs:: $(_EXTRA_EXPORT_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/dist/include
+
 GARBAGE += \
 		dom_quickstubs.h \
 		dom_quickstubs.cpp \
 		dombindings_gen.h \
 		dombindings_gen.cpp \
+		DictionaryHelpers.h \
+		DictionaryHelpers.cpp \
 		xpidl_debug \
 		$(MDDEPDIR)/dom_qsgen.pp \
 		$(MDDEPDIR)/dombindingsgen.pp \
+		$(MDDEPDIR)/dictionary_helper_gen.pp \
 		$(wildcard $(topsrcdir)/other-licenses/ply/ply/*.pyc) \
 		$(wildcard $(topsrcdir)/xpcom/idl-parser/*.pyc) \
 		$(NULL)
 
 GARBAGE_DIRS += $(DEPTH)/xpcom/idl-parser/cache
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2305,16 +2305,19 @@ XPCJSRuntime::newXPCJSRuntime(nsXPConnec
     }
 
     NS_RUNTIMEABORT("new XPCJSRuntime failed to initialize.");
 
     delete self;
     return nsnull;
 }
 
+// DefineStaticDictionaryJSVals is automatically generated.
+bool DefineStaticDictionaryJSVals(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;
     if (JSID_IS_VOID(mStrIDs[0])) {
@@ -2330,16 +2333,20 @@ XPCJSRuntime::OnJSContextNew(JSContext *
                     ok = false;
                     break;
                 }
                 mStrJSVals[i] = STRING_TO_JSVAL(str);
             }
         }
 
         ok = mozilla::dom::binding::DefineStaticJSVals(cx);
+        if (!ok)
+            return false;
+        
+        ok = DefineStaticDictionaryJSVals(cx);
     }
     if (!ok)
         return false;
 
     XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
     if (!tls)
         return false;
 
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -0,0 +1,22 @@
+# 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' ]
+   ]
+
+# include file names
+special_includes = [
+    'nsContentUtils.h',
+    'nsIXPConnect.h'
+  ]
+
+# name of the type to not include using #include "typename.h"
+exclude_automatic_type_include = [
+    'nsISupports'
+  ]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/src/dictionary_helper_gen.py
@@ -0,0 +1,440 @@
+#!/usr/bin/env python
+# header.py - Generate C++ header files from IDL.
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+#   Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Olli Pettay <Olli.Pettay@helsinki.fi>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+from codegen import *
+import sys, os.path, re, xpidl, itertools
+
+# --makedepend-output support.
+make_dependencies = []
+make_targets = []
+
+def strip_begin(text, suffix):
+    if not text.startswith(suffix):
+        return text
+    return text[len(suffix):]
+
+def strip_end(text, suffix):
+    if not text.endswith(suffix):
+        return text
+    return text[:-len(suffix)]
+
+# Copied from dombindingsgen.py
+def writeMakeDependOutput(filename):
+    print "Creating makedepend file", filename
+    f = open(filename, 'w')
+    try:
+        if len(make_targets) > 0:
+            f.write("%s:" % makeQuote(make_targets[0]))
+            for filename in make_dependencies:
+                f.write(' \\\n\t\t%s' % makeQuote(filename))
+            f.write('\n\n')
+            for filename in make_targets[1:]:
+                f.write('%s: %s\n' % (makeQuote(filename), makeQuote(make_targets[0])))
+    finally:
+        f.close()
+
+def findIDL(includePath, interfaceFileName):
+    for d in includePath:
+        # Not os.path.join: we need a forward slash even on Windows because
+        # this filename ends up in makedepend output.
+        path = d + '/' + interfaceFileName
+        if os.path.exists(path):
+            return path
+    raise BaseException("No IDL file found for interface %s "
+                        "in include path %r"
+                        % (interfaceFileName, includePath))
+
+def loadIDL(parser, includePath, filename):
+    if not filename in make_dependencies:
+        make_dependencies.append(filename)
+    idl = p.parse(open(findIDL(includePath, filename)).read(), filename)
+    idl.resolve(includePath, p)
+    return idl
+
+class Configuration:
+    def __init__(self, filename):
+        config = {}
+        execfile(filename, config)
+        self.dictionaries = config.get('dictionaries', [])
+        self.special_includes = config.get('special_includes', [])
+        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:
+            interfaces = []
+            base = p.base
+            baseiface = p.idl.getName(p.base, p.location)
+            while base != "nsISupports" and not base in dicts:
+                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)
+
+def print_header_file(fd, conf):
+    fd.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
+             "#ifndef _gen_mozilla_idl_dictionary_helpers_h_\n"
+             "#define _gen_mozilla_idl_dictionary_helpers_h_\n\n")
+
+    fd.write("#include \"jsapi.h\"\n"
+             "#include \"nsString.h\"\n"
+             "#include \"nsCOMPtr.h\"\n\n")
+
+    forwards = []
+    attrnames = []
+    for d in conf.dictionaries:
+        idl = loadIDL(p, options.incdirs, d[1])
+        collect_names_and_non_primitive_attribute_types(idl, d[0], attrnames, forwards)
+    
+    for c in forwards:
+        fd.write("class %s;\n" % c)
+
+
+    fd.write("\n"
+             "namespace mozilla {\n"
+             "namespace dom {\n\n")
+
+    dicts = []
+    for d in conf.dictionaries:
+        if not d[0] in set(dicts):
+            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:
+            interfaces = []
+            base = p.base
+            baseiface = p.idl.getName(p.base, p.location)
+            while base != "nsISupports":
+                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):
+    for member in iface.members:
+        if isinstance(member, xpidl.Attribute):
+            if not member.name in attrnames:
+                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:
+            interfaces = []
+            base = p.base
+            baseiface = p.idl.getName(p.base, p.location)
+            while base != "nsISupports" and not base in dicts:
+                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)
+
+def get_jsid(name):
+    return ("gDictionary_id_%s" % name)
+
+def print_cpp_file(fd, conf):
+    fd.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n")
+    fd.write('#include "DictionaryHelpers.h"\n')
+
+    includes = []
+    for s in conf.special_includes:
+        if not s in includes:
+            includes.append(strip_end(s, ".h"))
+    
+    for d in conf.dictionaries:
+        if not d[1] in includes:
+            includes.append(strip_end(d[1], ".idl"))
+
+    attrnames = []
+    for d in conf.dictionaries:
+        idl = loadIDL(p, options.incdirs, d[1])
+        collect_names_and_non_primitive_attribute_types(idl, d[0], attrnames, includes)
+    
+    for c in includes:
+      if not c in conf.exclude_automatic_type_include:
+            fd.write("#include \"%s.h\"\n" % c)
+
+    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"
+             "{\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"
+             "{\n"
+             "  JSAutoRequest ar(aCx);\n"
+             "  return\n")
+    for a in attrnames:
+        fd.write("    DefineStaticJSVal(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"
+
+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("\n{\npublic:\n")
+    fd.write("  %s()" % dict_name(iface.name))
+
+    if iface.base != "nsISupports" or len(attributes) > 0:
+        fd.write(" :\n")
+    
+    if iface.base != "nsISupports":
+        fd.write("    %s()" % dict_name(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("  // 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_cpp(iface, fd):
+    attributes = []
+    for member in iface.members:
+        if isinstance(member, xpidl.Attribute):
+            attributes.append(member)
+
+    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("{\n")
+    if iface.base != "nsISupports":
+        fd.write("  nsresult rv = %s_InitInternal(aDict, aIfaceObject, aCx, aObj);\n" %
+                 dict_name(iface.base))
+        fd.write("  NS_ENSURE_SUCCESS(rv, rv);\n")
+
+    fd.write("  JSBool found = PR_FALSE;\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")
+        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("{\n"
+             "  if (!aCx || !aVal) {\n"
+             "    return NS_OK;\n"
+             "  }\n"
+             "  NS_ENSURE_STATE(JSVAL_IS_OBJECT(*aVal));\n\n"
+             "  JSObject* obj = JSVAL_TO_OBJECT(*aVal);\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))
+
+
+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",
+                 type='string', dest='stub_output', default=None,
+                 help="Quick stub C++ source output file", metavar="FILE")
+    o.add_option('--header-output', type='string', default=None,
+                 help="Quick stub header output file", metavar="FILE")
+    o.add_option('--makedepend-output', type='string', default=None,
+                 help="gnumake dependencies output file", metavar="FILE")
+    o.add_option('--cachedir', dest='cachedir', default='',
+                 help="Directory in which to cache lex/parse tables.")
+    (options, filenames) = o.parse_args()
+    if len(filenames) != 1:
+        o.error("Exactly one config filename is needed.")
+    filename = filenames[0]
+
+    if options.cachedir is not None:
+        if not os.path.isdir(options.cachedir):
+            os.mkdir(options.cachedir)
+        sys.path.append(options.cachedir)
+
+    # Instantiate the parser.
+    p = xpidl.IDLParser(outputdir=options.cachedir)
+
+    conf = readConfigFile(filename)
+
+    if options.header_output is not None:
+        outfd = open(options.header_output, 'w')
+        print_header_file(outfd, conf)
+        outfd.close()
+    if options.stub_output is not None:
+        make_targets.append(options.stub_output)
+        outfd = open(options.stub_output, 'w')
+        print_cpp_file(outfd, conf)
+        outfd.close()
+        if options.makedepend_output is not None:
+            writeMakeDependOutput(options.makedepend_output)
+