Bumping manifests a=b2g-bump
[gecko.git] / dom / ipc / FilePickerParent.cpp
blobc772bbf314c023a7360ef8948dd478c586e34e04
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set sw=4 ts=8 et tw=80 :
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FilePickerParent.h"
8 #include "nsComponentManagerUtils.h"
9 #include "nsDOMFile.h"
10 #include "nsNetCID.h"
11 #include "nsIDocument.h"
12 #include "nsIDOMFile.h"
13 #include "nsIDOMWindow.h"
14 #include "nsIFile.h"
15 #include "nsISimpleEnumerator.h"
16 #include "mozilla/unused.h"
17 #include "mozilla/dom/ContentParent.h"
18 #include "mozilla/dom/Element.h"
19 #include "mozilla/dom/TabParent.h"
20 #include "mozilla/dom/ipc/Blob.h"
22 using mozilla::unused;
23 using namespace mozilla::dom;
25 NS_IMPL_ISUPPORTS(FilePickerParent::FilePickerShownCallback,
26 nsIFilePickerShownCallback);
28 NS_IMETHODIMP
29 FilePickerParent::FilePickerShownCallback::Done(int16_t aResult)
31 if (mFilePickerParent) {
32 mFilePickerParent->Done(aResult);
34 return NS_OK;
37 void
38 FilePickerParent::FilePickerShownCallback::Destroy()
40 mFilePickerParent = nullptr;
43 FilePickerParent::~FilePickerParent()
47 // Before sending a blob to the child, we need to get its size and modification
48 // date. Otherwise it will be sent as a "mystery blob" by
49 // GetOrCreateActorForBlob, which will cause problems for the child
50 // process. This runnable stat()s the file off the main thread.
52 // We run code in three places:
53 // 1. The main thread calls Dispatch() to start the runnable.
54 // 2. The stream transport thread stat()s the file in Run() and then dispatches
55 // the same runnable on the main thread.
56 // 3. The main thread sends the results over IPC.
57 FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
58 nsCOMArray<nsIDOMFile>& aDomfiles)
59 : mFilePickerParent(aFPParent)
61 mDomfiles.SwapElements(aDomfiles);
64 bool
65 FilePickerParent::FileSizeAndDateRunnable::Dispatch()
67 MOZ_ASSERT(NS_IsMainThread());
69 mEventTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
70 if (!mEventTarget) {
71 return false;
74 nsresult rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
75 return NS_SUCCEEDED(rv);
78 NS_IMETHODIMP
79 FilePickerParent::FileSizeAndDateRunnable::Run()
81 // If we're on the main thread, then that means we're done. Just send the
82 // results.
83 if (NS_IsMainThread()) {
84 if (mFilePickerParent) {
85 mFilePickerParent->SendFiles(mDomfiles);
87 return NS_OK;
90 // We're not on the main thread, so do the stat().
91 for (unsigned i = 0; i < mDomfiles.Length(); i++) {
92 uint64_t size, lastModified;
93 mDomfiles[i]->GetSize(&size);
94 mDomfiles[i]->GetMozLastModifiedDate(&lastModified);
97 // Dispatch ourselves back on the main thread.
98 if (NS_FAILED(NS_DispatchToMainThread(this))) {
99 // It's hard to see how we can recover gracefully in this case. The child
100 // process is waiting for an IPC, but that can only happen on the main
101 // thread.
102 MOZ_CRASH();
104 return NS_OK;
107 void
108 FilePickerParent::FileSizeAndDateRunnable::Destroy()
110 mFilePickerParent = nullptr;
113 void
114 FilePickerParent::SendFiles(const nsCOMArray<nsIDOMFile>& aDomfiles)
116 nsIContentParent* parent = static_cast<TabParent*>(Manager())->Manager();
117 InfallibleTArray<PBlobParent*> files;
119 for (unsigned i = 0; i < aDomfiles.Length(); i++) {
120 BlobParent* blob = parent->GetOrCreateActorForBlob(aDomfiles[i]);
121 if (blob) {
122 files.AppendElement(blob);
126 InputFiles infiles;
127 infiles.filesParent().SwapElements(files);
128 unused << Send__delete__(this, infiles, mResult);
131 void
132 FilePickerParent::Done(int16_t aResult)
134 mResult = aResult;
136 if (mResult != nsIFilePicker::returnOK) {
137 unused << Send__delete__(this, void_t(), mResult);
138 return;
141 nsCOMArray<nsIDOMFile> domfiles;
142 if (mMode == nsIFilePicker::modeOpenMultiple) {
143 nsCOMPtr<nsISimpleEnumerator> iter;
144 NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
146 nsCOMPtr<nsISupports> supports;
147 bool loop = true;
148 while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
149 iter->GetNext(getter_AddRefs(supports));
150 if (supports) {
151 nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
152 nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(file);
153 domfiles.AppendElement(domfile);
156 } else {
157 nsCOMPtr<nsIFile> file;
158 mFilePicker->GetFile(getter_AddRefs(file));
159 if (file) {
160 nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(file);
161 domfiles.AppendElement(domfile);
165 MOZ_ASSERT(!mRunnable);
166 mRunnable = new FileSizeAndDateRunnable(this, domfiles);
167 if (!mRunnable->Dispatch()) {
168 unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
172 bool
173 FilePickerParent::CreateFilePicker()
175 mFilePicker = do_CreateInstance("@mozilla.org/filepicker;1");
176 if (!mFilePicker) {
177 return false;
180 Element* element = static_cast<TabParent*>(Manager())->GetOwnerElement();
181 if (!element) {
182 return false;
185 nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(element->OwnerDoc()->GetWindow());
186 if (!window) {
187 return false;
190 return NS_SUCCEEDED(mFilePicker->Init(window, mTitle, mMode));
193 bool
194 FilePickerParent::RecvOpen(const int16_t& aSelectedType,
195 const bool& aAddToRecentDocs,
196 const nsString& aDefaultFile,
197 const nsString& aDefaultExtension,
198 const InfallibleTArray<nsString>& aFilters,
199 const InfallibleTArray<nsString>& aFilterNames)
201 if (!CreateFilePicker()) {
202 unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
203 return true;
206 mFilePicker->SetAddToRecentDocs(aAddToRecentDocs);
208 for (uint32_t i = 0; i < aFilters.Length(); ++i) {
209 mFilePicker->AppendFilter(aFilterNames[i], aFilters[i]);
212 mFilePicker->SetDefaultString(aDefaultFile);
213 mFilePicker->SetDefaultExtension(aDefaultExtension);
214 mFilePicker->SetFilterIndex(aSelectedType);
216 mCallback = new FilePickerShownCallback(this);
218 mFilePicker->Open(mCallback);
219 return true;
222 void
223 FilePickerParent::ActorDestroy(ActorDestroyReason aWhy)
225 if (mCallback) {
226 mCallback->Destroy();
227 mCallback = nullptr;
229 if (mRunnable) {
230 mRunnable->Destroy();
231 mRunnable = nullptr;