| OLD | NEW |
| (Empty) |
| 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 "webkit/plugins/ppapi/ppb_file_chooser_impl.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/logging.h" | |
| 11 #include "base/string_split.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "base/sys_string_conversions.h" | |
| 14 #include "ppapi/c/pp_completion_callback.h" | |
| 15 #include "ppapi/c/pp_errors.h" | |
| 16 #include "ppapi/shared_impl/tracked_callback.h" | |
| 17 #include "ppapi/shared_impl/var.h" | |
| 18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h
" | |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserComplet
ion.h" | |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserParams.
h" | |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | |
| 22 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" | |
| 23 #include "webkit/glue/webkit_glue.h" | |
| 24 #include "webkit/plugins/ppapi/common.h" | |
| 25 #include "webkit/plugins/ppapi/ppb_file_ref_impl.h" | |
| 26 #include "webkit/plugins/ppapi/plugin_delegate.h" | |
| 27 #include "webkit/plugins/ppapi/plugin_module.h" | |
| 28 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | |
| 29 #include "webkit/plugins/ppapi/resource_helper.h" | |
| 30 | |
| 31 using ppapi::StringVar; | |
| 32 using ppapi::thunk::PPB_FileChooser_API; | |
| 33 using ppapi::TrackedCallback; | |
| 34 using WebKit::WebCString; | |
| 35 using WebKit::WebFileChooserCompletion; | |
| 36 using WebKit::WebFileChooserParams; | |
| 37 using WebKit::WebString; | |
| 38 using WebKit::WebVector; | |
| 39 | |
| 40 namespace webkit { | |
| 41 namespace ppapi { | |
| 42 | |
| 43 namespace { | |
| 44 | |
| 45 class FileChooserCompletionImpl : public WebFileChooserCompletion { | |
| 46 public: | |
| 47 FileChooserCompletionImpl(PPB_FileChooser_Impl* file_chooser) | |
| 48 : file_chooser_(file_chooser) { | |
| 49 DCHECK(file_chooser_); | |
| 50 } | |
| 51 | |
| 52 virtual ~FileChooserCompletionImpl() {} | |
| 53 | |
| 54 virtual void didChooseFile(const WebVector<WebString>& file_names) { | |
| 55 std::vector<PPB_FileChooser_Impl::ChosenFileInfo> files; | |
| 56 for (size_t i = 0; i < file_names.size(); i++) { | |
| 57 files.push_back( | |
| 58 PPB_FileChooser_Impl::ChosenFileInfo(file_names[i].utf8(), | |
| 59 std::string())); | |
| 60 } | |
| 61 | |
| 62 file_chooser_->StoreChosenFiles(files); | |
| 63 | |
| 64 // It is the responsibility of this method to delete the instance. | |
| 65 delete this; | |
| 66 } | |
| 67 virtual void didChooseFile(const WebVector<SelectedFileInfo>& file_names) { | |
| 68 std::vector<PPB_FileChooser_Impl::ChosenFileInfo> files; | |
| 69 for (size_t i = 0; i < file_names.size(); i++) { | |
| 70 files.push_back( | |
| 71 PPB_FileChooser_Impl::ChosenFileInfo( | |
| 72 file_names[i].path.utf8(), | |
| 73 file_names[i].displayName.utf8())); | |
| 74 } | |
| 75 | |
| 76 file_chooser_->StoreChosenFiles(files); | |
| 77 | |
| 78 // It is the responsibility of this method to delete the instance. | |
| 79 delete this; | |
| 80 } | |
| 81 | |
| 82 private: | |
| 83 scoped_refptr<PPB_FileChooser_Impl> file_chooser_; | |
| 84 }; | |
| 85 | |
| 86 } // namespace | |
| 87 | |
| 88 PPB_FileChooser_Impl::ChosenFileInfo::ChosenFileInfo( | |
| 89 const std::string& path, | |
| 90 const std::string& display_name) | |
| 91 : path(path), | |
| 92 display_name(display_name) { | |
| 93 } | |
| 94 | |
| 95 PPB_FileChooser_Impl::PPB_FileChooser_Impl( | |
| 96 PP_Instance instance, | |
| 97 PP_FileChooserMode_Dev mode, | |
| 98 const char* accept_types) | |
| 99 : Resource(::ppapi::OBJECT_IS_IMPL, instance), | |
| 100 mode_(mode), | |
| 101 next_chosen_file_index_(0) { | |
| 102 if (accept_types) | |
| 103 accept_types_ = std::string(accept_types); | |
| 104 } | |
| 105 | |
| 106 PPB_FileChooser_Impl::~PPB_FileChooser_Impl() { | |
| 107 } | |
| 108 | |
| 109 // static | |
| 110 PP_Resource PPB_FileChooser_Impl::Create( | |
| 111 PP_Instance instance, | |
| 112 PP_FileChooserMode_Dev mode, | |
| 113 const char* accept_types) { | |
| 114 if (mode != PP_FILECHOOSERMODE_OPEN && | |
| 115 mode != PP_FILECHOOSERMODE_OPENMULTIPLE) | |
| 116 return 0; | |
| 117 return (new PPB_FileChooser_Impl(instance, mode, | |
| 118 accept_types))->GetReference(); | |
| 119 } | |
| 120 | |
| 121 PPB_FileChooser_Impl* PPB_FileChooser_Impl::AsPPB_FileChooser_Impl() { | |
| 122 return this; | |
| 123 } | |
| 124 | |
| 125 PPB_FileChooser_API* PPB_FileChooser_Impl::AsPPB_FileChooser_API() { | |
| 126 return this; | |
| 127 } | |
| 128 | |
| 129 void PPB_FileChooser_Impl::StoreChosenFiles( | |
| 130 const std::vector<ChosenFileInfo>& files) { | |
| 131 next_chosen_file_index_ = 0; | |
| 132 | |
| 133 // It is possible that |callback_| has been run: before the user takes action | |
| 134 // on the file chooser, the page navigates away and causes the plugin module | |
| 135 // (whose instance requested to show the file chooser) to be destroyed. In | |
| 136 // that case, |callback_| has been aborted when we get here. | |
| 137 if (!TrackedCallback::IsPending(callback_)) { | |
| 138 // To be cautious, reset our internal state. | |
| 139 output_.Reset(); | |
| 140 chosen_files_.clear(); | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 std::vector< scoped_refptr<Resource> > chosen_files; | |
| 145 for (std::vector<ChosenFileInfo>::const_iterator it = files.begin(); | |
| 146 it != files.end(); ++it) { | |
| 147 #if defined(OS_WIN) | |
| 148 FilePath file_path(base::SysUTF8ToWide(it->path)); | |
| 149 #else | |
| 150 FilePath file_path(it->path); | |
| 151 #endif | |
| 152 | |
| 153 chosen_files.push_back(scoped_refptr<Resource>( | |
| 154 PPB_FileRef_Impl::CreateExternal(pp_instance(), | |
| 155 file_path, | |
| 156 it->display_name))); | |
| 157 } | |
| 158 | |
| 159 int32_t result_code = (chosen_files.size() > 0) ? PP_OK : PP_ERROR_USERCANCEL; | |
| 160 if (output_.is_valid()) | |
| 161 output_.StoreResourceVector(chosen_files); | |
| 162 else // v0.5 API. | |
| 163 chosen_files_.swap(chosen_files); | |
| 164 RunCallback(result_code); | |
| 165 } | |
| 166 | |
| 167 int32_t PPB_FileChooser_Impl::ValidateCallback( | |
| 168 scoped_refptr<TrackedCallback> callback) { | |
| 169 if (TrackedCallback::IsPending(callback_)) | |
| 170 return PP_ERROR_INPROGRESS; | |
| 171 | |
| 172 return PP_OK; | |
| 173 } | |
| 174 | |
| 175 void PPB_FileChooser_Impl::RegisterCallback( | |
| 176 scoped_refptr<TrackedCallback> callback) { | |
| 177 DCHECK(!TrackedCallback::IsPending(callback_)); | |
| 178 | |
| 179 PluginModule* plugin_module = ResourceHelper::GetPluginModule(this); | |
| 180 if (!plugin_module) | |
| 181 return; | |
| 182 | |
| 183 callback_ = callback; | |
| 184 } | |
| 185 | |
| 186 void PPB_FileChooser_Impl::RunCallback(int32_t result) { | |
| 187 TrackedCallback::ClearAndRun(&callback_, result); | |
| 188 } | |
| 189 | |
| 190 int32_t PPB_FileChooser_Impl::Show(const PP_ArrayOutput& output, | |
| 191 scoped_refptr<TrackedCallback> callback) { | |
| 192 int32_t result = Show0_5(callback); | |
| 193 if (result == PP_OK_COMPLETIONPENDING) | |
| 194 output_.set_pp_array_output(output); | |
| 195 return result; | |
| 196 } | |
| 197 | |
| 198 int32_t PPB_FileChooser_Impl::ShowWithoutUserGesture( | |
| 199 PP_Bool save_as, | |
| 200 PP_Var suggested_file_name, | |
| 201 const PP_ArrayOutput& output, | |
| 202 scoped_refptr<TrackedCallback> callback) { | |
| 203 int32_t result = ShowWithoutUserGesture0_5(save_as, suggested_file_name, | |
| 204 callback); | |
| 205 if (result == PP_OK_COMPLETIONPENDING) | |
| 206 output_.set_pp_array_output(output); | |
| 207 return result; | |
| 208 } | |
| 209 | |
| 210 int32_t PPB_FileChooser_Impl::Show0_5(scoped_refptr<TrackedCallback> callback) { | |
| 211 PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(this); | |
| 212 if (!plugin_instance) | |
| 213 return PP_ERROR_FAILED; | |
| 214 if (!plugin_instance->IsProcessingUserGesture()) | |
| 215 return PP_ERROR_NO_USER_GESTURE; | |
| 216 return ShowWithoutUserGesture0_5(PP_FALSE, PP_MakeUndefined(), callback); | |
| 217 } | |
| 218 | |
| 219 int32_t PPB_FileChooser_Impl::ShowWithoutUserGesture0_5( | |
| 220 PP_Bool save_as, | |
| 221 PP_Var suggested_file_name, | |
| 222 scoped_refptr<TrackedCallback> callback) { | |
| 223 int32_t rv = ValidateCallback(callback); | |
| 224 if (rv != PP_OK) | |
| 225 return rv; | |
| 226 | |
| 227 DCHECK((mode_ == PP_FILECHOOSERMODE_OPEN) || | |
| 228 (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE)); | |
| 229 | |
| 230 WebFileChooserParams params; | |
| 231 if (save_as) { | |
| 232 params.saveAs = true; | |
| 233 StringVar* str = StringVar::FromPPVar(suggested_file_name); | |
| 234 if (str) | |
| 235 params.initialValue = WebString::fromUTF8(str->value().c_str()); | |
| 236 } else { | |
| 237 params.multiSelect = (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE); | |
| 238 } | |
| 239 params.acceptTypes = ParseAcceptValue(accept_types_); | |
| 240 params.directory = false; | |
| 241 | |
| 242 PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this); | |
| 243 if (!plugin_delegate) | |
| 244 return PP_ERROR_FAILED; | |
| 245 | |
| 246 if (!plugin_delegate->RunFileChooser(params, | |
| 247 new FileChooserCompletionImpl(this))) | |
| 248 return PP_ERROR_FAILED; | |
| 249 | |
| 250 RegisterCallback(callback); | |
| 251 return PP_OK_COMPLETIONPENDING; | |
| 252 } | |
| 253 | |
| 254 PP_Resource PPB_FileChooser_Impl::GetNextChosenFile() { | |
| 255 if (next_chosen_file_index_ >= chosen_files_.size()) | |
| 256 return 0; | |
| 257 | |
| 258 return chosen_files_[next_chosen_file_index_++]->GetReference(); | |
| 259 } | |
| 260 | |
| 261 std::vector<WebString> PPB_FileChooser_Impl::ParseAcceptValue( | |
| 262 const std::string& accept_types) { | |
| 263 if (accept_types.empty()) | |
| 264 return std::vector<WebString>(); | |
| 265 std::vector<std::string> type_list; | |
| 266 base::SplitString(accept_types, ',', &type_list); | |
| 267 std::vector<WebString> normalized_type_list; | |
| 268 normalized_type_list.reserve(type_list.size()); | |
| 269 for (size_t i = 0; i < type_list.size(); ++i) { | |
| 270 std::string type = type_list[i]; | |
| 271 TrimWhitespaceASCII(type, TRIM_ALL, &type); | |
| 272 | |
| 273 // If the type is a single character, it definitely cannot be valid. In the | |
| 274 // case of a file extension it would be a single ".". In the case of a MIME | |
| 275 // type it would just be a "/". | |
| 276 if (type.length() < 2) | |
| 277 continue; | |
| 278 if (type.find_first_of('/') == std::string::npos && type[0] != '.') | |
| 279 continue; | |
| 280 StringToLowerASCII(&type); | |
| 281 normalized_type_list.push_back(WebString::fromUTF8(type.data(), | |
| 282 type.size())); | |
| 283 } | |
| 284 return normalized_type_list; | |
| 285 } | |
| 286 | |
| 287 } // namespace ppapi | |
| 288 } // namespace webkit | |
| OLD | NEW |