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