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 id14210
push userdougt@mozilla.com
push dateThu, 01 Jul 2010 06:28:42 +0000
treeherdermozilla-central@3aff97777291 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs548847
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
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.