dom/ipc/FilePickerParent.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/ipc/FilePickerParent.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,233 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * vim: set sw=4 ts=8 et tw=80 :
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "FilePickerParent.h"
    1.11 +#include "nsComponentManagerUtils.h"
    1.12 +#include "nsDOMFile.h"
    1.13 +#include "nsNetCID.h"
    1.14 +#include "nsIDocument.h"
    1.15 +#include "nsIDOMFile.h"
    1.16 +#include "nsIDOMWindow.h"
    1.17 +#include "nsIFile.h"
    1.18 +#include "nsISimpleEnumerator.h"
    1.19 +#include "mozilla/unused.h"
    1.20 +#include "mozilla/dom/ContentParent.h"
    1.21 +#include "mozilla/dom/Element.h"
    1.22 +#include "mozilla/dom/TabParent.h"
    1.23 +#include "mozilla/dom/ipc/Blob.h"
    1.24 +
    1.25 +using mozilla::unused;
    1.26 +using namespace mozilla::dom;
    1.27 +
    1.28 +NS_IMPL_ISUPPORTS(FilePickerParent::FilePickerShownCallback,
    1.29 +                  nsIFilePickerShownCallback);
    1.30 +
    1.31 +NS_IMETHODIMP
    1.32 +FilePickerParent::FilePickerShownCallback::Done(int16_t aResult)
    1.33 +{
    1.34 +  if (mFilePickerParent) {
    1.35 +    mFilePickerParent->Done(aResult);
    1.36 +  }
    1.37 +  return NS_OK;
    1.38 +}
    1.39 +
    1.40 +void
    1.41 +FilePickerParent::FilePickerShownCallback::Destroy()
    1.42 +{
    1.43 +  mFilePickerParent = nullptr;
    1.44 +}
    1.45 +
    1.46 +FilePickerParent::~FilePickerParent()
    1.47 +{
    1.48 +}
    1.49 +
    1.50 +// Before sending a blob to the child, we need to get its size and modification
    1.51 +// date. Otherwise it will be sent as a "mystery blob" by
    1.52 +// GetOrCreateActorForBlob, which will cause problems for the child
    1.53 +// process. This runnable stat()s the file off the main thread.
    1.54 +//
    1.55 +// We run code in three places:
    1.56 +// 1. The main thread calls Dispatch() to start the runnable.
    1.57 +// 2. The stream transport thread stat()s the file in Run() and then dispatches
    1.58 +// the same runnable on the main thread.
    1.59 +// 3. The main thread sends the results over IPC.
    1.60 +FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
    1.61 +                                                                   nsCOMArray<nsIDOMFile>& aDomfiles)
    1.62 + : mFilePickerParent(aFPParent)
    1.63 +{
    1.64 +  mDomfiles.SwapElements(aDomfiles);
    1.65 +}
    1.66 +
    1.67 +bool
    1.68 +FilePickerParent::FileSizeAndDateRunnable::Dispatch()
    1.69 +{
    1.70 +  MOZ_ASSERT(NS_IsMainThread());
    1.71 +
    1.72 +  mEventTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
    1.73 +  if (!mEventTarget) {
    1.74 +    return false;
    1.75 +  }
    1.76 +
    1.77 +  nsresult rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
    1.78 +  return NS_SUCCEEDED(rv);
    1.79 +}
    1.80 +
    1.81 +NS_IMETHODIMP
    1.82 +FilePickerParent::FileSizeAndDateRunnable::Run()
    1.83 +{
    1.84 +  // If we're on the main thread, then that means we're done. Just send the
    1.85 +  // results.
    1.86 +  if (NS_IsMainThread()) {
    1.87 +    if (mFilePickerParent) {
    1.88 +      mFilePickerParent->SendFiles(mDomfiles);
    1.89 +    }
    1.90 +    return NS_OK;
    1.91 +  }
    1.92 +
    1.93 +  // We're not on the main thread, so do the stat().
    1.94 +  for (unsigned i = 0; i < mDomfiles.Length(); i++) {
    1.95 +    uint64_t size, lastModified;
    1.96 +    mDomfiles[i]->GetSize(&size);
    1.97 +    mDomfiles[i]->GetMozLastModifiedDate(&lastModified);
    1.98 +  }
    1.99 +
   1.100 +  // Dispatch ourselves back on the main thread.
   1.101 +  if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
   1.102 +    // It's hard to see how we can recover gracefully in this case. The child
   1.103 +    // process is waiting for an IPC, but that can only happen on the main
   1.104 +    // thread.
   1.105 +    MOZ_CRASH();
   1.106 +  }
   1.107 +  return NS_OK;
   1.108 +}
   1.109 +
   1.110 +void
   1.111 +FilePickerParent::FileSizeAndDateRunnable::Destroy()
   1.112 +{
   1.113 +  mFilePickerParent = nullptr;
   1.114 +}
   1.115 +
   1.116 +void
   1.117 +FilePickerParent::SendFiles(const nsCOMArray<nsIDOMFile>& aDomfiles)
   1.118 +{
   1.119 +  ContentParent* parent = static_cast<ContentParent*>(Manager()->Manager());
   1.120 +  InfallibleTArray<PBlobParent*> files;
   1.121 +
   1.122 +  for (unsigned i = 0; i < aDomfiles.Length(); i++) {
   1.123 +    BlobParent* blob = parent->GetOrCreateActorForBlob(aDomfiles[i]);
   1.124 +    if (blob) {
   1.125 +      files.AppendElement(blob);
   1.126 +    }
   1.127 +  }
   1.128 +
   1.129 +  InputFiles infiles;
   1.130 +  infiles.filesParent().SwapElements(files);
   1.131 +  unused << Send__delete__(this, infiles, mResult);
   1.132 +}
   1.133 +
   1.134 +void
   1.135 +FilePickerParent::Done(int16_t aResult)
   1.136 +{
   1.137 +  mResult = aResult;
   1.138 +
   1.139 +  if (mResult != nsIFilePicker::returnOK) {
   1.140 +    unused << Send__delete__(this, void_t(), mResult);
   1.141 +    return;
   1.142 +  }
   1.143 +
   1.144 +  nsCOMArray<nsIDOMFile> domfiles;
   1.145 +  if (mMode == nsIFilePicker::modeOpenMultiple) {
   1.146 +    nsCOMPtr<nsISimpleEnumerator> iter;
   1.147 +    NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
   1.148 +
   1.149 +    nsCOMPtr<nsISupports> supports;
   1.150 +    bool loop = true;
   1.151 +    while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
   1.152 +      iter->GetNext(getter_AddRefs(supports));
   1.153 +      if (supports) {
   1.154 +        nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
   1.155 +        nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
   1.156 +        domfiles.AppendElement(domfile);
   1.157 +      }
   1.158 +    }
   1.159 +  } else {
   1.160 +    nsCOMPtr<nsIFile> file;
   1.161 +    mFilePicker->GetFile(getter_AddRefs(file));
   1.162 +    if (file) {
   1.163 +      nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
   1.164 +      domfiles.AppendElement(domfile);
   1.165 +    }
   1.166 +  }
   1.167 +
   1.168 +  MOZ_ASSERT(!mRunnable);
   1.169 +  mRunnable = new FileSizeAndDateRunnable(this, domfiles);
   1.170 +  if (!mRunnable->Dispatch()) {
   1.171 +    unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
   1.172 +  }
   1.173 +}
   1.174 +
   1.175 +bool
   1.176 +FilePickerParent::CreateFilePicker()
   1.177 +{
   1.178 +  mFilePicker = do_CreateInstance("@mozilla.org/filepicker;1");
   1.179 +  if (!mFilePicker) {
   1.180 +    return false;
   1.181 +  }
   1.182 +
   1.183 +  Element* element = static_cast<TabParent*>(Manager())->GetOwnerElement();
   1.184 +  if (!element) {
   1.185 +    return false;
   1.186 +  }
   1.187 +
   1.188 +  nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(element->OwnerDoc()->GetWindow());
   1.189 +  if (!window) {
   1.190 +    return false;
   1.191 +  }
   1.192 +
   1.193 +  return NS_SUCCEEDED(mFilePicker->Init(window, mTitle, mMode));
   1.194 +}
   1.195 +
   1.196 +bool
   1.197 +FilePickerParent::RecvOpen(const int16_t& aSelectedType,
   1.198 +                           const bool& aAddToRecentDocs,
   1.199 +                           const nsString& aDefaultFile,
   1.200 +                           const nsString& aDefaultExtension,
   1.201 +                           const InfallibleTArray<nsString>& aFilters,
   1.202 +                           const InfallibleTArray<nsString>& aFilterNames)
   1.203 +{
   1.204 +  if (!CreateFilePicker()) {
   1.205 +    unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
   1.206 +    return true;
   1.207 +  }
   1.208 +
   1.209 +  mFilePicker->SetAddToRecentDocs(aAddToRecentDocs);
   1.210 +
   1.211 +  for (uint32_t i = 0; i < aFilters.Length(); ++i) {
   1.212 +    mFilePicker->AppendFilter(aFilterNames[i], aFilters[i]);
   1.213 +  }
   1.214 +
   1.215 +  mFilePicker->SetDefaultString(aDefaultFile);
   1.216 +  mFilePicker->SetDefaultExtension(aDefaultExtension);
   1.217 +  mFilePicker->SetFilterIndex(aSelectedType);
   1.218 +
   1.219 +  mCallback = new FilePickerShownCallback(this);
   1.220 +
   1.221 +  mFilePicker->Open(mCallback);
   1.222 +  return true;
   1.223 +}
   1.224 +
   1.225 +void
   1.226 +FilePickerParent::ActorDestroy(ActorDestroyReason aWhy)
   1.227 +{
   1.228 +  if (mCallback) {
   1.229 +    mCallback->Destroy();
   1.230 +    mCallback = nullptr;
   1.231 +  }
   1.232 +  if (mRunnable) {
   1.233 +    mRunnable->Destroy();
   1.234 +    mRunnable = nullptr;
   1.235 +  }
   1.236 +}

mercurial