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.
5 #include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h"
7 #include "base/pickle.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "ipc/ipc_message.h"
11 #include "ipc/ipc_message_macros.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/c/private/ppb_flash_clipboard.h"
14 #include "ppapi/host/dispatch_host_message.h"
15 #include "ppapi/host/host_message_context.h"
16 #include "ppapi/host/ppapi_host.h"
17 #include "ppapi/proxy/ppapi_messages.h"
18 #include "ppapi/proxy/resource_message_params.h"
19 #include "ui/base/clipboard/scoped_clipboard_writer.h"
21 using content::BrowserThread;
27 const size_t kMaxClipboardWriteSize = 1000000;
29 ui::ClipboardType ConvertClipboardType(uint32_t type) {
31 case PP_FLASH_CLIPBOARD_TYPE_STANDARD:
32 return ui::CLIPBOARD_TYPE_COPY_PASTE;
33 case PP_FLASH_CLIPBOARD_TYPE_SELECTION:
34 return ui::CLIPBOARD_TYPE_SELECTION;
37 return ui::CLIPBOARD_TYPE_COPY_PASTE;
40 // Functions to pack/unpack custom data from a pickle. See the header file for
41 // more detail on custom formats in Pepper.
42 // TODO(raymes): Currently pepper custom formats are stored in their own
43 // native format type. However we should be able to store them in the same way
44 // as "Web Custom" formats are. This would allow clipboard data to be shared
45 // between pepper applications and web applications. However currently web apps
46 // assume all data that is placed on the clipboard is UTF16 and pepper allows
47 // arbitrary data so this change would require some reworking of the chrome
48 // clipboard interface for custom data.
49 bool JumpToFormatInPickle(const base::string16& format, PickleIterator* iter) {
51 if (!iter->ReadUInt64(&size))
53 for (uint64 i = 0; i < size; ++i) {
54 base::string16 stored_format;
55 if (!iter->ReadString16(&stored_format))
57 if (stored_format == format)
60 if (!iter->ReadLength(&skip_length))
62 if (!iter->SkipBytes(skip_length))
68 bool IsFormatAvailableInPickle(const base::string16& format,
69 const Pickle& pickle) {
70 PickleIterator iter(pickle);
71 return JumpToFormatInPickle(format, &iter);
74 std::string ReadDataFromPickle(const base::string16& format,
75 const Pickle& pickle) {
77 PickleIterator iter(pickle);
78 if (!JumpToFormatInPickle(format, &iter) || !iter.ReadString(&result))
83 bool WriteDataToPickle(const std::map<base::string16, std::string>& data,
85 pickle->WriteUInt64(data.size());
86 for (std::map<base::string16, std::string>::const_iterator it = data.begin();
89 if (!pickle->WriteString16(it->first))
91 if (!pickle->WriteString(it->second))
99 PepperFlashClipboardMessageFilter::PepperFlashClipboardMessageFilter() {}
101 PepperFlashClipboardMessageFilter::~PepperFlashClipboardMessageFilter() {}
103 scoped_refptr<base::TaskRunner>
104 PepperFlashClipboardMessageFilter::OverrideTaskRunnerForMessage(
105 const IPC::Message& msg) {
106 // Clipboard writes should always occur on the UI thread due to the
107 // restrictions of various platform APIs. In general, the clipboard is not
108 // thread-safe, so all clipboard calls should be serviced from the UI thread.
109 if (msg.type() == PpapiHostMsg_FlashClipboard_WriteData::ID)
110 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
112 // Windows needs clipboard reads to be serviced from the IO thread because
113 // these are sync IPCs which can result in deadlocks with plugins if serviced
114 // from the UI thread. Note that Windows clipboard calls ARE thread-safe so it
115 // is ok for reads and writes to be serviced from different threads.
117 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
119 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
123 int32_t PepperFlashClipboardMessageFilter::OnResourceMessageReceived(
124 const IPC::Message& msg,
125 ppapi::host::HostMessageContext* context) {
126 PPAPI_BEGIN_MESSAGE_MAP(PepperFlashClipboardMessageFilter, msg)
127 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
128 PpapiHostMsg_FlashClipboard_RegisterCustomFormat,
129 OnMsgRegisterCustomFormat)
130 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
131 PpapiHostMsg_FlashClipboard_IsFormatAvailable, OnMsgIsFormatAvailable)
132 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_ReadData,
134 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_WriteData,
136 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
137 PpapiHostMsg_FlashClipboard_GetSequenceNumber, OnMsgGetSequenceNumber)
138 PPAPI_END_MESSAGE_MAP()
139 return PP_ERROR_FAILED;
142 int32_t PepperFlashClipboardMessageFilter::OnMsgRegisterCustomFormat(
143 ppapi::host::HostMessageContext* host_context,
144 const std::string& format_name) {
145 uint32_t format = custom_formats_.RegisterFormat(format_name);
146 if (format == PP_FLASH_CLIPBOARD_FORMAT_INVALID)
147 return PP_ERROR_FAILED;
148 host_context->reply_msg =
149 PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply(format);
153 int32_t PepperFlashClipboardMessageFilter::OnMsgIsFormatAvailable(
154 ppapi::host::HostMessageContext* host_context,
155 uint32_t clipboard_type,
157 if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
159 return PP_ERROR_FAILED;
162 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
163 ui::ClipboardType type = ConvertClipboardType(clipboard_type);
164 bool available = false;
166 case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: {
167 bool plain = clipboard->IsFormatAvailable(
168 ui::Clipboard::GetPlainTextFormatType(), type);
169 bool plainw = clipboard->IsFormatAvailable(
170 ui::Clipboard::GetPlainTextWFormatType(), type);
171 available = plain || plainw;
174 case PP_FLASH_CLIPBOARD_FORMAT_HTML:
175 available = clipboard->IsFormatAvailable(
176 ui::Clipboard::GetHtmlFormatType(), type);
178 case PP_FLASH_CLIPBOARD_FORMAT_RTF:
180 clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), type);
182 case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
185 if (custom_formats_.IsFormatRegistered(format)) {
186 std::string format_name = custom_formats_.GetFormatName(format);
187 std::string clipboard_data;
188 clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(),
190 Pickle pickle(clipboard_data.data(), clipboard_data.size());
192 IsFormatAvailableInPickle(base::UTF8ToUTF16(format_name), pickle);
197 return available ? PP_OK : PP_ERROR_FAILED;
200 int32_t PepperFlashClipboardMessageFilter::OnMsgReadData(
201 ppapi::host::HostMessageContext* host_context,
202 uint32_t clipboard_type,
204 if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
206 return PP_ERROR_FAILED;
209 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
210 ui::ClipboardType type = ConvertClipboardType(clipboard_type);
211 std::string clipboard_string;
212 int32_t result = PP_ERROR_FAILED;
214 case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: {
215 if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
218 clipboard->ReadText(type, &text);
221 clipboard_string = base::UTF16ToUTF8(text);
225 // If the PlainTextW format isn't available or is empty, take the
226 // ASCII text format.
227 if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
230 clipboard->ReadAsciiText(type, &clipboard_string);
234 case PP_FLASH_CLIPBOARD_FORMAT_HTML: {
235 if (!clipboard->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(),
242 uint32 fragment_start;
244 clipboard->ReadHTML(type, &html, &url, &fragment_start, &fragment_end);
246 clipboard_string = base::UTF16ToUTF8(
247 html.substr(fragment_start, fragment_end - fragment_start));
250 case PP_FLASH_CLIPBOARD_FORMAT_RTF: {
251 if (!clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(),
256 clipboard->ReadRTF(type, &clipboard_string);
259 case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
262 if (custom_formats_.IsFormatRegistered(format)) {
263 base::string16 format_name =
264 base::UTF8ToUTF16(custom_formats_.GetFormatName(format));
265 std::string clipboard_data;
266 clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(),
268 Pickle pickle(clipboard_data.data(), clipboard_data.size());
269 if (IsFormatAvailableInPickle(format_name, pickle)) {
271 clipboard_string = ReadDataFromPickle(format_name, pickle);
278 if (result == PP_OK) {
279 host_context->reply_msg =
280 PpapiPluginMsg_FlashClipboard_ReadDataReply(clipboard_string);
285 int32_t PepperFlashClipboardMessageFilter::OnMsgWriteData(
286 ppapi::host::HostMessageContext* host_context,
287 uint32_t clipboard_type,
288 const std::vector<uint32_t>& formats,
289 const std::vector<std::string>& data) {
290 if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
292 return PP_ERROR_FAILED;
294 if (formats.size() != data.size())
295 return PP_ERROR_FAILED;
297 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
298 ui::ClipboardType type = ConvertClipboardType(clipboard_type);
299 // If no formats are passed in clear the clipboard.
300 if (formats.size() == 0) {
301 clipboard->Clear(type);
305 ui::ScopedClipboardWriter scw(type);
306 std::map<base::string16, std::string> custom_data_map;
308 for (uint32_t i = 0; i < formats.size(); ++i) {
309 if (data[i].length() > kMaxClipboardWriteSize) {
310 res = PP_ERROR_NOSPACE;
314 switch (formats[i]) {
315 case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT:
316 scw.WriteText(base::UTF8ToUTF16(data[i]));
318 case PP_FLASH_CLIPBOARD_FORMAT_HTML:
319 scw.WriteHTML(base::UTF8ToUTF16(data[i]), std::string());
321 case PP_FLASH_CLIPBOARD_FORMAT_RTF:
322 scw.WriteRTF(data[i]);
324 case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
325 res = PP_ERROR_BADARGUMENT;
328 if (custom_formats_.IsFormatRegistered(formats[i])) {
329 std::string format_name = custom_formats_.GetFormatName(formats[i]);
330 custom_data_map[base::UTF8ToUTF16(format_name)] = data[i];
333 res = PP_ERROR_BADARGUMENT;
342 if (custom_data_map.size() > 0) {
344 if (WriteDataToPickle(custom_data_map, &pickle)) {
345 scw.WritePickledData(pickle,
346 ui::Clipboard::GetPepperCustomDataFormatType());
348 res = PP_ERROR_BADARGUMENT;
353 // Need to clear the objects so nothing is written.
360 int32_t PepperFlashClipboardMessageFilter::OnMsgGetSequenceNumber(
361 ppapi::host::HostMessageContext* host_context,
362 uint32_t clipboard_type) {
363 if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
365 return PP_ERROR_FAILED;
368 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
369 ui::ClipboardType type = ConvertClipboardType(clipboard_type);
370 int64_t sequence_number = clipboard->GetSequenceNumber(type);
371 host_context->reply_msg =
372 PpapiPluginMsg_FlashClipboard_GetSequenceNumberReply(sequence_number);
376 } // namespace chrome