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 "ppapi/proxy/file_chooser_resource.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_split.h" 9 #include "ipc/ipc_message.h" 10 #include "ppapi/c/pp_errors.h" 11 #include "ppapi/proxy/dispatch_reply_message.h" 12 #include "ppapi/proxy/file_ref_resource.h" 13 #include "ppapi/proxy/ppapi_messages.h" 14 #include "ppapi/shared_impl/var.h" 15 16 namespace ppapi { 17 namespace proxy { 18 19 FileChooserResource::FileChooserResource(Connection connection, 20 PP_Instance instance, 21 PP_FileChooserMode_Dev mode, 22 const std::string& accept_types) 23 : PluginResource(connection, instance), 24 mode_(mode) { 25 PopulateAcceptTypes(accept_types, &accept_types_); 26 } 27 28 FileChooserResource::~FileChooserResource() { 29 } 30 31 thunk::PPB_FileChooser_API* FileChooserResource::AsPPB_FileChooser_API() { 32 return this; 33 } 34 35 int32_t FileChooserResource::Show(const PP_ArrayOutput& output, 36 scoped_refptr<TrackedCallback> callback) { 37 return ShowWithoutUserGesture(PP_FALSE, PP_MakeUndefined(), output, callback); 38 } 39 40 int32_t FileChooserResource::ShowWithoutUserGesture( 41 PP_Bool save_as, 42 PP_Var suggested_file_name, 43 const PP_ArrayOutput& output, 44 scoped_refptr<TrackedCallback> callback) { 45 int32_t result = ShowInternal(save_as, suggested_file_name, callback); 46 if (result == PP_OK_COMPLETIONPENDING) 47 output_.set_pp_array_output(output); 48 return result; 49 } 50 51 int32_t FileChooserResource::Show0_5(scoped_refptr<TrackedCallback> callback) { 52 return ShowInternal(PP_FALSE, PP_MakeUndefined(), callback); 53 } 54 55 PP_Resource FileChooserResource::GetNextChosenFile() { 56 if (file_queue_.empty()) 57 return 0; 58 59 // Return the next resource in the queue. It will already have been addrefed 60 // (they're currently owned by the FileChooser) and returning it transfers 61 // ownership of that reference to the plugin. 62 PP_Resource next = file_queue_.front(); 63 file_queue_.pop(); 64 return next; 65 } 66 67 int32_t FileChooserResource::ShowWithoutUserGesture0_5( 68 PP_Bool save_as, 69 PP_Var suggested_file_name, 70 scoped_refptr<TrackedCallback> callback) { 71 return ShowInternal(save_as, suggested_file_name, callback); 72 } 73 74 // static 75 void FileChooserResource::PopulateAcceptTypes( 76 const std::string& input, 77 std::vector<std::string>* output) { 78 if (input.empty()) 79 return; 80 81 std::vector<std::string> type_list; 82 base::SplitString(input, ',', &type_list); 83 output->reserve(type_list.size()); 84 85 for (size_t i = 0; i < type_list.size(); ++i) { 86 std::string type = type_list[i]; 87 TrimWhitespaceASCII(type, TRIM_ALL, &type); 88 89 // If the type is a single character, it definitely cannot be valid. In the 90 // case of a file extension it would be a single ".". In the case of a MIME 91 // type it would just be a "/". 92 if (type.length() < 2) 93 continue; 94 if (type.find_first_of('/') == std::string::npos && type[0] != '.') 95 continue; 96 StringToLowerASCII(&type); 97 output->push_back(type); 98 } 99 } 100 101 void FileChooserResource::OnPluginMsgShowReply( 102 const ResourceMessageReplyParams& params, 103 const std::vector<FileRefCreateInfo>& chosen_files) { 104 if (output_.is_valid()) { 105 // Using v0.6 of the API with the output array. 106 std::vector<PP_Resource> files; 107 for (size_t i = 0; i < chosen_files.size(); i++) { 108 files.push_back(FileRefResource::CreateFileRef( 109 connection(), 110 pp_instance(), 111 chosen_files[i])); 112 } 113 output_.StoreResourceVector(files); 114 } else { 115 // Convert each of the passed in file infos to resources. These will be 116 // owned by the FileChooser object until they're passed to the plugin. 117 DCHECK(file_queue_.empty()); 118 for (size_t i = 0; i < chosen_files.size(); i++) { 119 file_queue_.push(FileRefResource::CreateFileRef( 120 connection(), 121 pp_instance(), 122 chosen_files[i])); 123 } 124 } 125 126 // Notify the plugin of the new data. 127 callback_->Run(params.result()); 128 // DANGER: May delete |this|! 129 } 130 131 int32_t FileChooserResource::ShowInternal( 132 PP_Bool save_as, 133 const PP_Var& suggested_file_name, 134 scoped_refptr<TrackedCallback> callback) { 135 if (TrackedCallback::IsPending(callback_)) 136 return PP_ERROR_INPROGRESS; 137 138 if (!sent_create_to_renderer()) 139 SendCreate(RENDERER, PpapiHostMsg_FileChooser_Create()); 140 141 callback_ = callback; 142 StringVar* sugg_str = StringVar::FromPPVar(suggested_file_name); 143 144 PpapiHostMsg_FileChooser_Show msg( 145 PP_ToBool(save_as), 146 mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE, 147 sugg_str ? sugg_str->value() : std::string(), 148 accept_types_); 149 Call<PpapiPluginMsg_FileChooser_ShowReply>(RENDERER, msg, 150 base::Bind(&FileChooserResource::OnPluginMsgShowReply, this)); 151 return PP_OK_COMPLETIONPENDING; 152 } 153 154 } // namespace proxy 155 } // namespace ppapi 156