Bug 548847 - [E10s] forward modal (chrome) dialogs from content to chrome, r=jst
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Mon, 17 May 2010 14:25:22 +0300
changeset 46871 8f48671284853f1e031fbe48de1aed6801de2eaf
parent 46870 51d9b7df8c1dd8135ecf18f8c55e4cde9b386523
child 46872 c8ab59eecb0dfafbc50901589307ffe2bc9a78a1
push idunknown
push userunknown
push dateunknown
reviewersjst
bugs548847
milestone1.9.3a5pre
Bug 548847 - [E10s] forward modal (chrome) dialogs from content to chrome, r=jst
content/base/public/nsIFrameLoader.idl
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
dom/ipc/PContentDialog.ipdl
dom/ipc/PIFrameEmbedding.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/ipdl.mk
dom/ipc/test.xul
embedding/base/Makefile.in
embedding/base/nsIDialogCreator.idl
embedding/components/windowwatcher/src/nsPromptService.cpp
embedding/components/windowwatcher/src/nsWindowWatcher.h
--- a/content/base/public/nsIFrameLoader.idl
+++ b/content/base/public/nsIFrameLoader.idl
@@ -41,17 +41,17 @@
 
 interface nsIDocShell;
 interface nsIURI;
 interface nsIWebProgress;
 interface nsIFrame;
 interface nsIChromeFrameMessageManager;
 interface nsIVariant;
 
