// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/proxy/file_chooser_resource.h" #include "base/bind.h" #include "base/strings/string_split.h" #include "ipc/ipc_message.h" #include "ppapi/c/pp_errors.h" #include "ppapi/proxy/dispatch_reply_message.h" #include "ppapi/proxy/file_ref_resource.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/shared_impl/var.h" namespace ppapi { namespace proxy { FileChooserResource::FileChooserResource(Connection connection, PP_Instance instance, PP_FileChooserMode_Dev mode, const std::string& accept_types) : PluginResource(connection, instance), mode_(mode) { PopulateAcceptTypes(accept_types, &accept_types_); } FileChooserResource::~FileChooserResource() { } thunk::PPB_FileChooser_API* FileChooserResource::AsPPB_FileChooser_API() { return this; } int32_t FileChooserResource::Show(const PP_ArrayOutput& output, scoped_refptr callback) { return ShowWithoutUserGesture(PP_FALSE, PP_MakeUndefined(), output, callback); } int32_t FileChooserResource::ShowWithoutUserGesture( PP_Bool save_as, PP_Var suggested_file_name, const PP_ArrayOutput& output, scoped_refptr callback) { int32_t result = ShowInternal(save_as, suggested_file_name, callback); if (result == PP_OK_COMPLETIONPENDING) output_.set_pp_array_output(output); return result; } int32_t FileChooserResource::Show0_5(scoped_refptr callback) { return ShowInternal(PP_FALSE, PP_MakeUndefined(), callback); } PP_Resource FileChooserResource::GetNextChosenFile() { if (file_queue_.empty()) return 0; // Return the next resource in the queue. It will already have been addrefed // (they're currently owned by the FileChooser) and returning it transfers // ownership of that reference to the plugin. PP_Resource next = file_queue_.front(); file_queue_.pop(); return next; } int32_t FileChooserResource::ShowWithoutUserGesture0_5( PP_Bool save_as, PP_Var suggested_file_name, scoped_refptr callback) { return ShowInternal(save_as, suggested_file_name, callback); } // static void FileChooserResource::PopulateAcceptTypes( const std::string& input, std::vector* output) { if (input.empty()) return; std::vector type_list; base::SplitString(input, ',', &type_list); output->reserve(type_list.size()); for (size_t i = 0; i < type_list.size(); ++i) { std::string type = type_list[i]; base::TrimWhitespaceASCII(type, base::TRIM_ALL, &type); // If the type is a single character, it definitely cannot be valid. In the // case of a file extension it would be a single ".". In the case of a MIME // type it would just be a "/". if (type.length() < 2) continue; if (type.find_first_of('/') == std::string::npos && type[0] != '.') continue; StringToLowerASCII(&type); output->push_back(type); } } void FileChooserResource::OnPluginMsgShowReply( const ResourceMessageReplyParams& params, const std::vector& chosen_files) { if (output_.is_valid()) { // Using v0.6 of the API with the output array. std::vector files; for (size_t i = 0; i < chosen_files.size(); i++) { files.push_back(FileRefResource::CreateFileRef( connection(), pp_instance(), chosen_files[i])); } output_.StoreResourceVector(files); } else { // Convert each of the passed in file infos to resources. These will be // owned by the FileChooser object until they're passed to the plugin. DCHECK(file_queue_.empty()); for (size_t i = 0; i < chosen_files.size(); i++) { file_queue_.push(FileRefResource::CreateFileRef( connection(), pp_instance(), chosen_files[i])); } } // Notify the plugin of the new data. callback_->Run(params.result()); // DANGER: May delete |this|! } int32_t FileChooserResource::ShowInternal( PP_Bool save_as, const PP_Var& suggested_file_name, scoped_refptr callback) { if (TrackedCallback::IsPending(callback_)) return PP_ERROR_INPROGRESS; if (!sent_create_to_renderer()) SendCreate(RENDERER, PpapiHostMsg_FileChooser_Create()); callback_ = callback; StringVar* sugg_str = StringVar::FromPPVar(suggested_file_name); PpapiHostMsg_FileChooser_Show msg( PP_ToBool(save_as), mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE, sugg_str ? sugg_str->value() : std::string(), accept_types_); Call(RENDERER, msg, base::Bind(&FileChooserResource::OnPluginMsgShowReply, this)); return PP_OK_COMPLETIONPENDING; } } // namespace proxy } // namespace ppapi