summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/file_chooser_resource.cc
blob: 06425686cf7a469a028a1a2c182e4220e4ace093 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// 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<TrackedCallback> 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<TrackedCallback> 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<TrackedCallback> 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<TrackedCallback> callback) {
  return ShowInternal(save_as, suggested_file_name, callback);
}

// static
void FileChooserResource::PopulateAcceptTypes(
    const std::string& input,
    std::vector<std::string>* output) {
  if (input.empty())
    return;

  std::vector<std::string> 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<FileRefCreateInfo>& chosen_files) {
  if (output_.is_valid()) {
    // Using v0.6 of the API with the output array.
    std::vector<PP_Resource> 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<TrackedCallback> 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<PpapiPluginMsg_FileChooser_ShowReply>(RENDERER, msg,
      base::Bind(&FileChooserResource::OnPluginMsgShowReply, this));
  return PP_OK_COMPLETIONPENDING;
}

}  // namespace proxy
}  // namespace ppapi