Bug 1867190 - Initialise the PHC allocate delay later r=glandium
[gecko.git] / dom / ipc / FilePickerParent.cpp
blobebd24cb0d3f481b1b7c0d4693d82ea8af8698999
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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 "nsNetCID.h"
10 #include "mozilla/dom/Document.h"
11 #include "nsIFile.h"
12 #include "nsISimpleEnumerator.h"
13 #include "mozilla/Unused.h"
14 #include "mozilla/dom/BrowserParent.h"
15 #include "mozilla/dom/CanonicalBrowsingContext.h"
16 #include "mozilla/dom/ContentParent.h"
17 #include "mozilla/dom/Element.h"
18 #include "mozilla/dom/FileBlobImpl.h"
19 #include "mozilla/dom/FileSystemSecurity.h"
20 #include "mozilla/dom/IPCBlobUtils.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(
30 nsIFilePicker::ResultCode aResult) {
31 if (mFilePickerParent) {
32 mFilePickerParent->Done(aResult);
34 return NS_OK;
37 void FilePickerParent::FilePickerShownCallback::Destroy() {
38 mFilePickerParent = nullptr;
41 FilePickerParent::~FilePickerParent() = default;
43 // We run code in three places:
44 // 1. The main thread calls Dispatch() to start the runnable.
45 // 2. The stream transport thread stat()s the file in Run() and then dispatches
46 // the same runnable on the main thread.
47 // 3. The main thread sends the results over IPC.
48 FilePickerParent::IORunnable::IORunnable(FilePickerParent* aFPParent,
49 nsTArray<nsCOMPtr<nsIFile>>&& aFiles,
50 bool aIsDirectory)
51 : mozilla::Runnable("dom::FilePickerParent::IORunnable"),
52 mFilePickerParent(aFPParent),
53 mFiles(std::move(aFiles)),
54 mIsDirectory(aIsDirectory) {
55 MOZ_ASSERT_IF(aIsDirectory, mFiles.Length() == 1);
58 bool FilePickerParent::IORunnable::Dispatch() {
59 MOZ_ASSERT(NS_IsMainThread());
61 mEventTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
62 if (!mEventTarget) {
63 return false;
66 nsresult rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
67 return NS_SUCCEEDED(rv);
70 NS_IMETHODIMP
71 FilePickerParent::IORunnable::Run() {
72 // If we're on the main thread, then that means we're done. Just send the
73 // results.
74 if (NS_IsMainThread()) {
75 if (mFilePickerParent) {
76 mFilePickerParent->SendFilesOrDirectories(mResults);
78 return NS_OK;
81 // We're not on the main thread, so do the IO.
83 for (uint32_t i = 0; i < mFiles.Length(); ++i) {
84 if (mIsDirectory) {
85 nsAutoString path;
86 nsresult rv = mFiles[i]->GetPath(path);
87 if (NS_WARN_IF(NS_FAILED(rv))) {
88 continue;
91 BlobImplOrString* data = mResults.AppendElement();
92 data->mType = BlobImplOrString::eDirectoryPath;
93 data->mDirectoryPath = path;
94 continue;
97 RefPtr<BlobImpl> blobImpl = new FileBlobImpl(mFiles[i]);
99 ErrorResult error;
100 blobImpl->GetSize(error);
101 if (NS_WARN_IF(error.Failed())) {
102 error.SuppressException();
103 continue;
106 blobImpl->GetLastModified(error);
107 if (NS_WARN_IF(error.Failed())) {
108 error.SuppressException();
109 continue;
112 BlobImplOrString* data = mResults.AppendElement();
113 data->mType = BlobImplOrString::eBlobImpl;
114 data->mBlobImpl = blobImpl;
117 // Dispatch ourselves back on the main thread.
118 if (NS_FAILED(NS_DispatchToMainThread(this))) {
119 // It's hard to see how we can recover gracefully in this case. The child
120 // process is waiting for an IPC, but that can only happen on the main
121 // thread.
122 MOZ_CRASH();
125 return NS_OK;
128 void FilePickerParent::IORunnable::Destroy() { mFilePickerParent = nullptr; }
130 void FilePickerParent::SendFilesOrDirectories(
131 const nsTArray<BlobImplOrString>& aData) {
132 ContentParent* parent = BrowserParent::GetFrom(Manager())->Manager();
134 if (mMode == nsIFilePicker::modeGetFolder) {
135 MOZ_ASSERT(aData.Length() <= 1);
136 if (aData.IsEmpty()) {
137 Unused << Send__delete__(this, void_t(), mResult);
138 return;
141 MOZ_ASSERT(aData[0].mType == BlobImplOrString::eDirectoryPath);
143 // Let's inform the security singleton about the given access of this tab on
144 // this directory path.
145 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::GetOrCreate();
146 fss->GrantAccessToContentProcess(parent->ChildID(),
147 aData[0].mDirectoryPath);
149 InputDirectory input;
150 input.directoryPath() = aData[0].mDirectoryPath;
151 Unused << Send__delete__(this, input, mResult);
152 return;
155 nsTArray<IPCBlob> ipcBlobs;
157 for (unsigned i = 0; i < aData.Length(); i++) {
158 IPCBlob ipcBlob;
160 MOZ_ASSERT(aData[i].mType == BlobImplOrString::eBlobImpl);
161 nsresult rv = IPCBlobUtils::Serialize(aData[i].mBlobImpl, ipcBlob);
162 if (NS_WARN_IF(NS_FAILED(rv))) {
163 break;
166 ipcBlobs.AppendElement(ipcBlob);
169 InputBlobs inblobs;
170 inblobs.blobs() = std::move(ipcBlobs);
172 Unused << Send__delete__(this, inblobs, mResult);
175 void FilePickerParent::Done(nsIFilePicker::ResultCode aResult) {
176 mResult = aResult;
178 if (mResult != nsIFilePicker::returnOK) {
179 Unused << Send__delete__(this, void_t(), mResult);
180 return;
183 nsTArray<nsCOMPtr<nsIFile>> files;
184 if (mMode == nsIFilePicker::modeOpenMultiple) {
185 nsCOMPtr<nsISimpleEnumerator> iter;
186 NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
188 nsCOMPtr<nsISupports> supports;
189 bool loop = true;
190 while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
191 iter->GetNext(getter_AddRefs(supports));
192 if (supports) {
193 nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
194 MOZ_ASSERT(file);
195 files.AppendElement(file);
198 } else {
199 nsCOMPtr<nsIFile> file;
200 mFilePicker->GetFile(getter_AddRefs(file));
201 if (file) {
202 files.AppendElement(file);
206 if (files.IsEmpty()) {
207 Unused << Send__delete__(this, void_t(), mResult);
208 return;
211 MOZ_ASSERT(!mRunnable);
212 mRunnable = new IORunnable(this, std::move(files),
213 mMode == nsIFilePicker::modeGetFolder);
215 // Dispatch to background thread to do I/O:
216 if (!mRunnable->Dispatch()) {
217 Unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
221 bool FilePickerParent::CreateFilePicker() {
222 mFilePicker = do_CreateInstance("@mozilla.org/filepicker;1");
223 if (!mFilePicker) {
224 return false;
227 auto* browserParent = BrowserParent::GetFrom(Manager());
228 auto* browsingContext = browserParent->GetBrowsingContext();
229 Element* element = browserParent->GetOwnerElement();
230 if (!element) {
231 return false;
234 nsCOMPtr<mozIDOMWindowProxy> window = element->OwnerDoc()->GetWindow();
235 if (!window) {
236 return false;
239 return NS_SUCCEEDED(
240 mFilePicker->Init(window, mTitle, mMode, browsingContext));
243 mozilla::ipc::IPCResult FilePickerParent::RecvOpen(
244 const int16_t& aSelectedType, const bool& aAddToRecentDocs,
245 const nsString& aDefaultFile, const nsString& aDefaultExtension,
246 nsTArray<nsString>&& aFilters, nsTArray<nsString>&& aFilterNames,
247 nsTArray<nsString>&& aRawFilters, const nsString& aDisplayDirectory,
248 const nsString& aDisplaySpecialDirectory, const nsString& aOkButtonLabel,
249 const nsIFilePicker::CaptureTarget& aCapture) {
250 if (!CreateFilePicker()) {
251 Unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
252 return IPC_OK();
255 mFilePicker->SetAddToRecentDocs(aAddToRecentDocs);
257 for (uint32_t i = 0; i < aFilters.Length(); ++i) {
258 mFilePicker->AppendFilter(aFilterNames[i], aFilters[i]);
261 for (uint32_t i = 0; i < aRawFilters.Length(); ++i) {
262 mFilePicker->AppendRawFilter(aRawFilters[i]);
265 mFilePicker->SetDefaultString(aDefaultFile);
266 mFilePicker->SetDefaultExtension(aDefaultExtension);
267 mFilePicker->SetFilterIndex(aSelectedType);
268 mFilePicker->SetOkButtonLabel(aOkButtonLabel);
269 mFilePicker->SetCapture(aCapture);
271 if (!aDisplayDirectory.IsEmpty()) {
272 nsCOMPtr<nsIFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
273 if (localFile) {
274 localFile->InitWithPath(aDisplayDirectory);
275 mFilePicker->SetDisplayDirectory(localFile);
277 } else if (!aDisplaySpecialDirectory.IsEmpty()) {
278 mFilePicker->SetDisplaySpecialDirectory(aDisplaySpecialDirectory);
281 MOZ_ASSERT(!mCallback);
282 mCallback = new FilePickerShownCallback(this);
284 mFilePicker->Open(mCallback);
285 return IPC_OK();
288 mozilla::ipc::IPCResult FilePickerParent::RecvClose() {
289 if (mFilePicker) {
290 mFilePicker->Close();
292 return IPC_OK();
295 void FilePickerParent::ActorDestroy(ActorDestroyReason aWhy) {
296 if (mCallback) {
297 mCallback->Destroy();
298 mCallback = nullptr;
300 if (mRunnable) {
301 mRunnable->Destroy();
302 mRunnable = nullptr;