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