bug 607767 - Fix rewrapping native objects across compartment boundaries. r=jst
authorBlake Kaplan <mrbkap@gmail.com>
Fri, 29 Oct 2010 12:49:32 -0700
changeset 56818 9ec3b67b2fd7e240ed424abf036d57a8ddabaa22
parent 56817 9ec91c8f9b8e6801515668c4835ae0b446c2c92a
child 56819 addeb77512a8883bd930e41bca0907c86914b10e
push idunknown
push userunknown
push dateunknown
reviewersjst
bugs607767
milestone2.0b8pre
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 607767 - Fix rewrapping native objects across compartment boundaries. r=jst
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsHistory.h
js/src/xpconnect/idl/nsIXPCScriptable.idl
js/src/xpconnect/public/xpc_map_end.h
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcwrappednativejsops.cpp
js/src/xpconnect/wrappers/WrapperFactory.cpp
toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_580030_errors_after_page_reload.js
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -69,16 +69,17 @@
 #include "nsTArray.h"
 #include "nsCSSValue.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "nsDOMEventTargetWrapperCache.h"
 
 // General helper includes
 #include "nsGlobalWindow.h"
+#include "nsHistory.h"
 #include "nsIContent.h"
 #include "nsIAttribute.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOM3Document.h"
 #include "nsIDOMXMLDocument.h"
 #include "nsIDOMNSDocument.h"
 #include "nsIDOMEvent.h"
