Home | History | Annotate | Download | only in proxy
      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     base::TrimWhitespaceASCII(type, base::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     base::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