- add sources.
[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 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     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 string16& format, const Pickle& pickle) {
69   PickleIterator iter(pickle);
70   return JumpToFormatInPickle(format, &iter);
71 }
72
73 std::string ReadDataFromPickle(const string16& format, const Pickle& pickle) {
74   std::string result;
75   PickleIterator iter(pickle);
76   if (!JumpToFormatInPickle(format, &iter) || !iter.ReadString(&result))
77     return std::string();
78   return result;
79 }
80
81 bool WriteDataToPickle(const std::map<string16, std::string>& data,
82                        Pickle* pickle) {
83   pickle->WriteUInt64(data.size());
84   for (std::map<string16, std::string>::const_iterator it = data.begin();
85        it != data.end(); ++it) {
86     if (!pickle->WriteString16(it->first))
87       return false;
88     if (!pickle->WriteString(it->second))
89       return false;
90   }
91   return true;
92 }
93
94 }  // namespace
95
96 PepperFlashClipboardMessageFilter::PepperFlashClipboardMessageFilter() {
97 }
98
99 PepperFlashClipboardMessageFilter::~PepperFlashClipboardMessageFilter() {
100 }
101
102 scoped_refptr<base::TaskRunner>
103 PepperFlashClipboardMessageFilter::OverrideTaskRunnerForMessage(
104     const IPC::Message& msg) {
105   // Clipboard writes should always occur on the UI thread due to the
106   // restrictions of various platform APIs. In general, the clipboard is not
107   // thread-safe, so all clipboard calls should be serviced from the UI thread.
108   if (msg.type() == PpapiHostMsg_FlashClipboard_WriteData::ID)
109     return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
110
111   // Windows needs clipboard reads to be serviced from the IO thread because
112   // these are sync IPCs which can result in deadlocks with plugins if serviced
113   // from the UI thread. Note that Windows clipboard calls ARE thread-safe so it
114   // is ok for reads and writes to be serviced from different threads.
115 #if !defined(OS_WIN)
116   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
117 #else
118   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
119 #endif
120 }
121
122 int32_t PepperFlashClipboardMessageFilter::OnResourceMessageReceived(
123     const IPC::Message& msg,
124     ppapi::host::HostMessageContext* context) {
125   IPC_BEGIN_MESSAGE_MAP(PepperFlashClipboardMessageFilter, msg)
126     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
127         PpapiHostMsg_FlashClipboard_RegisterCustomFormat,
128         OnMsgRegisterCustomFormat);
129     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
130         PpapiHostMsg_FlashClipboard_IsFormatAvailable,
131         OnMsgIsFormatAvailable);
132     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
133         PpapiHostMsg_FlashClipboard_ReadData,
134         OnMsgReadData);
135     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
136         PpapiHostMsg_FlashClipboard_WriteData,
137         OnMsgWriteData);
138   IPC_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(
189             ui::Clipboard::GetPepperCustomDataFormatType(), &clipboard_data);
190         Pickle pickle(clipboard_data.data(), clipboard_data.size());
191         available = IsFormatAvailableInPickle(UTF8ToUTF16(format_name), pickle);
192       }
193       break;
194   }
195
196   return available ? PP_OK : PP_ERROR_FAILED;
197 }
198
199 int32_t PepperFlashClipboardMessageFilter::OnMsgReadData(
200     ppapi::host::HostMessageContext* host_context,
201     uint32_t clipboard_type,
202     uint32_t format) {
203   if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
204     NOTIMPLEMENTED();
205     return PP_ERROR_FAILED;
206   }
207
208   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
209   ui::ClipboardType type = ConvertClipboardType(clipboard_type);
210   std::string clipboard_string;
211   int32_t result = PP_ERROR_FAILED;
212   switch (format) {
213     case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: {
214       if (clipboard->IsFormatAvailable(
215           ui::Clipboard::GetPlainTextWFormatType(), type)) {
216         string16 text;
217         clipboard->ReadText(type, &text);
218         if (!text.empty()) {
219           result = PP_OK;
220           clipboard_string = UTF16ToUTF8(text);
221           break;
222         }
223       }
224       // If the PlainTextW format isn't available or is empty, take the
225       // ASCII text format.
226       if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
227                                        type)) {
228         result = PP_OK;
229         clipboard->ReadAsciiText(type, &clipboard_string);
230       }
231       break;
232     }
233     case PP_FLASH_CLIPBOARD_FORMAT_HTML: {
234       if (!clipboard->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(),
235                                         type)) {
236         break;
237       }
238
239       string16 html;
240       std::string url;
241       uint32 fragment_start;
242       uint32 fragment_end;
243       clipboard->ReadHTML(type, &html, &url, &fragment_start, &fragment_end);
244       result = PP_OK;
245       clipboard_string = UTF16ToUTF8(
246           html.substr(fragment_start, fragment_end - fragment_start));
247       break;
248     }
249     case PP_FLASH_CLIPBOARD_FORMAT_RTF: {
250       if (!clipboard->IsFormatAvailable(
251           ui::Clipboard::GetRtfFormatType(), type)) {
252         break;
253       }
254       result = PP_OK;
255       clipboard->ReadRTF(type, &clipboard_string);
256       break;
257     }
258     case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
259       break;
260     default: {
261       if (custom_formats_.IsFormatRegistered(format)) {
262         string16 format_name =
263             UTF8ToUTF16(custom_formats_.GetFormatName(format));
264         std::string clipboard_data;
265         clipboard->ReadData(
266             ui::Clipboard::GetPepperCustomDataFormatType(), &clipboard_data);
267         Pickle pickle(clipboard_data.data(), clipboard_data.size());
268         if (IsFormatAvailableInPickle(format_name, pickle)) {
269           result = PP_OK;
270           clipboard_string = ReadDataFromPickle(format_name, pickle);
271         }
272       }
273       break;
274     }
275   }
276
277   if (result == PP_OK) {
278     host_context->reply_msg =
279         PpapiPluginMsg_FlashClipboard_ReadDataReply(clipboard_string);
280   }
281   return result;
282 }
283
284 int32_t PepperFlashClipboardMessageFilter::OnMsgWriteData(
285     ppapi::host::HostMessageContext* host_context,
286     uint32_t clipboard_type,
287     const std::vector<uint32_t>& formats,
288     const std::vector<std::string>& data) {
289   if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
290     NOTIMPLEMENTED();
291     return PP_ERROR_FAILED;
292   }
293   if (formats.size() != data.size())
294     return PP_ERROR_FAILED;
295
296   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
297   ui::ClipboardType type = ConvertClipboardType(clipboard_type);
298   // If no formats are passed in clear the clipboard.
299   if (formats.size() == 0) {
300     clipboard->Clear(type);
301     return PP_OK;
302   }
303
304   ui::ScopedClipboardWriter scw(clipboard, type);
305   std::map<string16, std::string> custom_data_map;
306   int32_t res = PP_OK;
307   for (uint32_t i = 0; i < formats.size(); ++i) {
308     if (data[i].length() > kMaxClipboardWriteSize) {
309       res = PP_ERROR_NOSPACE;
310       break;
311     }
312
313     switch (formats[i]) {
314       case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT:
315         scw.WriteText(UTF8ToUTF16(data[i]));
316         break;
317       case PP_FLASH_CLIPBOARD_FORMAT_HTML:
318         scw.WriteHTML(UTF8ToUTF16(data[i]), std::string());
319         break;
320       case PP_FLASH_CLIPBOARD_FORMAT_RTF:
321         scw.WriteRTF(data[i]);
322         break;
323       case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
324         res = PP_ERROR_BADARGUMENT;
325         break;
326       default:
327         if (custom_formats_.IsFormatRegistered(formats[i])) {
328           std::string format_name = custom_formats_.GetFormatName(formats[i]);
329           custom_data_map[UTF8ToUTF16(format_name)] = data[i];
330         } else {
331           // Invalid format.
332           res = PP_ERROR_BADARGUMENT;
333           break;
334         }
335     }
336
337     if (res != PP_OK)
338       break;
339   }
340
341   if (custom_data_map.size() > 0) {
342     Pickle pickle;
343     if (WriteDataToPickle(custom_data_map, &pickle)) {
344       scw.WritePickledData(pickle,
345                            ui::Clipboard::GetPepperCustomDataFormatType());
346     } else {
347       res = PP_ERROR_BADARGUMENT;
348     }
349   }
350
351   if (res != PP_OK) {
352     // Need to clear the objects so nothing is written.
353     scw.Reset();
354   }
355
356   return res;
357 }
358
359 }  // namespace chrome