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/ppb_file_ref_impl.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 "ppapi/proxy/ppb_file_ref_proxy.h" 17 #include "third_party/WebKit/public/platform/WebCString.h" 18 #include "third_party/WebKit/public/platform/WebString.h" 19 #include "third_party/WebKit/public/platform/WebVector.h" 20 #include "third_party/WebKit/public/web/WebFileChooserCompletion.h" 21 #include "third_party/WebKit/public/web/WebFileChooserParams.h" 22 23 namespace content { 24 25 class PepperFileChooserHost::CompletionHandler 26 : public WebKit::WebFileChooserCompletion { 27 public: 28 CompletionHandler(const base::WeakPtr<PepperFileChooserHost>& host) 29 : host_(host) { 30 } 31 32 virtual ~CompletionHandler() {} 33 34 virtual void didChooseFile( 35 const WebKit::WebVector<WebKit::WebString>& file_names) { 36 if (host_.get()) { 37 std::vector<PepperFileChooserHost::ChosenFileInfo> files; 38 for (size_t i = 0; i < file_names.size(); i++) { 39 files.push_back(PepperFileChooserHost::ChosenFileInfo( 40 file_names[i].utf8(), std::string())); 41 } 42 host_->StoreChosenFiles(files); 43 } 44 45 // It is the responsibility of this method to delete the instance. 46 delete this; 47 } 48 virtual void didChooseFile( 49 const WebKit::WebVector<SelectedFileInfo>& file_names) { 50 if (host_.get()) { 51 std::vector<PepperFileChooserHost::ChosenFileInfo> files; 52 for (size_t i = 0; i < file_names.size(); i++) { 53 files.push_back(PepperFileChooserHost::ChosenFileInfo( 54 file_names[i].path.utf8(), 55 file_names[i].displayName.utf8())); 56 } 57 host_->StoreChosenFiles(files); 58 } 59 60 // It is the responsibility of this method to delete the instance. 61 delete this; 62 } 63 64 private: 65 base::WeakPtr<PepperFileChooserHost> host_; 66 67 DISALLOW_COPY_AND_ASSIGN(CompletionHandler); 68 }; 69 70 PepperFileChooserHost::ChosenFileInfo::ChosenFileInfo( 71 const std::string& path, 72 const std::string& display_name) 73 : path(path), 74 display_name(display_name) { 75 } 76 77 78 PepperFileChooserHost::PepperFileChooserHost( 79 RendererPpapiHost* host, 80 PP_Instance instance, 81 PP_Resource resource) 82 : ResourceHost(host->GetPpapiHost(), instance, resource), 83 renderer_ppapi_host_(host), 84 handler_(NULL) { 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<ppapi::PPB_FileRef_CreateInfo> chosen_files; 102 for (size_t i = 0; i < files.size(); i++) { 103 #if defined(OS_WIN) 104 base::FilePath file_path(UTF8ToWide(files[i].path)); 105 #else 106 base::FilePath file_path(files[i].path); 107 #endif 108 109 PPB_FileRef_Impl* ref = PPB_FileRef_Impl::CreateExternal( 110 pp_instance(), file_path, files[i].display_name); 111 ppapi::PPB_FileRef_CreateInfo create_info; 112 ppapi::proxy::PPB_FileRef_Proxy::SerializeFileRef(ref->GetReference(), 113 &create_info); 114 chosen_files.push_back(create_info); 115 } 116 117 reply_context_.params.set_result( 118 (chosen_files.size() > 0) ? PP_OK : PP_ERROR_USERCANCEL); 119 host()->SendReply(reply_context_, 120 PpapiPluginMsg_FileChooser_ShowReply(chosen_files)); 121 122 reply_context_ = ppapi::host::ReplyMessageContext(); 123 handler_ = NULL; // Handler deletes itself. 124 } 125 126 int32_t PepperFileChooserHost::OnShow( 127 ppapi::host::HostMessageContext* context, 128 bool save_as, 129 bool open_multiple, 130 const std::string& suggested_file_name, 131 const std::vector<std::string>& accept_mime_types) { 132 if (handler_) 133 return PP_ERROR_INPROGRESS; // Already pending. 134 135 if (!host()->permissions().HasPermission( 136 ppapi::PERMISSION_BYPASS_USER_GESTURE) && 137 !renderer_ppapi_host_->HasUserGesture(pp_instance())) { 138 return PP_ERROR_NO_USER_GESTURE; 139 } 140 141 WebKit::WebFileChooserParams params; 142 if (save_as) { 143 params.saveAs = true; 144 params.initialValue = WebKit::WebString::fromUTF8( 145 suggested_file_name.data(), suggested_file_name.size()); 146 } else { 147 params.multiSelect = open_multiple; 148 } 149 std::vector<WebKit::WebString> mine_types(accept_mime_types.size()); 150 for (size_t i = 0; i < accept_mime_types.size(); i++) { 151 mine_types[i] = WebKit::WebString::fromUTF8( 152 accept_mime_types[i].data(), accept_mime_types[i].size()); 153 } 154 params.acceptTypes = mine_types; 155 params.directory = false; 156 157 handler_ = new CompletionHandler(AsWeakPtr()); 158 RenderViewImpl* render_view = static_cast<RenderViewImpl*>( 159 renderer_ppapi_host_->GetRenderViewForInstance(pp_instance())); 160 if (!render_view || !render_view->runFileChooser(params, handler_)) { 161 delete handler_; 162 handler_ = NULL; 163 return PP_ERROR_NOACCESS; 164 } 165 166 reply_context_ = context->MakeReplyMessageContext(); 167 return PP_OK_COMPLETIONPENDING; 168 } 169 170 } // namespace content 171 172