file_chooser_resource.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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
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<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
131int32_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