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   CompletionHandler(const base::WeakPtr<PepperFileChooserHost>& host)
     28       : host_(host) {
     29   }
     30 
     31   virtual ~CompletionHandler() {}
     32 
     33   virtual void didChooseFile(
     34       const blink::WebVector<blink::WebString>& file_names) {
     35     if (host_.get()) {
     36       std::vector<PepperFileChooserHost::ChosenFileInfo> files;
     37       for (size_t i = 0; i < file_names.size(); i++) {
     38         files.push_back(PepperFileChooserHost::ChosenFileInfo(
     39             file_names[i].utf8(), std::string()));
     40       }
     41       host_->StoreChosenFiles(files);
     42     }
     43 
     44     // It is the responsibility of this method to delete the instance.
     45     delete this;
     46   }
     47   virtual void didChooseFile(
     48       const blink::WebVector<SelectedFileInfo>& file_names) {
     49     if (host_.get()) {
     50       std::vector<PepperFileChooserHost::ChosenFileInfo> files;
     51       for (size_t i = 0; i < file_names.size(); i++) {
     52         files.push_back(PepperFileChooserHost::ChosenFileInfo(
     53             file_names[i].path.utf8(),
     54             file_names[i].displayName.utf8()));
     55       }
     56       host_->StoreChosenFiles(files);
     57     }
     58 
     59     // It is the responsibility of this method to delete the instance.
     60     delete this;
     61   }
     62 
     63  private:
     64   base::WeakPtr<PepperFileChooserHost> host_;
     65 
     66   DISALLOW_COPY_AND_ASSIGN(CompletionHandler);
     67 };
     68 
     69 PepperFileChooserHost::ChosenFileInfo::ChosenFileInfo(
     70     const std::string& path,
     71     const std::string& display_name)
     72     : path(path),
     73       display_name(display_name) {
     74 }
     75 
     76 
     77 PepperFileChooserHost::PepperFileChooserHost(
     78     RendererPpapiHost* host,
     79     PP_Instance instance,
     80     PP_Resource resource)
     81     : ResourceHost(host->GetPpapiHost(), instance, resource),
     82       renderer_ppapi_host_(host),
     83       handler_(NULL),
     84       weak_factory_(this) {
     85 }
     86 
     87 PepperFileChooserHost::~PepperFileChooserHost() {
     88 }
     89 
     90 int32_t PepperFileChooserHost::OnResourceMessageReceived(
     91     const IPC::Message& msg,
     92     ppapi::host::HostMessageContext* context) {
     93   IPC_BEGIN_MESSAGE_MAP(PepperFileChooserHost, msg)
     94     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileChooser_Show, OnShow)
     95   IPC_END_MESSAGE_MAP()
     96   return PP_ERROR_FAILED;
     97 }
     98 
     99 void PepperFileChooserHost::StoreChosenFiles(
    100     const std::vector<ChosenFileInfo>& files) {
    101   std::vector<IPC::Message> create_msgs;
    102   std::vector<base::FilePath> file_paths;
    103   std::vector<std::string> display_names;
    104   for (size_t i = 0; i < files.size(); i++) {
    105 #if defined(OS_WIN)
    106     base::FilePath file_path(UTF8ToWide(files[i].path));
    107 #else
    108     base::FilePath file_path(files[i].path);
    109 #endif
    110     file_paths.push_back(file_path);
    111     create_msgs.push_back(PpapiHostMsg_FileRef_CreateExternal(file_path));
    112     display_names.push_back(files[i].display_name);
    113   }
    114 
    115   if (!files.empty()) {
    116     renderer_ppapi_host_->CreateBrowserResourceHosts(
    117         pp_instance(),
    118         create_msgs,
    119         base::Bind(&PepperFileChooserHost::DidCreateResourceHosts,
    120                    weak_factory_.GetWeakPtr(),
    121                    file_paths,
    122                    display_names));
    123   } else {
    124     reply_context_.params.set_result(PP_ERROR_USERCANCEL);
    125     std::vector<ppapi::FileRefCreateInfo> chosen_files;
    126     host()->SendReply(reply_context_,
    127                       PpapiPluginMsg_FileChooser_ShowReply(chosen_files));
    128     reply_context_ = ppapi::host::ReplyMessageContext();
    129     handler_ = NULL;  // Handler deletes itself.
    130   }
    131 }
    132 
    133 int32_t PepperFileChooserHost::OnShow(
    134     ppapi::host::HostMessageContext* context,
    135     bool save_as,
    136     bool open_multiple,
    137     const std::string& suggested_file_name,
    138     const std::vector<std::string>& accept_mime_types) {
    139   if (handler_)
    140     return PP_ERROR_INPROGRESS;  // Already pending.
    141 
    142   if (!host()->permissions().HasPermission(
    143           ppapi::PERMISSION_BYPASS_USER_GESTURE) &&
    144        !renderer_ppapi_host_->HasUserGesture(pp_instance())) {
    145     return PP_ERROR_NO_USER_GESTURE;
    146   }
    147 
    148   blink::WebFileChooserParams params;
    149   if (save_as) {
    150     params.saveAs = true;
    151     params.initialValue = blink::WebString::fromUTF8(
    152         suggested_file_name.data(), suggested_file_name.size());
    153   } else {
    154     params.multiSelect = open_multiple;
    155   }
    156   std::vector<blink::WebString> mine_types(accept_mime_types.size());
    157   for (size_t i = 0; i < accept_mime_types.size(); i++) {
    158     mine_types[i] = blink::WebString::fromUTF8(
    159         accept_mime_types[i].data(), accept_mime_types[i].size());
    160   }
    161   params.acceptTypes = mine_types;
    162   params.directory = false;
    163 
    164   handler_ = new CompletionHandler(AsWeakPtr());
    165   RenderViewImpl* render_view = static_cast<RenderViewImpl*>(
    166       renderer_ppapi_host_->GetRenderViewForInstance(pp_instance()));
    167   if (!render_view || !render_view->runFileChooser(params, handler_)) {
    168     delete handler_;
    169     handler_ = NULL;
    170     return PP_ERROR_NOACCESS;
    171   }
    172 
    173   reply_context_ = context->MakeReplyMessageContext();
    174   return PP_OK_COMPLETIONPENDING;
    175 }
    176 
    177 void PepperFileChooserHost::DidCreateResourceHosts(
    178     const std::vector<base::FilePath>& file_paths,
    179     const std::vector<std::string>& display_names,
    180     const std::vector<int>& browser_ids) {
    181   DCHECK(file_paths.size() == display_names.size());
    182   DCHECK(file_paths.size() == browser_ids.size());
    183 
    184   std::vector<ppapi::FileRefCreateInfo> chosen_files;
    185   for (size_t i = 0; i < browser_ids.size(); ++i) {
    186     PepperFileRefRendererHost* renderer_host =
    187         new PepperFileRefRendererHost(renderer_ppapi_host_,
    188                                       pp_instance(),
    189                                       0,
    190                                       file_paths[i]);
    191     int renderer_id =
    192         renderer_ppapi_host_->GetPpapiHost()->AddPendingResourceHost(
    193             scoped_ptr<ppapi::host::ResourceHost>(renderer_host));
    194     ppapi::FileRefCreateInfo info = ppapi::MakeExternalFileRefCreateInfo(
    195         file_paths[i], display_names[i], browser_ids[i], renderer_id);
    196     chosen_files.push_back(info);
    197   }
    198 
    199   reply_context_.params.set_result(PP_OK);
    200   host()->SendReply(reply_context_,
    201                     PpapiPluginMsg_FileChooser_ShowReply(chosen_files));
    202   reply_context_ = ppapi::host::ReplyMessageContext();
    203   handler_ = NULL;  // Handler deletes itself.
    204 }
    205 
    206 }  // namespace content
    207 
    208