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 83324 33473863f42cb9a2f4913f89bac6428b9ace6b4e
parent 83323 c5b90ea7e475e362314174aeb8cbfdf0c7391572
child 83325 0697daa434137c0b12bc3d6b4dfaaec8a6ad7c62
push id4356
push userphilringnalda@gmail.com
push dateSun, 25 Dec 2011 05:53:32 +0000
treeherdermozilla-inbound@798b00a6fe29 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, mrbkap
bugs709569
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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)
+