Bug 910384 - Change nsFilePickerProxy to be asynchronous and add a proper IPDL protocol for it. r=jdm
authorTom Schuster <evilpies@gmail.com>
Tue, 18 Feb 2014 01:30:06 +0100
changeset 169563 3e38ac18ab846e1971de5c96bb8c612edaeef540
parent 169562 8da5f0f2f82c088be5a652162d9fe91263ef1d0f
child 169564 97037c9b3c8caaa9e2e4aced6d298e78d5a4479a
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersjdm
bugs910384
milestone30.0a1
Bug 910384 - Change nsFilePickerProxy to be asynchronous and add a proper IPDL protocol for it. r=jdm
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/FilePickerParent.cpp
dom/ipc/FilePickerParent.h
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/PFilePicker.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/moz.build
widget/xpwidgets/nsFilePickerProxy.cpp
widget/xpwidgets/nsFilePickerProxy.h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -62,17 +62,16 @@
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIAppsService.h"
 #include "nsIClipboard.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "mozilla/dom/WakeLock.h"
 #include "nsIDOMWindow.h"
 #include "nsIExternalProtocolService.h"
-#include "nsIFilePicker.h"
 #include "nsIGfxInfo.h"
 #include "nsIIdleService.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIRemoteBlob.h"
@@ -2656,91 +2655,16 @@ ContentParent::RecvSetURITitle(const URI
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     if (history) {
         history->SetURITitle(ourURI, title);
     }
     return true;
 }
 
 bool