-[scriptable, uuid(e511f61f-97db-448a-8b29-a10c470df3fa)]
+[scriptable, uuid(85a7f80b-4a3f-4606-8513-a1c4cced874f)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -119,16 +119,18 @@ interface nsIFrameLoader : nsISupports
    * @see nsIDOMWindowUtils sendKeyEvent.
    */
   void sendCrossProcessKeyEvent(in AString aType,
                                 in long aKeyCode,
                                 in long aCharCode,
                                 in long aModifiers,
                                 [optional] in boolean aPreventDefault);
 
+  attribute boolean delayRemoteDialogs;
+
 };
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
 [scriptable, uuid(5879040e-83e9-40e3-b2bb-5ddf43b76e47)]
 interface nsIFrameLoaderOwner : nsISupports
 {
   /**
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1634,16 +1634,38 @@ nsFrameLoader::SendCrossProcessKeyEvent(
                                 aPreventDefault);
     return NS_OK;
   }
 #endif
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
+nsFrameLoader::GetDelayRemoteDialogs(PRBool* aRetVal)
+{
+  *aRetVal = mDelayRemoteDialogs;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameLoader::SetDelayRemoteDialogs(PRBool aDelay)
+{
+#ifdef MOZ_IPC
+  if (mChildProcess && mDelayRemoteDialogs && !aDelay) {
+    nsRefPtr<nsIRunnable> ev =
+      NS_NewRunnableMethod(mChildProcess,
+                           &mozilla::dom::TabParent::HandleDelayedDialogs);
+    NS_DispatchToCurrentThread(ev);
+  }
+#endif
+  mDelayRemoteDialogs = aDelay;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsFrameLoader::GetCrossProcessObjectWrapper(nsIVariant** cpow)
 {
 #ifdef MOZ_IPC
    nsIXPConnect* xpc;
    nsIThreadJSContextStack* stack;
    JSContext* cx;
    JSObject* global;
  
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -79,16 +79,17 @@ protected:
   nsFrameLoader(nsIContent *aOwner) :
     mOwnerContent(aOwner),
     mDepthTooGreat(PR_FALSE),
     mIsTopLevelContent(PR_FALSE),
     mDestroyCalled(PR_FALSE),
     mNeedsAsyncDestroy(PR_FALSE),
     mInSwap(PR_FALSE)
 #ifdef MOZ_IPC
+    , mDelayRemoteDialogs(PR_FALSE)
     , mRemoteWidgetCreated(PR_FALSE)
     , mRemoteFrame(false)
     , mChildProcess(nsnull)
 #if defined(MOZ_WIDGET_GTK2) || defined(MOZ_WIDGET_QT)
     , mRemoteSocket(nsnull)
 #endif
 #endif
   {}
@@ -185,16 +186,17 @@ private:
   nsIContent *mOwnerContent; // WEAK
   PRPackedBool mDepthTooGreat : 1;
   PRPackedBool mIsTopLevelContent : 1;
   PRPackedBool mDestroyCalled : 1;
   PRPackedBool mNeedsAsyncDestroy : 1;
   PRPackedBool mInSwap : 1;
 
 #ifdef MOZ_IPC
+  PRPackedBool mDelayRemoteDialogs : 1;
   PRPackedBool mRemoteWidgetCreated : 1;
   bool mRemoteFrame;
   // XXX leaking
   nsCOMPtr<nsIObserver> mChildHost;
   mozilla::dom::TabParent* mChildProcess;
 
 #ifdef MOZ_WIDGET_GTK2
   GtkWidget* mRemoteSocket;
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PContentDialog.ipdl
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+
+/* ***** 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 Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 ***** */
+
+include protocol PIFrameEmbedding;
+include "mozilla/TabTypes.h";
+
+namespace mozilla {
+namespace dom {
+
+protocol PContentDialog
+{
+  manager PIFrameEmbedding;
+
+child:
+    __delete__(PRInt32[] aIntParams, nsString[] aStringParams);
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/ipc/PIFrameEmbedding.ipdl
+++ b/dom/ipc/PIFrameEmbedding.ipdl
@@ -38,16 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PContentProcess;
 include protocol PDocumentRenderer;
 include protocol PDocumentRendererShmem;
 include protocol PObjectWrapper;
 include protocol PContextWrapper;
 include protocol PGeolocationRequest;
+include protocol PContentDialog;
 
 include "mozilla/TabTypes.h";
 include "TabMessageUtils.h";
 include "gfxMatrix.h";
 include "mozilla/net/NeckoMessageUtils.h";
 
 using IPC::URI;
 using MagicWindowHandle;
@@ -59,16 +60,17 @@ namespace dom {
 
 rpc protocol PIFrameEmbedding
 {
     manager PContentProcess;
     manages PDocumentRenderer;
     manages PDocumentRendererShmem;
     manages PContextWrapper;
     manages PGeolocationRequest;
+    manages PContentDialog;
 
 child:
     __delete__();
 
 parent:
     /**
      * When child sends this message, parent should move focus to
      * the next or previous focusable element.
@@ -101,16 +103,19 @@ parent:
 
     rpc sendSyncMessageToParent(nsString aMessage, nsString aJSON, PObjectWrapper[] aObjects)
       returns (nsString[] retval);
 
     sendAsyncMessageToParent(nsString aMessage, nsString aJSON);
 
     PGeolocationRequest(URI uri);
 
+    PContentDialog(PRUint32 aType, nsCString aName, nsCString aFeatures,
+                   PRInt32[] aIntParams, nsString[] aStringParams);
+
 child:
     createWidget(MagicWindowHandle parentWidget);
 
     loadURL(nsCString uri);
 
     move(PRUint32 x,
          PRUint32 y,
          PRUint32 width,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -34,16 +34,17 @@
  * 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 "TabChild.h"
 #include "mozilla/dom/PContentProcessChild.h"
 #include "mozilla/jsipc/ContextWrapperChild.h"
+#include "mozilla/dom/PContentDialogChild.h"
 
 #include "nsIWebBrowser.h"
 #include "nsEmbedCID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIBaseWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsThreadUtils.h"
@@ -65,16 +66,17 @@
 #include "nsIDOMClassInfo.h"
 #include "nsIXPCSecurityManager.h"
 #include "nsIJSContextStack.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsScriptLoader.h"
 #include "nsPIWindowRoot.h"
 #include "nsIScriptContext.h"
+#include "nsInterfaceHashtable.h"
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsWeakReference.h"
 
 #ifdef MOZ_WIDGET_QT
 #include <QX11EmbedWidget>
 #include <QGraphicsView>
@@ -96,16 +98,24 @@ ContentListener::HandleEvent(nsIDOMEvent
 {
   RemoteDOMEvent remoteEvent;
   remoteEvent.mEvent = do_QueryInterface(aEvent);
   NS_ENSURE_STATE(remoteEvent.mEvent);
   mTabChild->SendsendEvent(remoteEvent);
   return NS_OK;
 }
 
+class ContentDialogChild : public PContentDialogChild
+{
+public:
+  virtual bool Recv__delete__(const nsTArray<int>& aIntParams,
+                              const nsTArray<nsString>& aStringParams);
+};
+
+
 TabChild::TabChild()
 : mCx(nsnull), mContextWrapper(nsnull), mTabChildGlobal(nsnull)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
 nsresult
 TabChild::Init()
@@ -128,22 +138,34 @@ TabChild::Init()
   mWebNav = do_QueryInterface(webBrowser);
   NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
 
   nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(mWebNav));
   docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
   return NS_OK;
 }
 
-NS_IMPL_ISUPPORTS11(TabChild, nsIWebBrowserChrome, nsIWebBrowserChrome2,
-                    nsIEmbeddingSiteWindow, nsIEmbeddingSiteWindow2,
-                    nsIWebBrowserChromeFocus, nsIInterfaceRequestor,
-                    nsIWindowProvider, nsIWebProgressListener,
-                    nsIWebProgressListener2, nsSupportsWeakReference,
-                    nsITabChild)
+NS_INTERFACE_MAP_BEGIN(TabChild)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebProgressListener2)
+  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
+  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
+  NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
+  NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow2)
+  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
+  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
+  NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
+  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
+  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener2)
+  NS_INTERFACE_MAP_ENTRY(nsSupportsWeakReference)
+  NS_INTERFACE_MAP_ENTRY(nsITabChild)
+  NS_INTERFACE_MAP_ENTRY(nsIDialogCreator)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(TabChild)
+NS_IMPL_RELEASE(TabChild)
 
 NS_IMETHODIMP
 TabChild::SetStatus(PRUint32 aStatusType, const PRUnichar* aStatus)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
@@ -303,16 +325,91 @@ TabChild::ProvideWindow(nsIDOMWindow* aP
     }
 
     nsCOMPtr<nsIDOMWindow> win =
         do_GetInterface(static_cast<TabChild*>(newChild)->mWebNav);
     win.forget(aReturn);
     return NS_OK;
 }
 
+static nsInterfaceHashtable<nsVoidPtrHashKey, nsIDialogParamBlock> gActiveDialogs;
+
+NS_IMETHODIMP
+TabChild::OpenDialog(PRUint32 aType, const nsACString& aName,
+                     const nsACString& aFeatures,
+                     nsIDialogParamBlock* aArguments,
+                     nsIDOMElement* aFrameElement)
+{
+  if (!gActiveDialogs.IsInitialized()) {
+    NS_ENSURE_STATE(gActiveDialogs.Init());
+  }
+  nsTArray<PRInt32> intParams;
+  nsTArray<nsString> stringParams;
+  ParamsToArrays(aArguments, intParams, stringParams);
+  PContentDialogChild* dialog =
+    SendPContentDialogConstructor(aType, nsCString(aName),
+                                  nsCString(aFeatures), intParams, stringParams);
+  NS_ENSURE_STATE(gActiveDialogs.Put(dialog, aArguments));
+  nsIThread *thread = NS_GetCurrentThread();
+  while (gActiveDialogs.GetWeak(dialog)) {
+    if (!NS_ProcessNextEvent(thread)) {
+      break;
+    }
+  }
+  return NS_OK;
+}
+
+bool
+ContentDialogChild::Recv__delete__(const nsTArray<int>& aIntParams,
+                                   const nsTArray<nsString>& aStringParams)
+{
+  nsCOMPtr<nsIDialogParamBlock> params;
+  if (gActiveDialogs.Get(this, getter_AddRefs(params))) {
+    TabChild::ArraysToParams(aIntParams, aStringParams, params);
+    gActiveDialogs.Remove(this);
+  }
+  return true;
+}
+
+void
+TabChild::ParamsToArrays(nsIDialogParamBlock* aParams,
+                         nsTArray<int>& aIntParams,
+                         nsTArray<nsString>& aStringParams)
+{
+  if (aParams) {
+    for (PRInt32 i = 0; i < 8; ++i) {
+      PRInt32 val = 0;
+      aParams->GetInt(i, &val);
+      aIntParams.AppendElement(val);
+    }
+    PRInt32 j = 0;
+    PRUnichar* str = nsnull;
+    while (NS_SUCCEEDED(aParams->GetString(j, &str))) {
+      nsAdoptingString strVal(str);
+      aStringParams.AppendElement(strVal);
+      ++j;
+    }
+  }
+}
+
+void
+TabChild::ArraysToParams(const nsTArray<int>& aIntParams,
+                         const nsTArray<nsString>& aStringParams,
+                         nsIDialogParamBlock* aParams)
+{
+  if (aParams) {
+    for (PRInt32 i = 0; PRUint32(i) < aIntParams.Length(); ++i) {
+      aParams->SetInt(i, aIntParams[i]);
+    }
+    for (PRInt32 j = 0; PRUint32(j) < aStringParams.Length(); ++j) {
+      aParams->SetString(j, aStringParams[j].get());
+    }
+  }
+}
+
 bool
 TabChild::RecvcreateWidget(const MagicWindowHandle& parentWidget)
 {
     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mWebNav);
     if (!baseWindow) {
         NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
         return true;
     }
@@ -662,16 +759,33 @@ TabChild::RecvPDocumentRendererShmemCons
 
     dirtyArea = aMatrix.Transform(dirtyArea);
 
     return PDocumentRendererShmemChild::Send__delete__(__a, dirtyArea.X(), dirtyArea.Y(), 
                                                        dirtyArea.Width(), dirtyArea.Height(),
                                                        aBuf);
 }
 
+PContentDialogChild*
+TabChild::AllocPContentDialog(const PRUint32&,
+                              const nsCString&,
+                              const nsCString&,
+                              const nsTArray<int>&,
+                              const nsTArray<nsString>&)
+{
+  return new ContentDialogChild();
+}
+
+bool
+TabChild::DeallocPContentDialog(PContentDialogChild* aDialog)
+{
+  delete aDialog;
+  return true;
+}
+
 /* The PGeolocationRequestChild actor is implemented by a refcounted
    nsGeolocationRequest, and has an identical lifetime. */
 
 PGeolocationRequestChild*
 TabChild::AllocPGeolocationRequest(const IPC::URI&)
 {
   NS_RUNTIMEABORT("unused");
   return nsnull;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -59,16 +59,18 @@
 #include "jsapi.h"
 #include "nsIXPConnect.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsNetUtil.h"
 #include "nsFrameMessageManager.h"
 #include "nsIScriptContext.h"
 #include "nsDOMEventTargetHelper.h"
+#include "nsIDialogCreator.h"
+#include "nsIDialogParamBlock.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsWeakReference.h"
 #include "nsITabChild.h"
 
 class gfxMatrix;
 
@@ -77,16 +79,17 @@ namespace mozilla {
 namespace jsipc {
 class PContextWrapperChild;
 class ContextWrapperChild;
 }
 
 namespace dom {
 
 class TabChild;
+class PContentDialogChild;
 
 class TabChildGlobal : public nsDOMEventTargetHelper,
                        public nsIContentFrameMessageManager,
                        public nsIScriptObjectPrincipal,
                        public nsIScriptContextPrincipal
 {
 public:
   TabChildGlobal(TabChild* aTabChild);
@@ -145,16 +148,17 @@ protected:
 class TabChild : public PIFrameEmbeddingChild,
                  public nsIWebProgressListener2,
                  public nsIWebBrowserChrome2,
                  public nsIEmbeddingSiteWindow2,
                  public nsIWebBrowserChromeFocus,
                  public nsIInterfaceRequestor,
                  public nsIWindowProvider,
                  public nsSupportsWeakReference,
+                 public nsIDialogCreator,
                  public nsITabChild
 {
 public:
     TabChild();
     virtual ~TabChild();
     bool destroyWidget();
     nsresult Init();
 
@@ -163,16 +167,17 @@ public:
     NS_DECL_NSIWEBPROGRESSLISTENER2
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIEMBEDDINGSITEWINDOW2
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSIWINDOWPROVIDER
+    NS_DECL_NSIDIALOGCREATOR
 
     virtual bool RecvcreateWidget(const MagicWindowHandle& parentWidget);
     virtual bool RecvloadURL(const nsCString& uri);
     virtual bool Recvmove(const PRUint32& x,
                           const PRUint32& y,
                           const PRUint32& width,
                           const PRUint32& height);
     virtual bool Recvactivate();
@@ -205,16 +210,28 @@ public:
             mozilla::ipc::PDocumentRendererChild *__a,
             const PRInt32& x,
             const PRInt32& y,
             const PRInt32& w,
             const PRInt32& h,
             const nsString& bgcolor,
             const PRUint32& flags,
             const bool& flush);
+    virtual PContentDialogChild* AllocPContentDialog(const PRUint32&,
+                                                     const nsCString&,
+                                                     const nsCString&,
+                                                     const nsTArray<int>&,
+                                                     const nsTArray<nsString>&);
+    virtual bool DeallocPContentDialog(PContentDialogChild* aDialog);
+    static void ParamsToArrays(nsIDialogParamBlock* aParams,
+                               nsTArray<int>& aIntParams,
+                               nsTArray<nsString>& aStringParams);
+    static void ArraysToParams(const nsTArray<int>& aIntParams,
+                               const nsTArray<nsString>& aStringParams,
+                               nsIDialogParamBlock* aParams);
 
     virtual PDocumentRendererShmemChild* AllocPDocumentRendererShmem(
             const PRInt32& x,
             const PRInt32& y,
             const PRInt32& w,
             const PRInt32& h,
             const nsString& bgcolor,
             const PRUint32& flags,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -45,25 +45,31 @@
 
 #include "nsIURI.h"
 #include "nsFocusManager.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDOMElement.h"
 #include "nsEventDispatcher.h"
 #include "nsIDOMEventTarget.h"
+#include "nsIWindowWatcher.h"
+#include "nsIDOMWindow.h"
+#include "nsPIDOMWindow.h"
+#include "TabChild.h"
 #include "nsIDOMEvent.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIWebProgressListener2.h"
 #include "nsFrameLoader.h"
 #include "nsNetUtil.h"
 #include "jsarray.h"
 #include "nsContentUtils.h"
 #include "nsGeolocationOOP.h"
 #include "nsIDOMNSHTMLFrameElement.h"
+#include "nsIDialogCreator.h"
+#include "nsThreadUtils.h"
 
 using mozilla::ipc::DocumentRendererParent;
 using mozilla::ipc::DocumentRendererShmemParent;
 using mozilla::dom::ContentProcessParent;
 using mozilla::jsipc::PContextWrapperParent;
 using mozilla::jsipc::ContextWrapperParent;
 
 // The flags passed by the webProgress notifications are 16 bits shifted
@@ -626,10 +632,95 @@ TabParent::GetDOMWindow(nsIDOMWindow **a
 }
 
 NS_IMETHODIMP
 TabParent::GetIsLoadingDocument(PRBool *aIsLoadingDocument)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+PContentDialogParent*
+TabParent::AllocPContentDialog(const PRUint32& aType,
+                               const nsCString& aName,
+                               const nsCString& aFeatures,
+                               const nsTArray<int>& aIntParams,
+                               const nsTArray<nsString>& aStringParams)
+{
+  ContentDialogParent* parent = new ContentDialogParent();
+  nsCOMPtr<nsIDialogParamBlock> params =
+    do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
+  TabChild::ArraysToParams(aIntParams, aStringParams, params);
+  mDelayedDialogs.AppendElement(new DelayedDialogData(parent, aType, aName,
+                                                      aFeatures, params));
+  nsRefPtr<nsIRunnable> ev =
+    NS_NewRunnableMethod(this, &TabParent::HandleDelayedDialogs);
+  NS_DispatchToCurrentThread(ev);
+  return parent;
+}
+
+void
+TabParent::HandleDelayedDialogs()
+{
+  nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
+  nsCOMPtr<nsIDOMWindow> window;
+  nsCOMPtr<nsIContent> frame = do_QueryInterface(mFrameElement);
+  if (frame) {
+    window = do_QueryInterface(frame->GetOwnerDoc()->GetWindow());
+  }
+  nsCOMPtr<nsIDialogCreator> dialogCreator = do_QueryInterface(mBrowserDOMWindow);
+  while (!ShouldDelayDialogs() && mDelayedDialogs.Length()) {
+    PRUint32 index = mDelayedDialogs.Length() - 1;
+    DelayedDialogData* data = mDelayedDialogs[index];
+    mDelayedDialogs.RemoveElementAt(index);
+    nsCOMPtr<nsIDialogParamBlock> params;
+    params.swap(data->mParams);
+    PContentDialogParent* dialog = data->mDialog;
+    if (dialogCreator) {
+      dialogCreator->OpenDialog(data->mType,
+                                data->mName, data->mFeatures,
+                                params, mFrameElement);
+    } else if (ww) {
+      nsCAutoString url;
+      if (data->mType) {
+        if (data->mType == nsIDialogCreator::SELECT_DIALOG) {
+          url.Assign("chrome://global/content/selectDialog.xul");
+        } else if (data->mType == nsIDialogCreator::GENERIC_DIALOG) {
+          url.Assign("chrome://global/content/commonDialog.xul");
+        }
+
+        nsCOMPtr<nsISupports> arguments(do_QueryInterface(params));
+        nsCOMPtr<nsIDOMWindow> dialog;
+        ww->OpenWindow(window, url.get(), data->mName.get(),
+                       data->mFeatures.get(), arguments, getter_AddRefs(dialog));
+      } else {
+        NS_WARNING("unknown dialog types aren't automatically supported in E10s yet!");
+      }
+    }
+
+    delete data;
+    if (dialog) {
+      nsTArray<PRInt32> intParams;
+      nsTArray<nsString> stringParams;
+      TabChild::ParamsToArrays(params, intParams, stringParams);
+      PContentDialogParent::Send__delete__(dialog, intParams, stringParams);
+    }
+  }
+  if (ShouldDelayDialogs() && mDelayedDialogs.Length()) {
+    nsContentUtils::DispatchTrustedEvent(frame->GetOwnerDoc(), frame,
+                                         NS_LITERAL_STRING("MozDelayedModalDialog"),
+                                         PR_TRUE, PR_TRUE);
+  }
+}
+
+PRBool
+TabParent::ShouldDelayDialogs()
+{
+  nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(mFrameElement);
+  NS_ENSURE_TRUE(frameLoaderOwner, PR_TRUE);
+  nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
+  NS_ENSURE_TRUE(frameLoader, PR_TRUE);
+  PRBool delay = PR_FALSE;
+  frameLoader->GetDelayRemoteDialogs(&delay);
+  return delay;
+}
+
 } // namespace tabs
 } // namespace mozilla
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -35,25 +35,26 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/dom/PIFrameEmbeddingParent.h"
-
+#include "mozilla/dom/PContentDialogParent.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 
 #include "jsapi.h"
 #include "nsCOMPtr.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsWeakReference.h"
+#include "nsIDialogParamBlock.h"
 
 class nsIURI;
 class nsIDOMElement;
 class gfxMatrix;
 
 struct JSContext;
 struct JSObject;
 
@@ -83,16 +84,18 @@ struct TabParentListenerInfo
 };
 
 inline    
 bool operator==(const TabParentListenerInfo& lhs, const TabParentListenerInfo& rhs)
 {
   return &lhs == &rhs;
 }
 
+class ContentDialogParent : public PContentDialogParent {};
+
 class TabParent : public PIFrameEmbeddingParent, public nsIWebProgress
 {
 public:
     TabParent();
     virtual ~TabParent();
     void SetOwnerElement(nsIDOMElement* aElement) { mFrameElement = aElement; }
     void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) {
         mBrowserDOMWindow = aBrowserDOMWindow;
@@ -117,16 +120,26 @@ public:
 
     virtual bool AnswercreateWindow(PIFrameEmbeddingParent** retval);
     virtual bool AnswersendSyncMessageToParent(const nsString& aMessage,
                                                const nsString& aJSON,
                                                const nsTArray<PObjectWrapperParent*>&,
                                                nsTArray<nsString>* aJSONRetVal);
     virtual bool RecvsendAsyncMessageToParent(const nsString& aMessage,
                                               const nsString& aJSON);
+    virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
+                                                      const nsCString& aName,
+                                                      const nsCString& aFeatures,
+                                                      const nsTArray<int>& aIntParams,
+                                                      const nsTArray<nsString>& aStringParams);
+    virtual bool DeallocPContentDialog(PContentDialogParent* aDialog)
+    {
+      delete aDialog;
+      return true;
+    }
 
     void LoadURL(nsIURI* aURI);
     void Move(PRUint32 x, PRUint32 y, PRUint32 width, PRUint32 height);
     void Activate();
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
                         PRInt32 aButton, PRInt32 aClickCount,
                         PRInt32 aModifiers, PRBool aIgnoreRootScrollFrame);
     void SendKeyEvent(const nsAString& aType, PRInt32 aKeyCode,
@@ -163,29 +176,49 @@ public:
     virtual PGeolocationRequestParent* AllocPGeolocationRequest(const IPC::URI& uri);
     virtual bool DeallocPGeolocationRequest(PGeolocationRequestParent* actor);
 
     JSBool GetGlobalJSObject(JSContext* cx, JSObject** globalp);
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBPROGRESS
 
+    void HandleDelayedDialogs();
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         PRBool aSync,
                         const nsString& aJSON,
                         const nsTArray<PObjectWrapperParent*>* aObjects,
                         nsTArray<nsString>* aJSONRetVal = nsnull);
 
     TabParentListenerInfo* GetListenerInfo(nsIWebProgressListener *aListener);
 
     void ActorDestroy(ActorDestroyReason why);
 
     nsIDOMElement* mFrameElement;
     nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
 
     nsTArray<TabParentListenerInfo> mListenerInfoList;
+
+    struct DelayedDialogData
+    {
+      DelayedDialogData(PContentDialogParent* aDialog, PRUint32 aType,
+                        const nsCString& aName,
+                        const nsCString& aFeatures,
+                        nsIDialogParamBlock* aParams)
+      : mDialog(aDialog), mType(aType), mName(aName), mFeatures(aFeatures),
+        mParams(aParams) {}
+
+      PContentDialogParent* mDialog;
+      PRUint32 mType;
+      nsCString mName;
+      nsCString mFeatures;
+      nsCOMPtr<nsIDialogParamBlock> mParams;
+    };
+    nsTArray<DelayedDialogData*> mDelayedDialogs;
+
+    PRBool ShouldDelayDialogs();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/ipc/ipdl.mk
+++ b/dom/ipc/ipdl.mk
@@ -34,9 +34,10 @@
 #
 # ***** END LICENSE BLOCK *****
 
 IPDLSRCS = \
   PContentProcess.ipdl \
   PIFrameEmbedding.ipdl \
   PDocumentRenderer.ipdl \
   PDocumentRendererShmem.ipdl \
+  PContentDialog.ipdl \
   $(NULL)
--- a/dom/ipc/test.xul
+++ b/dom/ipc/test.xul
@@ -203,16 +203,46 @@
     var MozAfterPaintCount = 0;
     function enableMozAfterPaint() {
       messageManager.addMessageListener("MozAfterPaint",
         function(m) {
           document.getElementById("messageLog").value = m.name + "[" + (++MozAfterPaintCount) + "]";
         });
       messageManager.loadFrameScript("data:,addEventListener('MozAfterPaint', function(e) { sendAsyncMessage('MozAfterPaint'); },true);", false);
     }
+
+   var Ci = Components.interfaces;
+   var Cu = Components.utils;
+   Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+    function DialogProvider() { }
+
+    DialogProvider.prototype = {
+      QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsIDialogCreator, Ci.nsISupports]),
+      openURI: function (aURI, aOpener, aWhere, aContext) {
+        return null;
+      },
+      isTabContentWindow: function (aWindow) {
+        return false;
+      },
+      openDialog: function(aType, aName, aFeatures, aArguments, aFrameElement) {
+        alert(aType + ", " + aName + ", " + aFeatures + ", " + aArguments + ", " + aFrameElement);
+      }
+    }
+
+    function defaultDialogs(useDefault) {
+       window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = useDefault ? null : new DialogProvider();
+    }
+
+    defaultDialogs(false);
+
+    window.addEventListener("MozDelayedModalDialog",
+                            function(e) { alert(e.type + ", " + e.target); },
+                            true);
+
   </script>
 
   <toolbar id="controls">
     <toolbarbutton label="Back"/>
     <toolbarbutton label="Forward"/>
     <textbox onchange="loadURL(this.value)" flex="1" id="URL"/>
   </toolbar>
   <toolbar>
@@ -229,13 +259,17 @@
     <textbox flex="1" id="script"/><button
       label="send" oncommand="document.getElementById('page').QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.
                               messageManager.loadFrameScript(this.previousSibling.value, false);"/>
   </toolbar>
   <toolbar>
     <label value="Eval script in chrome context"/>
     <textbox flex="1"/><button label="run" oncommand="eval(this.previousSibling.value);"/>
   </toolbar>
+  <toolbar>
+    <checkbox label="allow dialogs from remote content"
+               oncommand="document.getElementById('page').QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.delayRemoteDialogs = this.checked;"/>
+  </toolbar>
 
   <browser type="content" src="http://www.google.com/" flex="1" id="page" remote="true"
            onfocus="this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.activateRemoteFrame();"/>
   <label id="messageLog" value="" crop="center"/>
 </window>
--- a/embedding/base/Makefile.in
+++ b/embedding/base/Makefile.in
@@ -64,16 +64,17 @@ SDK_XPIDLSRCS   = \
 
 SDK_LIBRARY     =                        \
 		$(LIB_PREFIX)embed_base_s.$(LIB_SUFFIX) \
 		$(NULL)
 
 XPIDLSRCS	    = \
                 nsIWindowCreator2.idl \
                 nsIWindowProvider.idl \
+                nsIDialogCreator.idl \
                 $(NULL)
 
 include $(srcdir)/objs.mk
 
 CPPSRCS += $(EMBED_CPPSRCS)
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
new file mode 100644
--- /dev/null
+++ b/embedding/base/nsIDialogCreator.idl
@@ -0,0 +1,54 @@
+/* ***** 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
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 ***** */
+
+
+#include "nsISupports.idl"
+
+interface nsIDOMElement;
+interface nsIDialogParamBlock;
+
+[scriptable, uuid(17c9e659-2a9a-4a58-8a1c-d76bb58339c0)]
+interface nsIDialogCreator : nsISupports
+{
+  const unsigned long UNKNOWN_DIALOG = 0;
+  const unsigned long GENERIC_DIALOG = 1;
+  const unsigned long SELECT_DIALOG  = 2;
+
+  void openDialog(in unsigned long aType,
+                  in ACString aName, in ACString aFeatures,
+                  in nsIDialogParamBlock aArguments,
+                  [optional] in nsIDOMElement aFrameElement);
+};
--- a/embedding/components/windowwatcher/src/nsPromptService.cpp
+++ b/embedding/components/windowwatcher/src/nsPromptService.cpp
@@ -48,16 +48,21 @@
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIServiceManager.h"
 #include "nsISupportsUtils.h"
 #include "nsString.h"
 #include "nsIStringBundle.h"
 #include "nsXPIDLString.h"
 #include "nsISound.h"
+#include "nsIDialogCreator.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIDocShellTreeOwner.h"
+#include "nsWindowWatcher.h"
+#include "nsCRT.h"
 
 static const char kPromptURL[] = "chrome://global/content/commonDialog.xul";
 static const char kSelectPromptURL[] = "chrome://global/content/selectDialog.xul";
 static const char kQuestionIconClass[] = "question-icon";
 static const char kAlertIconClass[] = "alert-icon";
 // We include question-icon for backwards compatibility
 static const char kAuthenticationIconClass[] = "authentication-icon question-icon";
 
@@ -736,40 +741,61 @@ nsPromptService::Select(nsIDOMWindow *pa
   block->GetInt(eSelection, outSelection);
   *_retval = buttonPressed ? PR_FALSE : PR_TRUE;
 
   return rv;
 }
 
 nsresult
 nsPromptService::DoDialog(nsIDOMWindow *aParent,
-                   nsIDialogParamBlock *aParamBlock, const char *aChromeURL)
+                          nsIDialogParamBlock *aParamBlock, const char *aChromeURL)
 {
   NS_ENSURE_ARG(aParamBlock);
   NS_ENSURE_ARG(aChromeURL);
   if (!mWatcher)
     return NS_ERROR_FAILURE;
 
-  nsresult rv = NS_OK;
+  const char* features = "centerscreen,chrome,modal,titlebar";
+  const char* name = "_blank";
+
+  nsresult rv = NS_ERROR_FAILURE;
 
   // get a parent, if at all possible
   // (though we'd rather this didn't fail, it's OK if it does. so there's
   // no failure or null check.)
   nsCOMPtr<nsIDOMWindow> activeParent; // retain ownership for method lifetime
   if (!aParent) {
     mWatcher->GetActiveWindow(getter_AddRefs(activeParent));
     aParent = activeParent;
   }
 
-  nsCOMPtr<nsISupports> arguments(do_QueryInterface(aParamBlock));
-  nsCOMPtr<nsIDOMWindow> dialog;
-  rv = mWatcher->OpenWindow(aParent, aChromeURL, "_blank",
-                            "centerscreen,chrome,modal,titlebar", arguments,
-                            getter_AddRefs(dialog));
+  nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
+  nsWindowWatcher::GetWindowTreeOwner(aParent, getter_AddRefs(parentTreeOwner));
+  nsCOMPtr<nsIDialogCreator> dialogCreator = do_GetInterface(parentTreeOwner);
+  if (dialogCreator) {
+    PRUint32 type = nsIDialogCreator::UNKNOWN_DIALOG;
+    if (nsCRT::strcmp(aChromeURL, kPromptURL) == 0) {
+      type = nsIDialogCreator::GENERIC_DIALOG;
+    } else if (nsCRT::strcmp(aChromeURL, kSelectPromptURL) == 0) {
+      type = nsIDialogCreator::SELECT_DIALOG;
+    }
 
+    rv = dialogCreator->OpenDialog(type,
+                                   nsDependentCString(name),
+                                   nsDependentCString(features),
+                                   aParamBlock,
+                                   nsnull);
+  }
+  if (NS_FAILED(rv)) {
+    nsCOMPtr<nsISupports> arguments(do_QueryInterface(aParamBlock));
+    nsCOMPtr<nsIDOMWindow> dialog;
+    rv = mWatcher->OpenWindow(aParent, aChromeURL, name,
+                              features, arguments,
+                              getter_AddRefs(dialog));
+  }
   return rv;
 }
 
 nsresult
 nsPromptService::GetLocaleString(const char *aKey, PRUnichar **aResult)
 {
   nsresult rv;
 
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.h
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.h
@@ -53,16 +53,17 @@
 
 class  nsIURI;
 class  nsIDocShellTreeItem;
 class  nsIDocShellTreeOwner;
 class  nsIWebBrowserChrome;
 class  nsString;
 class  nsWatcherWindowEnumerator;
 class  nsIScriptContext;
+class  nsPromptService;
 struct JSContext;
 struct JSObject;
 struct nsWatcherWindowEntry;
 struct PRLock;
 struct SizeSpec;
 
 class nsWindowWatcher :
       public nsIWindowWatcher,
@@ -80,17 +81,18 @@ public:
 
   NS_DECL_ISUPPORTS
 
   NS_DECL_NSIWINDOWWATCHER
   NS_DECL_NSPIWINDOWWATCHER
   NS_DECL_NSIPROMPTFACTORY
   NS_DECL_NSIAUTHPROMPTADAPTERFACTORY
 
-private:
+protected:
+  friend class nsPromptService;
   PRBool AddEnumerator(nsWatcherWindowEnumerator* inEnumerator);
   PRBool RemoveEnumerator(nsWatcherWindowEnumerator* inEnumerator);
 
   nsWatcherWindowEntry *FindWindowEntry(nsIDOMWindow *aWindow);
   nsresult RemoveWindow(nsWatcherWindowEntry *inInfo);
 
   // Get the caller tree item.  Look on the JS stack, then fall back
   // to the parent if there's nothing there.