@@ -656,17 +657,18 @@ static nsDOMClassInfoData sClassInfoData
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MimeType, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MimeTypeArray, nsMimeTypeArraySH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(BarProp, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(History, nsHistorySH,
-                           ARRAY_SCRIPTABLE_FLAGS)
+                           ARRAY_SCRIPTABLE_FLAGS |
+                           nsIXPCScriptable::WANT_PRECREATE)
   NS_DEFINE_CLASSINFO_DATA(Screen, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DOMPrototype, nsDOMConstructorSH,
                            DOM_BASE_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_HASINSTANCE |
                            nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
   NS_DEFINE_CLASSINFO_DATA(DOMConstructor, nsDOMConstructorSH,
                            DOM_BASE_SCRIPTABLE_FLAGS |
@@ -4577,25 +4579,16 @@ NS_IMETHODIMP
 nsDOMClassInfo::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                             JSObject * obj, JSObject * *_retval)
 {
   NS_WARNING("nsDOMClassInfo::OuterObject Don't call me!");
 
   return NS_ERROR_UNEXPECTED;
 }
 
-NS_IMETHODIMP
-nsDOMClassInfo::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
-                            JSObject * obj, JSObject * *_retval)
-{
-  NS_WARNING("nsDOMClassInfo::InnerObject Don't call me!");
-
-  return NS_ERROR_UNEXPECTED;
-}
-
 static nsresult
 GetExternalClassInfo(nsScriptNameSpaceManager *aNameSpaceManager,
                      const nsString &aName,
                      const nsGlobalNameStruct *aStruct,
                      const nsGlobalNameStruct **aResult)
 {
   NS_ASSERTION(aStruct->mType ==
                  nsGlobalNameStruct::eTypeExternalClassInfoCreator,
@@ -7092,17 +7085,17 @@ nsLocationSH::PreCreate(nsISupports *nat
   if (!ds) {
     NS_WARNING("Refusing to create a location in the wrong scope");
     return NS_ERROR_UNEXPECTED;
   }
 
   nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(ds);
   if (!sgo) {
     NS_WARNING("Refusing to create a location in the wrong scope because the "
-	       "docshell is being destroyed");
+               "docshell is being destroyed");
     return NS_ERROR_UNEXPECTED;
   }
 
   *parentObj = sgo->GetGlobalJSObject();
   return NS_OK;
 }
 
 // DOM Navigator helper
@@ -9910,39 +9903,48 @@ nsStringArraySH::GetProperty(nsIXPConnec
 
   return NS_SUCCESS_I_DID_SOMETHING;
 }
 
 
 // History helper
 
 NS_IMETHODIMP
+nsHistorySH::PreCreate(nsISupports *nativeObj, JSContext *cx,
+                       JSObject *globalObj, JSObject **parentObj)
+{
+  nsHistory *history = (nsHistory *)nativeObj;
+  nsIDocShell *ds = history->GetDocShell();
+  if (!ds) {
+    NS_WARNING("Refusing to create a history object in the wrong scope");
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(ds);
+  if (!sgo) {
+    NS_WARNING("Refusing to create a history object in the wrong scope because the "
+               "docshell is being destroyed");
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  *parentObj = sgo->GetGlobalJSObject();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsHistorySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, PRBool *_retval)
 {
   PRBool is_number = PR_FALSE;
   GetArrayIndexFromId(cx, id, &is_number);
 
   if (!is_number) {
     return NS_OK;
   }
 
-  nsresult rv =
-    sSecMan->CheckPropertyAccess(cx, obj, mData->mName, sItem_id,
-                                 nsIXPCSecurityManager::ACCESS_CALL_METHOD);
-
-  if (NS_FAILED(rv)) {
-    // Let XPConnect know that the access was not granted.
-    *_retval = PR_FALSE;
-
-    return NS_OK;
-  }
-
-  // sec check
-
   return nsStringArraySH::GetProperty(wrapper, cx, obj, id, vp, _retval);
 }
 
 nsresult
 nsHistorySH::GetStringAt(nsISupports *aNative, PRInt32 aIndex,
                          nsAString& aResult)
 {
   if (aIndex < 0) {
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -1265,16 +1265,18 @@ protected:
   virtual ~nsHistorySH()
   {
   }
 
   virtual nsresult GetStringAt(nsISupports *aNative, PRInt32 aIndex,
                                nsAString& aResult);
 
 public:
+  NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
+                       JSObject *globalObj, JSObject **parentObj);
   NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsHistorySH(aData);
   }
 };
--- a/dom/base/nsHistory.h
+++ b/dom/base/nsHistory.h
@@ -53,16 +53,17 @@ public:
   virtual ~nsHistory();
 
   // nsISupports
   NS_DECL_ISUPPORTS
 
   // nsIDOMHistory
   NS_DECL_NSIDOMHISTORY
 
+  nsIDocShell *GetDocShell() { return mDocShell; }
   void SetDocShell(nsIDocShell *aDocShell);
 
 protected:
   nsresult GetSessionHistoryFromDocShell(nsIDocShell * aDocShell,
                                          nsISHistory ** aReturn);
 
   nsIDocShell* mDocShell;
 };
--- a/js/src/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl
@@ -75,17 +75,17 @@
 
 /**
  * Note: This is not really an XPCOM interface.  For example, callers must
  * guarantee that they set the *_retval of the various methods that return a
  * boolean to PR_TRUE before making the call.  Implementations may skip writing
  * to *_retval unless they want to return PR_FALSE.
  */
 
-[uuid(5d309b93-e9b4-4374-bcd5-44245c83408f)]
+[uuid(a40ce52e-2d8c-400f-9af2-f8784a656070)]
 interface nsIXPCScriptable : nsISupports
 {
     /* bitflags used for 'flags' (only 32 bits available!) */
 
     const PRUint32 WANT_PRECREATE                   = 1 <<  0;
     const PRUint32 WANT_CREATE                      = 1 <<  1;
     const PRUint32 WANT_POSTCREATE                  = 1 <<  2;
     const PRUint32 WANT_ADDPROPERTY                 = 1 <<  3;
@@ -110,17 +110,16 @@ interface nsIXPCScriptable : nsISupports
     const PRUint32 DONT_ASK_INSTANCE_FOR_SCRIPTABLE = 1 << 22;
     const PRUint32 CLASSINFO_INTERFACES_ONLY        = 1 << 23;
     const PRUint32 ALLOW_PROP_MODS_DURING_RESOLVE   = 1 << 24;
     const PRUint32 ALLOW_PROP_MODS_TO_PROTOTYPE     = 1 << 25;
     const PRUint32 DONT_SHARE_PROTOTYPE             = 1 << 26;
     const PRUint32 DONT_REFLECT_INTERFACE_NAMES     = 1 << 27;
     const PRUint32 WANT_EQUALITY                    = 1 << 28;
     const PRUint32 WANT_OUTER_OBJECT                = 1 << 29;
-    const PRUint32 WANT_INNER_OBJECT                = 1 << 30;
 
     // The high order bit is RESERVED for consumers of these flags. 
     // No implementor of this interface should ever return flags 
     // with this bit set.
     const PRUint32 RESERVED                         = 1 << 31;
 
     readonly attribute string   className;
     readonly attribute PRUint32 scriptableFlags;
@@ -192,19 +191,16 @@ interface nsIXPCScriptable : nsISupports
                in JSTracerPtr trc, in JSObjectPtr obj);
 
     PRBool equality(in nsIXPConnectWrappedNative wrapper,
                     in JSContextPtr cx, in JSObjectPtr obj, in jsval val);
 
     JSObjectPtr outerObject(in nsIXPConnectWrappedNative wrapper,
                             in JSContextPtr cx, in JSObjectPtr obj);
 
-    JSObjectPtr innerObject(in nsIXPConnectWrappedNative wrapper,
-                            in JSContextPtr cx, in JSObjectPtr obj);
-
     void postCreatePrototype(in JSContextPtr cx, in JSObjectPtr proto);
 };
 
 %{ C++
 
 #include "nsAutoPtr.h"
 
 #define NS_XPCCLASSINFO_IID \
--- a/js/src/xpconnect/public/xpc_map_end.h
+++ b/js/src/xpconnect/public/xpc_map_end.h
@@ -113,20 +113,16 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::GetScri
     nsIXPCScriptable::WANT_TRACE |
 #endif
 #ifdef XPC_MAP_WANT_EQUALITY
     nsIXPCScriptable::WANT_EQUALITY |
 #endif
 #ifdef XPC_MAP_WANT_OUTER_OBJECT
     nsIXPCScriptable::WANT_OUTER_OBJECT |
 #endif
-#ifdef XPC_MAP_WANT_INNER_OBJECT
-    nsIXPCScriptable::WANT_INNER_OBJECT |
-#endif
-
 #ifdef XPC_MAP_FLAGS
     XPC_MAP_FLAGS |
 #endif
     0;
     return NS_OK;
 }
 
 /**************************************************************/