-ContentParent::RecvShowFilePicker(const int16_t& mode,
-                                  const int16_t& selectedType,
-                                  const bool& addToRecentDocs,
-                                  const nsString& title,
-                                  const nsString& defaultFile,
-                                  const nsString& defaultExtension,
-                                  const InfallibleTArray<nsString>& filters,
-                                  const InfallibleTArray<nsString>& filterNames,
-                                  InfallibleTArray<nsString>* files,
-                                  int16_t* retValue,
-                                  nsresult* result)
-{
-    nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1");
-    if (!filePicker) {
-        *result = NS_ERROR_NOT_AVAILABLE;
-        return true;
-    }
-
-    // as the parent given to the content process would be meaningless in this
-    // process, always use active window as the parent
-    nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
-    nsCOMPtr<nsIDOMWindow> window;
-    ww->GetActiveWindow(getter_AddRefs(window));
-
-    // initialize the "real" picker with all data given
-    *result = filePicker->Init(window, title, mode);
-    if (NS_FAILED(*result))
-        return true;
-
-    filePicker->SetAddToRecentDocs(addToRecentDocs);
-
-    uint32_t count = filters.Length();
-    for (uint32_t i = 0; i < count; ++i) {
-        filePicker->AppendFilter(filterNames[i], filters[i]);
-    }
-
-    filePicker->SetDefaultString(defaultFile);
-    filePicker->SetDefaultExtension(defaultExtension);
-    filePicker->SetFilterIndex(selectedType);
-
-    // and finally open the dialog
-    *result = filePicker->Show(retValue);
-    if (NS_FAILED(*result))
-        return true;
-
-    if (mode == nsIFilePicker::modeOpenMultiple) {
-        nsCOMPtr<nsISimpleEnumerator> fileIter;
-        *result = filePicker->GetFiles(getter_AddRefs(fileIter));
-
-        nsCOMPtr<nsIFile> singleFile;
-        bool loop = true;
-        while (NS_SUCCEEDED(fileIter->HasMoreElements(&loop)) && loop) {
-            fileIter->GetNext(getter_AddRefs(singleFile));
-            if (singleFile) {
-                nsAutoString filePath;
-                singleFile->GetPath(filePath);
-                files->AppendElement(filePath);
-            }
-        }
-        return true;
-    }
-    nsCOMPtr<nsIFile> file;
-    filePicker->GetFile(getter_AddRefs(file));
-
-    // Even with NS_OK file can be null if nothing was selected.
-    if (file) {
-        nsAutoString filePath;
-        file->GetPath(filePath);
-        files->AppendElement(filePath);
-    }
-
-    return true;
-}
-
-bool
 ContentParent::RecvGetRandomValues(const uint32_t& length,
                                    InfallibleTArray<uint8_t>* randomValues)
 {
     uint8_t* buf = Crypto::GetRandomValues(length);
     if (!buf) {
         return true;
     }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -424,28 +424,16 @@ private:
 
     virtual bool RecvVisitURI(const URIParams& uri,
                               const OptionalURIParams& referrer,
                               const uint32_t& flags) MOZ_OVERRIDE;
 
     virtual bool RecvSetURITitle(const URIParams& uri,
                                  const nsString& title) MOZ_OVERRIDE;
 
-    virtual bool RecvShowFilePicker(const int16_t& mode,
-                                    const int16_t& selectedType,
-                                    const bool& addToRecentDocs,
-                                    const nsString& title,
-                                    const nsString& defaultFile,
-                                    const nsString& defaultExtension,
-                                    const InfallibleTArray<nsString>& filters,
-                                    const InfallibleTArray<nsString>& filterNames,
-                                    InfallibleTArray<nsString>* files,
-                                    int16_t* retValue,
-                                    nsresult* result) MOZ_OVERRIDE;
-
     virtual bool RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
                                            const nsString& aText, const bool& aTextClickable,
                                            const nsString& aCookie, const nsString& aName,
                                            const nsString& aBidi, const nsString& aLang,
                                            const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
     virtual bool RecvCloseAlert(const nsString& aName,
                                 const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
new file mode 100644
--- /dev/null
+++ b/dom/ipc/FilePickerParent.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set sw=4 ts=8 et tw=80 :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FilePickerParent.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIDocument.h"
+#include "nsIDOMWindow.h"
+#include "nsIFile.h"
+#include "nsISimpleEnumerator.h"
+#include "mozilla/unused.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabParent.h"
+
+using mozilla::unused;
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS1(FilePickerParent::FilePickerShownCallback,
+                   nsIFilePickerShownCallback);
+
+NS_IMETHODIMP
+FilePickerParent::FilePickerShownCallback::Done(int16_t aResult)
+{
+  if (mFilePickerParent) {
+    mFilePickerParent->Done(aResult);
+  }
+  return NS_OK;
+}
+
+void
+FilePickerParent::FilePickerShownCallback::Destroy()
+{
+  mFilePickerParent = nullptr;
+}
+
+FilePickerParent::~FilePickerParent()
+{
+}
+
+void
+FilePickerParent::Done(int16_t aResult)
+{
+  InfallibleTArray<nsString> files;
+
+  if (mMode == nsIFilePicker::modeOpenMultiple) {
+    nsCOMPtr<nsISimpleEnumerator> iter;
+    NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
+
+    nsCOMPtr<nsIFile> file;
+    bool loop = true;
+    while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
+      iter->GetNext(getter_AddRefs(file));
+      if (file) {
+        nsAutoString path;
+        if (NS_SUCCEEDED(file->GetPath(path))) {
+          files.AppendElement(path);
+        }
+      }
+    }
+  } else {
+    nsCOMPtr<nsIFile> file;
+    mFilePicker->GetFile(getter_AddRefs(file));
+
+    if (file) {
+      nsAutoString path;
+      if (NS_SUCCEEDED(file->GetPath(path))) {
+        files.AppendElement(path);
+      }
+    }
+  }
+
+  unused << Send__delete__(this, InputFiles(files), aResult);
+}
+
+bool
+FilePickerParent::CreateFilePicker()
+{
+  mFilePicker = do_CreateInstance("@mozilla.org/filepicker;1");
+  if (!mFilePicker) {
+    return false;
+  }
+
+  Element* element = static_cast<TabParent*>(Manager())->GetOwnerElement();
+  if (!element) {
+    return false;
+  }
+
+  nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(element->OwnerDoc()->GetWindow());
+  if (!window) {
+    return false;
+  }
+
+  return NS_SUCCEEDED(mFilePicker->Init(window, mTitle, mMode));
+}
+
+bool
+FilePickerParent::RecvOpen(const int16_t& aSelectedType,
+                           const bool& aAddToRecentDocs,
+                           const nsString& aDefaultFile,
+                           const nsString& aDefaultExtension,
+                           const InfallibleTArray<nsString>& aFilters,
+                           const InfallibleTArray<nsString>& aFilterNames)
+{
+  if (!CreateFilePicker()) {
+    unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
+    return true;
+  }
+
+  mFilePicker->SetAddToRecentDocs(aAddToRecentDocs);
+
+  for (uint32_t i = 0; i < aFilters.Length(); ++i) {
+    mFilePicker->AppendFilter(aFilterNames[i], aFilters[i]);
+  }
+
+  mFilePicker->SetDefaultString(aDefaultFile);
+  mFilePicker->SetDefaultExtension(aDefaultExtension);
+  mFilePicker->SetFilterIndex(aSelectedType);
+
+  mCallback = new FilePickerShownCallback(this);
+
+  mFilePicker->Open(mCallback);
+  return true;
+}
+
+void
+FilePickerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mCallback) {
+    mCallback->Destroy();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/FilePickerParent.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set sw=4 ts=8 et tw=80 :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FilePickerParent_h
+#define mozilla_dom_FilePickerParent_h
+
+#include "nsIFilePicker.h"
+#include "mozilla/dom/PFilePickerParent.h"
+
+namespace mozilla {
+namespace dom {
+
+class FilePickerParent : public PFilePickerParent
+{
+ public:
+  FilePickerParent(const nsString& aTitle,
+                   const int16_t& aMode)
+  : mTitle(aTitle)
+  , mMode(aMode)
+  {}
+
+  virtual ~FilePickerParent();
+
+  void Done(int16_t aResult);
+
+  virtual bool RecvOpen(const int16_t& aSelectedType,
+                        const bool& aAddToRecentDocs,
+                        const nsString& aDefaultFile,
+                        const nsString& aDefaultExtension,
+                        const InfallibleTArray<nsString>& aFilters,
+                        const InfallibleTArray<nsString>& aFilterNames) MOZ_OVERRIDE;
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  class FilePickerShownCallback : public nsIFilePickerShownCallback
+  {
+  public:
+    FilePickerShownCallback(FilePickerParent* aFilePickerParent)
+      : mFilePickerParent(aFilePickerParent)
+    { }
+    virtual ~FilePickerShownCallback() {}
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIFILEPICKERSHOWNCALLBACK
+
+    void Destroy();
+
+  private:
+    FilePickerParent* mFilePickerParent;
+  };
+
+ private:
+  bool CreateFilePicker();
+
+  nsRefPtr<FilePickerShownCallback> mCallback;
+  nsCOMPtr<nsIFilePicker> mFilePicker;
+
+  nsString mTitle;
+  int16_t mMode;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -5,16 +5,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBlob;
 include protocol PContent;
 include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PContentPermissionRequest;
+include protocol PFilePicker;
 include protocol PRenderFrame;
 include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
 include DOMTypes;
 include JavaScriptTypes;
 include URIParams;
 include PContentPermission;
 
@@ -54,16 +55,17 @@ namespace dom {
 
 intr protocol PBrowser
 {
     manager PContent;
 
     manages PContentDialog;
     manages PDocumentRenderer;
     manages PContentPermissionRequest;
+    manages PFilePicker;
     manages PRenderFrame;
     manages POfflineCacheUpdate;
     manages PIndexedDB;
 
 both:
     AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows,
                  Principal aPrincipal);
 
@@ -232,16 +234,18 @@ parent:
      *       principals that can live in the content process should
      *       provided.
      */
     PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal);
 
     PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures,
                    int32_t[] aIntParams, nsString[] aStringParams);
 
+    PFilePicker(nsString aTitle, int16_t aMode);
+
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
      */
     sync PRenderFrame();
 
     sync InitRenderFrame(PRenderFrame aFrame)
         returns (ScrollingBehavior scrolling,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -383,22 +383,16 @@ parent:
 
     PAsmJSCacheEntry(OpenMode openMode, WriteParams write, Principal principal);
 
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
     async SetURITitle(URIParams uri, nsString title);
-    
-    // filepicker remoting
-    sync ShowFilePicker(int16_t mode, int16_t selectedType, bool addToRecentDocs,
-                        nsString title, nsString defaultFile, nsString defaultExtension,
-                        nsString[] filters, nsString[] filterNames)
-        returns (nsString[] files, int16_t retValue, nsresult result);
 
     async LoadURIExternal(URIParams uri);
 
     // PrefService message
     sync ReadPrefsArray() returns (PrefSetting[] prefs);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PFilePicker.ipdl
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PBrowser;
+
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+
+namespace mozilla {
+namespace dom {
+
+struct InputFiles
+{
+  nsString[] files;
+};
+
+union MaybeInputFiles
+{
+  InputFiles;
+  void_t;
+};
+
+protocol PFilePicker
+{
+  manager PBrowser;
+
+parent:
+    Open(int16_t selectedType, bool addToRecentDocs, nsString defaultFile,
+         nsString defaultExtension, nsString[] filters, nsString[] filterNames);
+
+child:
+    __delete__(MaybeInputFiles files, int16_t result);
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -33,16 +33,17 @@
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsEmbedCID.h"
 #include "nsEventListenerManager.h"
 #include <algorithm>
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
+#include "nsFilePickerProxy.h"
 #include "mozilla/dom/Element.h"
 #include "nsIBaseWindow.h"
 #include "nsICachedFileDescriptorListener.h"
 #include "nsIDialogParamBlock.h"
 #include "nsIDocumentInlines.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMWindow.h"
@@ -2097,16 +2098,31 @@ TabChild::DeallocPContentPermissionReque
         static_cast<PCOMContentPermissionRequestChild*>(actor);
 #ifdef DEBUG
     child->mIPCOpen = false;
 #endif /* DEBUG */
     child->IPDLRelease();
     return true;
 }
 
+PFilePickerChild*
+TabChild::AllocPFilePickerChild(const nsString&, const int16_t&)
+{
+  NS_RUNTIMEABORT("unused");
+  return nullptr;
+}
+
+bool
+TabChild::DeallocPFilePickerChild(PFilePickerChild* actor)
+{
+  nsFilePickerProxy* filePicker = static_cast<nsFilePickerProxy*>(actor);
+  NS_RELEASE(filePicker);
+  return true;
+}
+
 bool
 TabChild::RecvActivateFrameEvent(const nsString& aType, const bool& capture)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
   NS_ENSURE_TRUE(window, true);
   nsCOMPtr<EventTarget> chromeHandler =
     do_QueryInterface(window->GetChromeEventHandler());
   NS_ENSURE_TRUE(chromeHandler, true);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -300,16 +300,21 @@ public:
 #endif /* DEBUG */
 
     virtual PContentPermissionRequestChild*
     AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
                                         const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
     virtual bool
     DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor) MOZ_OVERRIDE;
 
+    virtual PFilePickerChild*
+    AllocPFilePickerChild(const nsString& aTitle, const int16_t& aMode) MOZ_OVERRIDE;
+    virtual bool
+    DeallocPFilePickerChild(PFilePickerChild* actor) MOZ_OVERRIDE;
+
     virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdateChild(
             const URIParams& manifestURI,
             const URIParams& documentURI,
             const bool& stickDocument) MOZ_OVERRIDE;
     virtual bool
     DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* offlineCacheUpdate) MOZ_OVERRIDE;
 
     nsIWebNavigation* WebNavigation() { return mWebNav; }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -51,16 +51,17 @@
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "private/pprio.h"
 #include "PermissionMessageUtils.h"
 #include "StructuredCloneUtils.h"
 #include "JavaScriptParent.h"
+#include "FilePickerParent.h"
 #include "TabChild.h"
 #include "LoadContext.h"
 #include "nsNetCID.h"
 #include <algorithm>
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
@@ -632,16 +633,29 @@ TabParent::AllocPContentPermissionReques
 
 bool
 TabParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor)
 {
   delete actor;
   return true;
 }
 
+PFilePickerParent*
+TabParent::AllocPFilePickerParent(const nsString& aTitle, const int16_t& aMode)
+{
+  return new FilePickerParent(aTitle, aMode);
+}
+
+bool
+TabParent::DeallocPFilePickerParent(PFilePickerParent* actor)
+{
+  delete actor;
+  return true;
+}
+
 void
 TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
                           int32_t aButton, int32_t aClickCount,
                           int32_t aModifiers, bool aIgnoreRootScrollFrame)
 {
   if (!mIsDestroyed) {
     unused << PBrowserParent::SendMouseEvent(nsString(aType), aX, aY,
                                              aButton, aClickCount,
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PContentDialogParent.h"
+#include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDialogParamBlock.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
@@ -253,16 +254,21 @@ public:
     virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor) MOZ_OVERRIDE;
 
     virtual PContentPermissionRequestParent*
     AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
                                          const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
     virtual bool
     DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) MOZ_OVERRIDE;
 
+    virtual PFilePickerParent*
+    AllocPFilePickerParent(const nsString& aTitle,
+                           const int16_t& aMode) MOZ_OVERRIDE;
+    virtual bool DeallocPFilePickerParent(PFilePickerParent* actor) MOZ_OVERRIDE;
+
     virtual POfflineCacheUpdateParent*
     AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
                                    const URIParams& aDocumentURI,
                                    const bool& aStickDocument) MOZ_OVERRIDE;
     virtual bool
     RecvPOfflineCacheUpdateConstructor(POfflineCacheUpdateParent* aActor,
                                        const URIParams& aManifestURI,
                                        const URIParams& aDocumentURI,
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -18,16 +18,17 @@ EXPORTS.mozilla.dom.ipc += [
 ]
 
 EXPORTS.mozilla.dom += [
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
+    'FilePickerParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
 ]
 
@@ -38,16 +39,17 @@ EXPORTS.mozilla += [
 ]
 
 UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ContentChild.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
     'CrashReporterParent.cpp',
+    'FilePickerParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'StructuredCloneUtils.cpp',
     'TabChild.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
     'TabParent.cpp',
@@ -67,16 +69,17 @@ IPDL_SOURCES += [
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
     'PContent.ipdl',
     'PContentDialog.ipdl',
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PDocumentRenderer.ipdl',
+    'PFilePicker.ipdl',
     'PMemoryReportRequest.ipdl',
     'PTabContext.ipdlh',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/widget/xpwidgets/nsFilePickerProxy.cpp
+++ b/widget/xpwidgets/nsFilePickerProxy.cpp
@@ -1,170 +1,176 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/dom/ContentChild.h"
 #include "nsFilePickerProxy.h"
+#include "nsComponentManagerUtils.h"
 #include "nsNetUtil.h"
+#include "nsIFile.h"
+#include "mozilla/dom/TabChild.h"
 
+using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS1(nsFilePickerProxy, nsIFilePicker)
 
 nsFilePickerProxy::nsFilePickerProxy()
-{ 
+{
 }
 
 nsFilePickerProxy::~nsFilePickerProxy()
 {
 }
 
 NS_IMETHODIMP
-nsFilePickerProxy::Init(nsIDOMWindow* /*aParent*/, const nsAString& aTitle,
+nsFilePickerProxy::Init(nsIDOMWindow* aParent, const nsAString& aTitle,
                         int16_t aMode)
 {
-    mTitle = aTitle;
-    mMode = aMode;
+  TabChild* tabChild = TabChild::GetFrom(aParent);
+  if (!tabChild) {
+    return NS_ERROR_FAILURE;
+  }
 
-    return NS_OK;
+  mMode = aMode;
+
+  NS_ADDREF_THIS();
+  tabChild->SendPFilePickerConstructor(this, nsString(aTitle), aMode);
+  return NS_OK;
 }
 
-void nsFilePickerProxy::InitNative(nsIWidget* aParent, const nsAString& aTitle)
+void
+nsFilePickerProxy::InitNative(nsIWidget* aParent, const nsAString& aTitle)
 {
 }
 
-
 NS_IMETHODIMP
 nsFilePickerProxy::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
 {
-    mFilters.AppendElement(aFilter);
-    mFilterNames.AppendElement(aTitle);  
-    return NS_OK;
+  mFilterNames.AppendElement(aTitle);
+  mFilters.AppendElement(aFilter);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::GetDefaultString(nsAString& aDefaultString)
 {
-    aDefaultString = mDefault;
-    return NS_OK;
+  aDefaultString = mDefault;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::SetDefaultString(const nsAString& aDefaultString)
 {
-    mDefault = aDefaultString;
-    return NS_OK;
+  mDefault = aDefaultString;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::GetDefaultExtension(nsAString& aDefaultExtension)
 {
-    aDefaultExtension = mDefaultExtension;
-    return NS_OK;
+  aDefaultExtension = mDefaultExtension;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::SetDefaultExtension(const nsAString& aDefaultExtension)
 {
-    mDefaultExtension = aDefaultExtension;
-    return NS_OK;
+  mDefaultExtension = aDefaultExtension;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::GetFilterIndex(int32_t* aFilterIndex)
 {
-    *aFilterIndex = mSelectedType;
-    return NS_OK;
+  *aFilterIndex = mSelectedType;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::SetFilterIndex(int32_t aFilterIndex)
 {
-    mSelectedType = aFilterIndex;
-    return NS_OK;
+  mSelectedType = aFilterIndex;
+  return NS_OK;
 }
 
 /* readonly attribute nsIFile file; */
 NS_IMETHODIMP
 nsFilePickerProxy::GetFile(nsIFile** aFile)
 {
-    NS_ENSURE_ARG_POINTER(aFile);
-
-    *aFile = nullptr;
-    if (mFile.IsEmpty()) {
-        return NS_OK;
-    }
+  NS_ENSURE_ARG_POINTER(aFile);
 
-    nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
-    NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
+  *aFile = nullptr;
+  if (mFiles.IsEmpty()) {
+      return NS_OK;
+  }
 
-    file->InitWithPath(mFile);
-
-    file.forget(aFile);
-
-    return NS_OK;
+  nsCOMPtr<nsIFile> file = mFiles[0];
+  file.forget(aFile);
+  return NS_OK;
 }
 
 /* readonly attribute nsIFileURL fileURL; */
 NS_IMETHODIMP
 nsFilePickerProxy::GetFileURL(nsIURI** aFileURL)
 {
-    nsCOMPtr<nsIFile> file;
-    GetFile(getter_AddRefs(file));
+  nsCOMPtr<nsIFile> file;
+  GetFile(getter_AddRefs(file));
 
-    nsCOMPtr<nsIURI> uri;
-    NS_NewFileURI(getter_AddRefs(uri), file);
-    NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIURI> uri;
+  NS_NewFileURI(getter_AddRefs(uri), file);
+  NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
-    return CallQueryInterface(uri, aFileURL);
+  return CallQueryInterface(uri, aFileURL);
 }
 
 /* readonly attribute nsISimpleEnumerator files; */
 NS_IMETHODIMP
 nsFilePickerProxy::GetFiles(nsISimpleEnumerator** aFiles)
 {
-    NS_ENSURE_ARG_POINTER(aFiles);
+  NS_ENSURE_ARG_POINTER(aFiles);
+
+  if (mMode == nsIFilePicker::modeOpenMultiple) {
+    return NS_NewArrayEnumerator(aFiles, mFiles);
+  }
 
-    if (mMode == nsIFilePicker::modeOpenMultiple) {
-        return NS_NewArrayEnumerator(aFiles, mFiles);
-    }
+  return NS_ERROR_FAILURE;
+}
 
-    return NS_ERROR_FAILURE;
+NS_IMETHODIMP
+nsFilePickerProxy::Show(int16_t* aReturn)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-NS_IMETHODIMP nsFilePickerProxy::Show(int16_t* aReturn)
+NS_IMETHODIMP
+nsFilePickerProxy::Open(nsIFilePickerShownCallback* aCallback)
 {
-    mozilla::dom::ContentChild *cc = mozilla::dom::ContentChild::GetSingleton();
-    NS_ASSERTION(cc, "Content Protocol is NULL!");
-    
-    InfallibleTArray<nsString> filePaths;
-    
-    nsresult rv;
-    cc->SendShowFilePicker(mMode, mSelectedType,
-                           mAddToRecentDocs, mTitle,
-                           mDefault, mDefaultExtension,
-                           mFilters, mFilterNames,
-                           &filePaths, aReturn, &rv);
+  mCallback = aCallback;
 
-    NS_ENSURE_SUCCESS(rv, rv);
+  SendOpen(mSelectedType, mAddToRecentDocs, mDefault,
+           mDefaultExtension, mFilters, mFilterNames);
+
+  return NS_OK;
+}
 
-    uint32_t count = filePaths.Length();
-    
-    if (mMode == nsIFilePicker::modeOpenMultiple) {
-        for (uint32_t i = 0; i < count; ++i) {
-            nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
-            NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
+bool
+nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles,
+                                  const int16_t& aResult)
+{
+  if (aFiles.type() == MaybeInputFiles::TInputFiles) {
+    const InfallibleTArray<nsString>& files = aFiles.get_InputFiles().files();
+    for (uint32_t i = 0; i < files.Length(); ++i) {
+      nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
+      NS_ENSURE_TRUE(file, true);
+      file->InitWithPath(files[i]);
+      mFiles.AppendObject(file);
+    }
+  }
 
-            file->InitWithPath(filePaths[i]);
-            mFiles.AppendObject(file);
-        }
-        return NS_OK;
-    }
+  if (mCallback) {
+    mCallback->Done(aResult);
+    mCallback = nullptr;
+  }
 
-    NS_ASSERTION(count == 1 || count == 0, "we should only have 1 or 0 files");
-
-    if (count == 1)
-        mFile = filePaths[0];
-    
-    return NS_OK;
+  return true;
 }
--- a/widget/xpwidgets/nsFilePickerProxy.h
+++ b/widget/xpwidgets/nsFilePickerProxy.h
@@ -7,55 +7,63 @@
 #define NSFILEPICKERPROXY_H
 
 #include "nsBaseFilePicker.h"
 #include "nsString.h"
 #include "nsIURI.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 
+#include "mozilla/dom/PFilePickerChild.h"
+
 class nsIWidget;
 class nsIFile;
 
 /**
   This class creates a proxy file picker to be used in content processes.
   The file picker just collects the initialization data and when Show() is
   called, remotes everything to the chrome process which in turn can show a
   platform specific file picker.
 */
-class nsFilePickerProxy : public nsBaseFilePicker
+class nsFilePickerProxy : public nsBaseFilePicker,
+                          public mozilla::dom::PFilePickerChild
 {
 public:
     nsFilePickerProxy();
 
     NS_DECL_ISUPPORTS
 
     // nsIFilePicker (less what's in nsBaseFilePicker)
-    NS_IMETHODIMP Init(nsIDOMWindow* parent, const nsAString& title, int16_t mode);
+    NS_IMETHODIMP Init(nsIDOMWindow* aParent, const nsAString& aTitle, int16_t aMode);
     NS_IMETHODIMP AppendFilter(const nsAString& aTitle, const nsAString& aFilter);
     NS_IMETHODIMP GetDefaultString(nsAString& aDefaultString);
     NS_IMETHODIMP SetDefaultString(const nsAString& aDefaultString);
     NS_IMETHODIMP GetDefaultExtension(nsAString& aDefaultExtension);
     NS_IMETHODIMP SetDefaultExtension(const nsAString& aDefaultExtension);
     NS_IMETHODIMP GetFilterIndex(int32_t* aFilterIndex);
     NS_IMETHODIMP SetFilterIndex(int32_t aFilterIndex);
     NS_IMETHODIMP GetFile(nsIFile** aFile);
     NS_IMETHODIMP GetFileURL(nsIURI** aFileURL);
     NS_IMETHODIMP GetFiles(nsISimpleEnumerator** aFiles);
     NS_IMETHODIMP Show(int16_t* aReturn);
+    NS_IMETHODIMP Open(nsIFilePickerShownCallback* aCallback);
+
+    // PFilePickerChild
+    virtual bool
+    Recv__delete__(const MaybeInputFiles& aFiles, const int16_t& aResult);
 
 private:
     ~nsFilePickerProxy();
     void InitNative(nsIWidget*, const nsAString&);
 
     nsCOMArray<nsIFile> mFiles;
+    nsCOMPtr<nsIFilePickerShownCallback> mCallback;
 
     int16_t   mSelectedType;
     nsString  mFile;
-    nsString  mTitle;
     nsString  mDefault;
     nsString  mDefaultExtension;
 
     InfallibleTArray<nsString> mFilters;
     InfallibleTArray<nsString> mFilterNames;
 };
 
 #endif // NSFILEPICKERPROXY_H