Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_host / pepper / pepper_flash_clipboard_message_filter.cc
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 "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h"
6
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"
20
21 using content::BrowserThread;
22
23 namespace chrome {
24
25 namespace {
26
27 const size_t kMaxClipboardWriteSize = 1000000;
28
29 ui::ClipboardType ConvertClipboardType(uint32_t type) {
30   switch (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;
35   }
36   NOTREACHED();
37   return ui::CLIPBOARD_TYPE_COPY_PASTE;
38 }
39
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) {
50   uint64 size = 0;
51   if (!iter->ReadUInt64(&size))
52     return false;
53   for (uint64 i = 0; i < size; ++i) {
54     base::string16 stored_format;
55     if (!iter->ReadString16(&stored_format))
56       return false;
57     if (stored_format == format)
58       return true;
59     int skip_length;
60     if (!iter->ReadLength(&skip_length))
61       return false;
62     if (!iter->SkipBytes(skip_length))
63       return false;
64   }
65   return false;
66 }
67
68 bool IsFormatAvailableInPickle(const base::string16& format,
69                                const Pickle& pickle) {
70   PickleIterator iter(pickle);
71   return JumpToFormatInPickle(format, &iter);
72 }
73
74 std::string ReadDataFromPickle(const base::string16& format,
75                                const Pickle& pickle) {
76   std::string result;
77   PickleIterator iter(pickle);
78   if (!JumpToFormatInPickle(format, &iter) || !iter.ReadString(&result))
79     return std::string();
80   return result;
81 }
82
83 bool WriteDataToPickle(const std::map<base::string16, std::string>& data,
84                        Pickle* pickle) {
85   pickle->WriteUInt64(data.size());
86   for (std::map<base::string16, std::string>::const_iterator it = data.begin();
87        it != data.end();
88        ++it) {
89     if (!pickle->WriteString16(it->first))
90       return false;
91     if (!pickle->WriteString(it->second))
92       return false;
93   }
94   return true;
95 }
96
97 }  // namespace
98
99 PepperFlashClipboardMessageFilter::PepperFlashClipboardMessageFilter() {}
100
101 PepperFlashClipboardMessageFilter::~PepperFlashClipboardMessageFilter() {}
102
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);
111
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.
116 #if !defined(OS_WIN)
117   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
118 #else
119   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
120 #endif
121 }
122
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,
133                                       OnMsgReadData)
134     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_WriteData,
135                                       OnMsgWriteData)
136     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
137         PpapiHostMsg_FlashClipboard_GetSequenceNumber, OnMsgGetSequenceNumber)
138   PPAPI_END_MESSAGE_MAP()
139   return PP_ERROR_FAILED;
140 }
141
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);
150   return PP_OK;
151 }
152
153 int32_t PepperFlashClipboardMessageFilter::OnMsgIsFormatAvailable(
154     ppapi::host::HostMessageContext* host_context,
155     uint32_t clipboard_type,
156     uint32_t format) {
157   if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
158     NOTIMPLEMENTED();
159     return PP_ERROR_FAILED;
160   }
161
162   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
163   ui::ClipboardType type = ConvertClipboardType(clipboard_type);
164   bool available = false;
165   switch (format) {
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;
172       break;
173     }
174     case PP_FLASH_CLIPBOARD_FORMAT_HTML:
175       available = clipboard->IsFormatAvailable(
176           ui::Clipboard::GetHtmlFormatType(), type);
177       break;
178     case PP_FLASH_CLIPBOARD_FORMAT_RTF:
179       available =
180           clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), type);
181       break;
182     case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
183       break;
184     default:
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(),
189                             &clipboard_data);
190         Pickle pickle(clipboard_data.data(), clipboard_data.size());
191         available =
192             IsFormatAvailableInPickle(base::UTF8ToUTF16(format_name), pickle);
193       }
194       break;
195   }
196
197   return available ? PP_OK : PP_ERROR_FAILED;
198 }
199
200 int32_t PepperFlashClipboardMessageFilter::OnMsgReadData(
201     ppapi::host::HostMessageContext* host_context,
202     uint32_t clipboard_type,
203     uint32_t format) {
204   if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
205     NOTIMPLEMENTED();
206     return PP_ERROR_FAILED;
207   }
208
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;
213   switch (format) {
214     case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: {
215       if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
216                                        type)) {
217         base::string16 text;
218         clipboard->ReadText(type, &text);
219         if (!text.empty()) {
220           result = PP_OK;
221           clipboard_string = base::UTF16ToUTF8(text);
222           break;
223         }
224       }
225       // If the PlainTextW format isn't available or is empty, take the
226       // ASCII text format.
227       if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
228                                        type)) {
229         result = PP_OK;
230         clipboard->ReadAsciiText(type, &clipboard_string);
231       }
232       break;
233     }
234     case PP_FLASH_CLIPBOARD_FORMAT_HTML: {
235       if (!clipboard->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(),
236                                         type)) {
237         break;
238       }
239
240       base::string16 html;
241       std::string url;
242       uint32 fragment_start;
243       uint32 fragment_end;
244       clipboard->ReadHTML(type, &html, &url, &fragment_start, &fragment_end);
245       result = PP_OK;
246       clipboard_string = base::UTF16ToUTF8(
247           html.substr(fragment_start, fragment_end - fragment_start));
248       break;
249     }
250     case PP_FLASH_CLIPBOARD_FORMAT_RTF: {
251       if (!clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(),
252                                         type)) {
253         break;
254       }
255       result = PP_OK;
256       clipboard->ReadRTF(type, &clipboard_string);
257       break;
258     }
259     case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
260       break;
261     default: {
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(),
267                             &clipboard_data);
268         Pickle pickle(clipboard_data.data(), clipboard_data.size());
269         if (IsFormatAvailableInPickle(format_name, pickle)) {
270           result = PP_OK;
271           clipboard_string = ReadDataFromPickle(format_name, pickle);
272         }
273       }
274       break;
275     }
276   }
277
278   if (result == PP_OK) {
279     host_context->reply_msg =
280         PpapiPluginMsg_FlashClipboard_ReadDataReply(clipboard_string);
281   }
282   return result;
283 }
284
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) {
291     NOTIMPLEMENTED();
292     return PP_ERROR_FAILED;
293   }
294   if (formats.size() != data.size())
295     return PP_ERROR_FAILED;
296
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);
302     return PP_OK;
303   }
304
305   ui::ScopedClipboardWriter scw(type);
306   std::map<base::string16, std::string> custom_data_map;
307   int32_t res = PP_OK;
308   for (uint32_t i = 0; i < formats.size(); ++i) {
309     if (data[i].length() > kMaxClipboardWriteSize) {
310       res = PP_ERROR_NOSPACE;
311       break;
312     }
313
314     switch (formats[i]) {
315       case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT:
316         scw.WriteText(base::UTF8ToUTF16(data[i]));
317         break;
318       case PP_FLASH_CLIPBOARD_FORMAT_HTML:
319         scw.WriteHTML(base::UTF8ToUTF16(data[i]), std::string());
320         break;
321       case PP_FLASH_CLIPBOARD_FORMAT_RTF:
322         scw.WriteRTF(data[i]);
323         break;
324       case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
325         res = PP_ERROR_BADARGUMENT;
326         break;
327       default:
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];
331         } else {
332           // Invalid format.
333           res = PP_ERROR_BADARGUMENT;
334           break;
335         }
336     }
337
338     if (res != PP_OK)
339       break;
340   }
341
342   if (custom_data_map.size() > 0) {
343     Pickle pickle;
344     if (WriteDataToPickle(custom_data_map, &pickle)) {
345       scw.WritePickledData(pickle,
346                            ui::Clipboard::GetPepperCustomDataFormatType());
347     } else {
348       res = PP_ERROR_BADARGUMENT;
349     }
350   }
351
352   if (res != PP_OK) {
353     // Need to clear the objects so nothing is written.
354     scw.Reset();
355   }
356
357   return res;
358 }
359
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) {
364     NOTIMPLEMENTED();
365     return PP_ERROR_FAILED;
366   }
367
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);
373   return PP_OK;
374 }
375
376 }  // namespace chrome