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/ppapi_messages.h" 13#include "ppapi/proxy/ppb_file_ref_proxy.h" 14#include "ppapi/shared_impl/var.h" 15 16namespace ppapi { 17namespace proxy { 18 19FileChooserResource::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 28FileChooserResource::~FileChooserResource() { 29} 30 31thunk::PPB_FileChooser_API* FileChooserResource::AsPPB_FileChooser_API() { 32 return this; 33} 34 35int32_t FileChooserResource::Show(const PP_ArrayOutput& output, 36 scoped_refptr<TrackedCallback> callback) { 37 return ShowWithoutUserGesture(PP_FALSE, PP_MakeUndefined(), output, callback); 38} 39 40int32_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 51int32_t FileChooserResource::Show0_5(scoped_refptr<TrackedCallback> callback) { 52 return ShowInternal(PP_FALSE, PP_MakeUndefined(), callback); 53} 54 55PP_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 67int32_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 75void 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 101void FileChooserResource::OnPluginMsgShowReply( 102 const ResourceMessageReplyParams& params, 103 const std::vector<PPB_FileRef_CreateInfo>& 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(PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); 109 output_.StoreResourceVector(files); 110 } else { 111 // Convert each of the passed in file infos to resources. These will be 112 // owned by the FileChooser object until they're passed to the plugin. 113 DCHECK(file_queue_.empty()); 114 for (size_t i = 0; i < chosen_files.size(); i++) { 115 file_queue_.push(PPB_FileRef_Proxy::DeserializeFileRef( 116 chosen_files[i])); 117 } 118 } 119 120 // Notify the plugin of the new data. 121 callback_->Run(params.result()); 122 // DANGER: May delete |this|! 123} 124 125int32_t FileChooserResource::ShowInternal( 126 PP_Bool save_as, 127 const PP_Var& suggested_file_name, 128 scoped_refptr<TrackedCallback> callback) { 129 if (TrackedCallback::IsPending(callback_)) 130 return PP_ERROR_INPROGRESS; 131 132 if (!sent_create_to_renderer()) 133 SendCreate(RENDERER, PpapiHostMsg_FileChooser_Create()); 134 135 callback_ = callback; 136 StringVar* sugg_str = StringVar::FromPPVar(suggested_file_name); 137 138 PpapiHostMsg_FileChooser_Show msg( 139 PP_ToBool(save_as), 140 mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE, 141 sugg_str ? sugg_str->value() : std::string(), 142 accept_types_); 143 Call<PpapiPluginMsg_FileChooser_ShowReply>(RENDERER, msg, 144 base::Bind(&FileChooserResource::OnPluginMsgShowReply, this)); 145 return PP_OK_COMPLETIONPENDING; 146} 147 148} // namespace proxy 149} // namespace ppapi 150