Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / 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 "content/browser/renderer_host/clipboard_message_filter.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/common/clipboard_messages.h"
14 #include "content/public/browser/browser_context.h"
15 #include "ipc/ipc_message_macros.h"
16 #include "third_party/skia/include/core/SkBitmap.h"
17 #include "ui/gfx/codec/png_codec.h"
18 #include "ui/gfx/size.h"
19 #include "url/gurl.h"
20
21 namespace content {
22
23 namespace {
24
25 enum BitmapPolicy {
26   kFilterBitmap,
27   kAllowBitmap,
28 };
29 void SanitizeObjectMap(ui::Clipboard::ObjectMap* objects,
30                        BitmapPolicy bitmap_policy) {
31   if (bitmap_policy != kAllowBitmap)
32     objects->erase(ui::Clipboard::CBF_SMBITMAP);
33
34   ui::Clipboard::ObjectMap::iterator data_it =
35       objects->find(ui::Clipboard::CBF_DATA);
36   if (data_it != objects->end()) {
37     const ui::Clipboard::FormatType& web_custom_format =
38         ui::Clipboard::GetWebCustomDataFormatType();
39     if (data_it->second.size() != 2 ||
40         !web_custom_format.Equals(
41             ui::Clipboard::FormatType::Deserialize(std::string(
42                 &data_it->second[0].front(),
43                 data_it->second[0].size())))) {
44       // CBF_DATA should always have two parameters associated with it, and the
45       // associated FormatType should always be web custom data. If not, then
46       // data is malformed and we'll ignore it.
47       objects->erase(ui::Clipboard::CBF_DATA);
48     }
49   }
50 }
51
52 }  // namespace
53
54
55 ClipboardMessageFilter::ClipboardMessageFilter()
56     : BrowserMessageFilter(ClipboardMsgStart) {}
57
58 void ClipboardMessageFilter::OverrideThreadForMessage(
59     const IPC::Message& message, BrowserThread::ID* thread) {
60   // Clipboard writes should always occur on the UI thread due the restrictions
61   // of various platform APIs. In general, the clipboard is not thread-safe, so
62   // all clipboard calls should be serviced from the UI thread.
63   //
64   // Windows needs clipboard reads to be serviced from the IO thread because
65   // these are sync IPCs which can result in deadlocks with NPAPI plugins if
66   // serviced from the UI thread. Note that Windows clipboard calls ARE
67   // thread-safe so it is ok for reads and writes to be serviced from different
68   // threads.
69 #if !defined(OS_WIN)
70   if (IPC_MESSAGE_CLASS(message) == ClipboardMsgStart)
71     *thread = BrowserThread::UI;
72 #endif
73
74 #if defined(OS_WIN)
75   if (message.type() == ClipboardHostMsg_ReadImage::ID)
76     *thread = BrowserThread::FILE;
77 #endif
78 }
79
80 bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message,
81                                                bool* message_was_ok) {
82   bool handled = true;
83   IPC_BEGIN_MESSAGE_MAP_EX(ClipboardMessageFilter, message, *message_was_ok)
84     IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsAsync, OnWriteObjectsAsync)
85     IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsSync, OnWriteObjectsSync)
86     IPC_MESSAGE_HANDLER(ClipboardHostMsg_GetSequenceNumber, OnGetSequenceNumber)
87     IPC_MESSAGE_HANDLER(ClipboardHostMsg_IsFormatAvailable, OnIsFormatAvailable)
88     IPC_MESSAGE_HANDLER(ClipboardHostMsg_Clear, OnClear)
89     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadAvailableTypes,
90                         OnReadAvailableTypes)
91     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadText, OnReadText)
92     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadHTML, OnReadHTML)
93     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadRTF, OnReadRTF)
94     IPC_MESSAGE_HANDLER_DELAY_REPLY(ClipboardHostMsg_ReadImage, OnReadImage)
95     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadCustomData, OnReadCustomData)
96 #if defined(OS_MACOSX)
97     IPC_MESSAGE_HANDLER(ClipboardHostMsg_FindPboardWriteStringAsync,
98                         OnFindPboardWriteString)
99 #endif
100     IPC_MESSAGE_UNHANDLED(handled = false)
101   IPC_END_MESSAGE_MAP()
102   return handled;
103 }
104
105 ClipboardMessageFilter::~ClipboardMessageFilter() {
106 }
107
108 void ClipboardMessageFilter::OnWriteObjectsSync(
109     const ui::Clipboard::ObjectMap& objects,
110     base::SharedMemoryHandle bitmap_handle) {
111   DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
112       << "Bad bitmap handle";
113
114   // On Windows, we can't write directly from the IO thread, so we copy the data
115   // into a heap allocated map and post a task to the UI thread. On other
116   // platforms, to lower the amount of time the renderer has to wait for the
117   // sync IPC to complete, we also take a copy and post a task to flush the data
118   // to the clipboard later.
119   scoped_ptr<ui::Clipboard::ObjectMap> long_living_objects(
120       new ui::Clipboard::ObjectMap(objects));
121   SanitizeObjectMap(long_living_objects.get(), kAllowBitmap);
122   // Splice the shared memory handle into the data. |long_living_objects| now
123   // contains a heap-allocated SharedMemory object that references
124   // |bitmap_handle|. This reference will keep the shared memory section alive
125   // when this IPC returns, and the SharedMemory object will eventually be
126   // freed by ui::Clipboard::WriteObjects().
127   if (!ui::Clipboard::ReplaceSharedMemHandle(
128            long_living_objects.get(), bitmap_handle, PeerHandle()))
129     return;
130
131   BrowserThread::PostTask(
132       BrowserThread::UI,
133       FROM_HERE,
134       base::Bind(&ClipboardMessageFilter::WriteObjectsOnUIThread,
135                  base::Owned(long_living_objects.release())));
136 }
137
138 // On Windows, the write must be performed on the UI thread because the
139 // clipboard object from the IO thread cannot create windows so it cannot be
140 // the "owner" of the clipboard's contents. See http://crbug.com/5823.
141 // TODO(dcheng): Temporarily a member of ClipboardMessageFilter so it can access
142 // ui::Clipboard::WriteObjects().
143 void ClipboardMessageFilter::WriteObjectsOnUIThread(
144     const ui::Clipboard::ObjectMap* objects) {
145   DCHECK_CURRENTLY_ON(BrowserThread::UI);
146   static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
147   clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, *objects);
148 }
149
150 void ClipboardMessageFilter::OnWriteObjectsAsync(
151     const ui::Clipboard::ObjectMap& objects) {
152   // This async message doesn't support shared-memory based bitmaps; they must
153   // be removed otherwise we might dereference a rubbish pointer.
154   scoped_ptr<ui::Clipboard::ObjectMap> sanitized_objects(
155       new ui::Clipboard::ObjectMap(objects));
156   SanitizeObjectMap(sanitized_objects.get(), kFilterBitmap);
157
158 #if defined(OS_WIN)
159   // We cannot write directly from the IO thread, and cannot service the IPC
160   // on the UI thread. We'll copy the relevant data and post a task to preform
161   // the write on the UI thread.
162   BrowserThread::PostTask(
163       BrowserThread::UI,
164       FROM_HERE,
165       base::Bind(
166           &WriteObjectsOnUIThread, base::Owned(sanitized_objects.release())));
167 #else
168   GetClipboard()->WriteObjects(
169       ui::CLIPBOARD_TYPE_COPY_PASTE, *sanitized_objects.get());
170 #endif
171 }
172
173 void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type,
174                                                  uint64* sequence_number) {
175   *sequence_number = GetClipboard()->GetSequenceNumber(type);
176 }
177
178 void ClipboardMessageFilter::OnReadAvailableTypes(
179     ui::ClipboardType type,
180     std::vector<base::string16>* types,
181     bool* contains_filenames) {
182   GetClipboard()->ReadAvailableTypes(type, types, contains_filenames);
183 }
184
185 void ClipboardMessageFilter::OnIsFormatAvailable(ClipboardFormat format,
186                                                  ui::ClipboardType type,
187                                                  bool* result) {
188   switch (format) {
189     case CLIPBOARD_FORMAT_PLAINTEXT:
190       *result = GetClipboard()->IsFormatAvailable(
191                     ui::Clipboard::GetPlainTextWFormatType(), type) ||
192                 GetClipboard()->IsFormatAvailable(
193                     ui::Clipboard::GetPlainTextFormatType(), type);
194       break;
195     case CLIPBOARD_FORMAT_HTML:
196       *result = GetClipboard()->IsFormatAvailable(
197           ui::Clipboard::GetHtmlFormatType(), type);
198       break;
199     case CLIPBOARD_FORMAT_SMART_PASTE:
200       *result = GetClipboard()->IsFormatAvailable(
201           ui::Clipboard::GetWebKitSmartPasteFormatType(), type);
202       break;
203     case CLIPBOARD_FORMAT_BOOKMARK:
204 #if defined(OS_WIN) || defined(OS_MACOSX)
205       *result = GetClipboard()->IsFormatAvailable(
206           ui::Clipboard::GetUrlWFormatType(), type);
207 #else
208       *result = false;
209 #endif
210       break;
211   }
212 }
213
214 void ClipboardMessageFilter::OnClear(ui::ClipboardType type) {
215   GetClipboard()->Clear(type);
216 }
217
218 void ClipboardMessageFilter::OnReadText(ui::ClipboardType type,
219                                         base::string16* result) {
220   if (GetClipboard()->IsFormatAvailable(
221           ui::Clipboard::GetPlainTextWFormatType(), type)) {
222     GetClipboard()->ReadText(type, result);
223   } else if (GetClipboard()->IsFormatAvailable(
224                  ui::Clipboard::GetPlainTextFormatType(), type)) {
225     std::string ascii;
226     GetClipboard()->ReadAsciiText(type, &ascii);
227     *result = base::ASCIIToUTF16(ascii);
228   } else {
229     result->clear();
230   }
231 }
232
233 void ClipboardMessageFilter::OnReadHTML(ui::ClipboardType type,
234                                         base::string16* markup,
235                                         GURL* url,
236                                         uint32* fragment_start,
237                                         uint32* fragment_end) {
238   std::string src_url_str;
239   GetClipboard()->ReadHTML(type, markup, &src_url_str, fragment_start,
240                            fragment_end);
241   *url = GURL(src_url_str);
242 }
243
244 void ClipboardMessageFilter::OnReadRTF(ui::ClipboardType type,
245                                        std::string* result) {
246   GetClipboard()->ReadRTF(type, result);
247 }
248
249 void ClipboardMessageFilter::OnReadImage(ui::ClipboardType type,
250                                          IPC::Message* reply_msg) {
251   SkBitmap bitmap = GetClipboard()->ReadImage(type);
252
253 #if defined(USE_X11)
254   BrowserThread::PostTask(
255       BrowserThread::FILE, FROM_HERE,
256       base::Bind(
257           &ClipboardMessageFilter::OnReadImageReply, this, bitmap, reply_msg));
258 #else
259   OnReadImageReply(bitmap, reply_msg);
260 #endif
261 }
262
263 void ClipboardMessageFilter::OnReadImageReply(
264     const SkBitmap& bitmap, IPC::Message* reply_msg) {
265   base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle();
266   uint32 image_size = 0;
267   if (!bitmap.isNull()) {
268     std::vector<unsigned char> png_data;
269     if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &png_data)) {
270       base::SharedMemory buffer;
271       if (buffer.CreateAndMapAnonymous(png_data.size())) {
272         memcpy(buffer.memory(), vector_as_array(&png_data), png_data.size());
273         if (buffer.GiveToProcess(PeerHandle(), &image_handle)) {
274           image_size = png_data.size();
275         }
276       }
277     }
278   }
279   ClipboardHostMsg_ReadImage::WriteReplyParams(reply_msg, image_handle,
280                                                image_size);
281   Send(reply_msg);
282 }
283
284 void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type,
285                                               const base::string16& type,
286                                               base::string16* result) {
287   GetClipboard()->ReadCustomData(clipboard_type, type, result);
288 }
289
290 // static
291 ui::Clipboard* ClipboardMessageFilter::GetClipboard() {
292   // We have a static instance of the clipboard service for use by all message
293   // filters.  This instance lives for the life of the browser processes.
294   static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
295   return clipboard;
296 }
297
298 }  // namespace content