Home | History | Annotate | Download | only in pepper
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/pepper/pepper_file_chooser_host.h"
      6 
      7 #include "base/files/file_path.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "content/public/renderer/renderer_ppapi_host.h"
     10 #include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
     11 #include "content/renderer/render_view_impl.h"
     12 #include "ppapi/c/pp_errors.h"
     13 #include "ppapi/host/dispatch_host_message.h"
     14 #include "ppapi/host/ppapi_host.h"
     15 #include "ppapi/proxy/ppapi_messages.h"
     16 #include "third_party/WebKit/public/platform/WebCString.h"
     17 #include "third_party/WebKit/public/platform/WebString.h"
     18 #include "third_party/WebKit/public/platform/WebVector.h"
     19 #include "third_party/WebKit/public/web/WebFileChooserCompletion.h"
     20 #include "third_party/WebKit/public/web/WebFileChooserParams.h"
     21 
     22 namespace content {
     23 
     24 class PepperFileChooserHost::CompletionHandler
     25     : public blink::WebFileChooserCompletion {
     26  public:
     27   explicit CompletionHandler(const base::WeakPtr<PepperFileChooserHost>& host)
     28       : host_(host) {}
     29 
     30   virtual ~CompletionHandler() {}
     31 
     32   virtual void didChooseFile(
     33       const blink::WebVector<blink::WebString>& file_names) {
     34     if (host_.get()) {
     35       std::vector<PepperFileChooserHost::ChosenFileInfo> files;
     36       for (size_t i = 0; i < file_names.size(); i++) {
     37         files.push_back(PepperFileChooserHost::ChosenFileInfo(
     38             file_names[i].utf8(), std::string()));
     39       }
     40       host_->StoreChosenFiles(files);
     41     }
     42 
     43     // It is the responsibility of this method to delete the instance.
     44     delete this;
     45   }
     46   virtual void didChooseFile(
     47       const blink::WebVector<SelectedFileInfo>& file_names) {
     48     if (host_.get()) {
     49       std::vector<PepperFileChooserHost::ChosenFileInfo> files;
     50       for (size_t i = 0; i < file_names.size(); i++) {
     51         files.push_back(PepperFileChooserHost::ChosenFileInfo(
     52             file_names[i].path.utf8(), file_names[i].displayName.utf8()));
     53       }
     54       host_->StoreChosenFiles(files);
     55     }
     56 
     57     // It is the responsibility of this method to delete the instance.
     58     delete this;
     59   }
     60 
     61  private:
     62   base::WeakPtr<PepperFileChooserHost> host_;
     63 
     64   DISALLOW_COPY_AND_ASSIGN(CompletionHandler);
     65 };
     66 
     67 PepperFileChooserHost::ChosenFileInfo::ChosenFileInfo(
     68     const std::string& path,
     69     const std::string& display_name)
     70     : path(path), display_name(display_name) {}
     71 
     72 PepperFileChooserHost::PepperFileChooserHost(RendererPpapiHost* host,
     73                                              PP_Instance instance,
     74                                              PP_Resource resource)
     75     : ResourceHost(host->GetPpapiHost(), instance, resource),
     76       renderer_ppapi_host_(host),
     77       handler_(NULL),
     78       weak_factory_(this) {}
     79 
     80 PepperFileChooserHost::~PepperFileChooserHost() {}
     81 
     82 int32_t PepperFileChooserHost::OnResourceMessageReceived(
     83     const IPC::Message& msg,
     84     ppapi::host::HostMessageContext* context) {
     85   PPAPI_BEGIN_MESSAGE_MAP(PepperFileChooserHost, msg)
     86     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileChooser_Show, OnShow)
     87   PPAPI_END_MESSAGE_MAP()
     88   return PP_ERROR_FAILED;
     89 }
     90 
     91 void PepperFileChooserHost::StoreChosenFiles(
     92     const std::vector<ChosenFileInfo>& files) {
     93   std::vector<IPC::Message> create_msgs;
     94   std::vector<base::FilePath> file_paths;
     95   std::vector<std::string> display_names;
     96   for (size_t i = 0; i < files.size(); i++) {
     97 #if defined(OS_WIN)
     98     base::FilePath file_path(base::UTF8ToWide(files[i].path));
     99 #else
    100     base::FilePath file_path(files[i].path);
    101 #endif
    102     file_paths.push_back(file_path);
    103     create_msgs.push_back(PpapiHostMsg_FileRef_CreateForRawFS(file_path));
    104     display_names.push_back(files[i].display_name);
    105   }
    106 
    107   if (!files.empty()) {
    108     renderer_ppapi_host_->CreateBrowserResourceHosts(
    109         pp_instance(),
    110         create_msgs,
    111         base::Bind(&PepperFileChooserHost::DidCreateResourceHosts,
    112                    weak_factory_.GetWeakPtr(),
    113                    file_paths,
    114                    display_names));
    115   } else {
    116     reply_context_.params.set_result(PP_ERROR_USERCANCEL);
    117     std::vector<ppapi::FileRefCreateInfo> chosen_files;
    118     host()->SendReply(reply_context_,
    119                       PpapiPluginMsg_FileChooser_ShowReply(chosen_files));
    120     reply_context_ = ppapi::host::ReplyMessageContext();
    121     handler_ = NULL;  // Handler deletes itself.
    122   }
    123 }
    124 
    125 int32_t PepperFileChooserHost::OnShow(
    126     ppapi::host::HostMessageContext* context,
    127     bool save_as,
    128     bool open_multiple,
    129     const std::string& suggested_file_name,
    130     const std::vector<std::string>& accept_mime_types) {
    131   if (handler_)
    132     return PP_ERROR_INPROGRESS;  // Already pending.
    133 
    134   if (!host()->permissions().HasPermission(
    135           ppapi::PERMISSION_BYPASS_USER_GESTURE) &&
    136       !renderer_ppapi_host_->HasUserGesture(pp_instance())) {
    137     return PP_ERROR_NO_USER_GESTURE;
    138   }
    139 
    140   blink::WebFileChooserParams params;
    141   if (save_as) {
    142     params.saveAs = true;
    143     params.initialValue = blink::WebString::fromUTF8(
    144         suggested_file_name.data(), suggested_file_name.size());
    145   } else {
    146     params.multiSelect = open_multiple;
    147   }
    148   std::vector<blink::WebString> mine_types(accept_mime_types.size());
    149   for (size_t i = 0; i < accept_mime_types.size(); i++) {
    150     mine_types[i] = blink::WebString::fromUTF8(accept_mime_types[i].data(),
    151                                                accept_mime_types[i].size());
    152   }
    153   params.acceptTypes = mine_types;
    154   params.directory = false;
    155 
    156   handler_ = new CompletionHandler(AsWeakPtr());
    157   RenderViewImpl* render_view = static_cast<RenderViewImpl*>(
    158       renderer_ppapi_host_->GetRenderViewForInstance(pp_instance()));
    159   if (!render_view || !render_view->runFileChooser(params, handler_)) {
    160     delete handler_;
    161     handler_ = NULL;
    162     return PP_ERROR_NOACCESS;
    163   }
    164 
    165   reply_context_ = context->MakeReplyMessageContext();
    166   return PP_OK_COMPLETIONPENDING;
    167 }
    168 
    169 void PepperFileChooserHost::DidCreateResourceHosts(
    170     const std::vector<base::FilePath>& file_paths,
    171     const std::vector<std::string>& display_names,
    172     const std::vector<int>& browser_ids) {
    173   DCHECK(file_paths.size() == display_names.size());
    174   DCHECK(file_paths.size() == browser_ids.size());
    175 
    176   std::vector<ppapi::FileRefCreateInfo> chosen_files;
    177   for (size_t i = 0; i < browser_ids.size(); ++i) {
    178     PepperFileRefRendererHost* renderer_host = new PepperFileRefRendererHost(
    179         renderer_ppapi_host_, pp_instance(), 0, file_paths[i]);
    180     int renderer_id =
    181         renderer_ppapi_host_->GetPpapiHost()->AddPendingResourceHost(
    182             scoped_ptr<ppapi::host::ResourceHost>(renderer_host));
    183     ppapi::FileRefCreateInfo info = ppapi::MakeExternalFileRefCreateInfo(
    184         file_paths[i], display_names[i], browser_ids[i], renderer_id);
    185     chosen_files.push_back(info);
    186   }
    187 
    188   reply_context_.params.set_result(PP_OK);
    189   host()->SendReply(reply_context_,
    190                     PpapiPluginMsg_FileChooser_ShowReply(chosen_files));
    191   reply_context_ = ppapi::host::ReplyMessageContext();
    192   handler_ = NULL;  // Handler deletes itself.
    193 }
    194 
    195 }  // namespace content
    196