@@ -222,21 +218,16 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::Equalit
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_OUTER_OBJECT
 NS_IMETHODIMP XPC_MAP_CLASSNAME::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
-#ifndef XPC_MAP_WANT_INNER_OBJECT
-NS_IMETHODIMP XPC_MAP_CLASSNAME::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval)
-    {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
-#endif
-
 #ifndef XPC_MAP_WANT_POST_CREATE_PROTOTYPE
 NS_IMETHODIMP XPC_MAP_CLASSNAME::PostCreatePrototype(JSContext *cx, JSObject *proto)
     {return NS_OK;}
 #endif
 
 /**************************************************************/
 
 #undef XPC_MAP_CLASSNAME
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1999,17 +1999,16 @@ public:
     JSBool WantFinalize()                 GET_IT(WANT_FINALIZE)
     JSBool WantCheckAccess()              GET_IT(WANT_CHECKACCESS)
     JSBool WantCall()                     GET_IT(WANT_CALL)
     JSBool WantConstruct()                GET_IT(WANT_CONSTRUCT)
     JSBool WantHasInstance()              GET_IT(WANT_HASINSTANCE)
     JSBool WantTrace()                    GET_IT(WANT_TRACE)
     JSBool WantEquality()                 GET_IT(WANT_EQUALITY)
     JSBool WantOuterObject()              GET_IT(WANT_OUTER_OBJECT)
-    JSBool WantInnerObject()              GET_IT(WANT_INNER_OBJECT)
     JSBool UseJSStubForAddProperty()      GET_IT(USE_JSSTUB_FOR_ADDPROPERTY)
     JSBool UseJSStubForDelProperty()      GET_IT(USE_JSSTUB_FOR_DELPROPERTY)
     JSBool UseJSStubForSetProperty()      GET_IT(USE_JSSTUB_FOR_SETPROPERTY)
     JSBool DontEnumStaticProps()          GET_IT(DONT_ENUM_STATIC_PROPS)
     JSBool DontEnumQueryInterface()       GET_IT(DONT_ENUM_QUERY_INTERFACE)
     JSBool DontAskInstanceForScriptable() GET_IT(DONT_ASK_INSTANCE_FOR_SCRIPTABLE)
     JSBool ClassInfoInterfacesOnly()      GET_IT(CLASSINFO_INTERFACES_ONLY)
     JSBool AllowPropModsDuringResolve()   GET_IT(ALLOW_PROP_MODS_DURING_RESOLVE)
@@ -2541,20 +2540,20 @@ public:
 
     XPCLock*
     GetLock() const {return IsValid() && HasProto() ?
                                 GetProto()->GetLock() : nsnull;}
 
     XPCNativeSet*
     GetSet() const {XPCAutoLock al(GetLock()); return mSet;}
 
-private:
     void
     SetSet(XPCNativeSet* set) {XPCAutoLock al(GetLock()); mSet = set;}
 
+private:
     inline void
     ExpireWrapper()
         {mMaybeScope = (XPCWrappedNativeScope*)
                        (XPC_SCOPE_WORD(mMaybeScope) | XPC_WRAPPER_EXPIRED);}
 
 public:
 
     XPCNativeScriptableInfo*
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -852,55 +852,16 @@ XPC_WN_OuterObject(JSContext *cx, JSObje
         }
 
         obj = newThis;
     }
 
     return obj;
 }
 
-static JSObject *
-XPC_WN_InnerObject(JSContext *cx, JSObject *obj)
-{
-    XPCWrappedNative *wrapper =
-        static_cast<XPCWrappedNative *>(obj->getPrivate());
-    if(!wrapper)
-    {
-        Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
-
-        return nsnull;
-    }
-
-    if(!wrapper->IsValid())
-    {
-        Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx);
-
-        return nsnull;
-    }
-
-    XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
-    if(si && si->GetFlags().WantInnerObject())
-    {
-        JSObject *newThis;
-        nsresult rv =
-            si->GetCallback()->InnerObject(wrapper, cx, obj, &newThis);
-
-        if(NS_FAILED(rv))
-        {
-            Throw(rv, cx);
-
-            return nsnull;
-        }
-
-        obj = newThis;
-    }
-
-    return obj;
-}
-
 js::Class XPC_WN_NoHelper_JSClass = {
     "XPCWrappedNative_NoHelper",    // name;
     WRAPPER_SLOTS |
     JSCLASS_PRIVATE_IS_NSISUPPORTS |
     JSCLASS_MARK_IS_TRACE, // flags;
 
     /* Mandatory non-null function pointer members. */
     JS_VALUEIFY(js::PropertyOp, XPC_WN_OnlyIWrite_PropertyStub), // addProperty
@@ -920,18 +881,18 @@ js::Class XPC_WN_NoHelper_JSClass = {
     nsnull,                         // construct
     nsnull,                         // xdrObject;
     nsnull,                         // hasInstance
     JS_CLASS_TRACE(XPC_WN_Shared_Trace), // mark/trace
 
     // ClassExtension
     {
         JS_VALUEIFY(js::EqualityOp, XPC_WN_Equality),
-        XPC_WN_OuterObject,
-        XPC_WN_InnerObject,
+        nsnull, // outerObject
+        nsnull, // innerObject
         nsnull, // iteratorObject
         nsnull, // wrappedObject
     },
    
     // ObjectOps
     {
         nsnull, // lookupProperty
         nsnull, // defineProperty
@@ -1584,21 +1545,18 @@ XPCNativeScriptableShared::PopulateJSCla
 
     if(mFlags.WantTrace())
         mJSClass.base.mark = JS_CLASS_TRACE(XPC_WN_Helper_Trace);
     else
         mJSClass.base.mark = JS_CLASS_TRACE(XPC_WN_Shared_Trace);
 
     if(mFlags.WantOuterObject())
         mJSClass.base.ext.outerObject = XPC_WN_OuterObject;
-    if(mFlags.WantInnerObject())
-        mJSClass.base.ext.innerObject = XPC_WN_InnerObject;
 
-    if(!(mFlags & (nsIXPCScriptable::WANT_OUTER_OBJECT |
-                   nsIXPCScriptable::WANT_INNER_OBJECT)))
+    if(!(mFlags & nsIXPCScriptable::WANT_OUTER_OBJECT))
         mCanBeSlim = JS_TRUE;
 }
 
 /***************************************************************************/
 /***************************************************************************/
 
 JSBool
 XPC_WN_CallMethod(JSContext *cx, uintN argc, jsval *vp)
--- a/js/src/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/src/xpconnect/wrappers/WrapperFactory.cpp
@@ -121,20 +121,16 @@ WrapperFactory::PrepareForWrapping(JSCon
 
     XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
 
     // If the object doesn't have classinfo we want to return the same
     // XPCWrappedNative so that we keep the same set of interfaces.
     if (!wn->GetClassInfo())
         return DoubleWrap(cx, obj, flags);
 
-    // We know that DOM objects only allow one object, we can return early.
-    if (wn->HasProto() && wn->GetProto()->ClassIsDOMObject())
-        return DoubleWrap(cx, obj, flags);
-
     XPCCallContext ccx(JS_CALLER, cx, obj);
     if (NATIVE_HAS_FLAG(&ccx, WantPreCreate)) {
         // We have a precreate hook. This object might enforce that we only
         // ever create JS object for it.
         JSObject *originalScope = scope;
         nsresult rv = wn->GetScriptableInfo()->GetCallback()->
             PreCreate(wn->Native(), cx, scope, &scope);
         NS_ENSURE_SUCCESS(rv, DoubleWrap(cx, obj, flags));
@@ -154,23 +150,48 @@ WrapperFactory::PrepareForWrapping(JSCon
 
     // The object we're looking at might allow us to create a new wrapped
     // native in the new scope. Try it and continue wrapping on the
     // possibly-new object.
     JSAutoEnterCompartment ac;
     if (!ac.enter(cx, scope))
         return nsnull;
 
+    // NB: Passing a holder here inhibits slim wrappers under
+    // WrapNativeToJSVal.
+    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     jsval v;
     nsresult rv =
         nsXPConnect::FastGetXPConnect()->WrapNativeToJSVal(cx, scope, wn->Native(), nsnull,
                                                            &NS_GET_IID(nsISupports), PR_FALSE,
-                                                           &v, nsnull);
-    if (NS_SUCCEEDED(rv))
+                                                           &v, getter_AddRefs(holder));
+    if (NS_SUCCEEDED(rv)) {
         obj = JSVAL_TO_OBJECT(v);
+        NS_ASSERTION(IS_WN_WRAPPER(obj), "bad object");
+
+        XPCWrappedNative *newwn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
+        if (newwn->GetSet()->GetInterfaceCount() == 1) {
+            // Some objects claim to implement nsIClassInfo, but don't
+            // actually implement GetInterfaces. In those cases, the
+            // newly-created WN will not have any useful functions or
+            // properties on it. We detect that here and use the old WN's
+            // set on the new wrapper.
+
+#ifdef DEBUG
+            {
+                XPCNativeInterface *iface = newwn->GetSet()->GetInterfaceAt(0);
+                JSString *name = JSID_TO_STRING(iface->GetName());
+                NS_ASSERTION(!strcmp("nsISupports", JS_GetStringBytes(name)), "weird interface");
+            }
+#endif
+
+            newwn->SetSet(wn->GetSet());
+        }
+
+    }
 
     return DoubleWrap(cx, obj, flags);
 }
 
 JSObject *
 WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent,
                        uintN flags)
 {
--- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_580030_errors_after_page_reload.js
+++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_580030_errors_after_page_reload.js
@@ -64,19 +64,19 @@ function testErrorsAfterPageReload(aEven
   browser.removeEventListener(aEvent.type, arguments.callee, true);
 
   // dispatch a click event to the button in the test page and listen for
   // errors.
 
   Services.console.registerListener(consoleObserver);
 
   var button = content.document.querySelector("button").wrappedJSObject;
-  var clickEvent = content.wrappedJSObject.document.createEvent("MouseEvents").wrappedJSObject;
+  var clickEvent = content.document.createEvent("MouseEvents");
   clickEvent.initMouseEvent("click", true, true,
-    content.wrappedJSObject, 0, 0, 0, 0, 0, false, false,
+    content, 0, 0, 0, 0, 0, false, false,
     false, false, 0, null);
 
   executeSoon(function() {
     button.dispatchEvent(clickEvent);
   });
 }
 
 var consoleObserver = {