- add sources.
[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/stl_util.h"
10 #include "content/common/clipboard_messages.h"
11 #include "content/public/browser/browser_context.h"
12 #include "ipc/ipc_message_macros.h"
13 #include "third_party/skia/include/core/SkBitmap.h"
14 #include "ui/gfx/codec/png_codec.h"
15 #include "ui/gfx/size.h"
16 #include "url/gurl.h"
17
18 namespace content {
19
20 #if defined(OS_WIN)
21
22 namespace {
23
24 // The write must be performed on the UI thread because the clipboard object
25 // from the IO thread cannot create windows so it cannot be the "owner" of the
26 // clipboard's contents.  // See http://crbug.com/5823.
27 void WriteObjectsOnUIThread(ui::Clipboard::ObjectMap* objects) {
28   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
29   static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
30   clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, *objects);
31 }
32
33 }  // namespace
34
35 #endif
36
37 ClipboardMessageFilter::ClipboardMessageFilter() {}
38
39 void ClipboardMessageFilter::OverrideThreadForMessage(
40     const IPC::Message& message, BrowserThread::ID* thread) {
41   // Clipboard writes should always occur on the UI thread due the restrictions
42   // of various platform APIs. In general, the clipboard is not thread-safe, so
43   // all clipboard calls should be serviced from the UI thread.
44   //
45   // Windows needs clipboard reads to be serviced from the IO thread because
46   // these are sync IPCs which can result in deadlocks with NPAPI plugins if
47   // serviced from the UI thread. Note that Windows clipboard calls ARE
48   // thread-safe so it is ok for reads and writes to be serviced from different
49   // threads.
50 #if !defined(OS_WIN)
51   if (IPC_MESSAGE_CLASS(message) == ClipboardMsgStart)
52     *thread = BrowserThread::UI;
53 #endif
54
55 #if defined(OS_WIN)
56   if (message.type() == ClipboardHostMsg_ReadImage::ID)
57     *thread = BrowserThread::FILE;
58 #endif
59 }
60
61 bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message,
62                                                bool* message_was_ok) {
63   bool handled = true;
64   IPC_BEGIN_MESSAGE_MAP_EX(ClipboardMessageFilter, message, *message_was_ok)
65     IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsAsync, OnWriteObjectsAsync)
66     IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsSync, OnWriteObjectsSync)
67     IPC_MESSAGE_HANDLER(ClipboardHostMsg_GetSequenceNumber, OnGetSequenceNumber)
68     IPC_MESSAGE_HANDLER(ClipboardHostMsg_IsFormatAvailable, OnIsFormatAvailable)
69     IPC_MESSAGE_HANDLER(ClipboardHostMsg_Clear, OnClear)
70     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadAvailableTypes,
71                         OnReadAvailableTypes)
72     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadText, OnReadText)
73     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadAsciiText, OnReadAsciiText)
74     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadHTML, OnReadHTML)
75     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadRTF, OnReadRTF)
76     IPC_MESSAGE_HANDLER_DELAY_REPLY(ClipboardHostMsg_ReadImage, OnReadImage)
77     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadCustomData, OnReadCustomData)
78     IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadData, OnReadData)
79 #if defined(OS_MACOSX)
80     IPC_MESSAGE_HANDLER(ClipboardHostMsg_FindPboardWriteStringAsync,
81                         OnFindPboardWriteString)
82 #endif
83     IPC_MESSAGE_UNHANDLED(handled = false)
84   IPC_END_MESSAGE_MAP()
85   return handled;
86 }
87
88 ClipboardMessageFilter::~ClipboardMessageFilter() {
89 }
90
91 void ClipboardMessageFilter::OnWriteObjectsSync(
92     ui::Clipboard::ObjectMap objects,
93     base::SharedMemoryHandle bitmap_handle) {
94   DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
95       << "Bad bitmap handle";
96   // Splice the shared memory handle into the clipboard data.
97   ui::Clipboard::ReplaceSharedMemHandle(&objects, bitmap_handle, PeerHandle());
98 #if defined(OS_WIN)
99   // We cannot write directly from the IO thread, and cannot service the IPC
100   // on the UI thread. We'll copy the relevant data and get a handle to any
101   // shared memory so it doesn't go away when we resume the renderer, and post
102   // a task to perform the write on the UI thread.
103   ui::Clipboard::ObjectMap* long_living_objects = new ui::Clipboard::ObjectMap;
104   long_living_objects->swap(objects);
105
106   BrowserThread::PostTask(
107       BrowserThread::UI,
108       FROM_HERE,
109       base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects)));
110 #else
111   GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
112 #endif
113 }
114
115 void ClipboardMessageFilter::OnWriteObjectsAsync(
116     const ui::Clipboard::ObjectMap& objects) {
117 #if defined(OS_WIN)
118   // We cannot write directly from the IO thread, and cannot service the IPC
119   // on the UI thread. We'll copy the relevant data and post a task to preform
120   // the write on the UI thread.
121   ui::Clipboard::ObjectMap* long_living_objects =
122       new ui::Clipboard::ObjectMap(objects);
123
124   // This async message doesn't support shared-memory based bitmaps; they must
125   // be removed otherwise we might dereference a rubbish pointer.
126   long_living_objects->erase(ui::Clipboard::CBF_SMBITMAP);
127
128   BrowserThread::PostTask(
129       BrowserThread::UI,
130       FROM_HERE,
131       base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects)));
132 #else
133   GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
134 #endif
135 }
136
137 void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type,
138                                                  uint64* sequence_number) {
139   *sequence_number = GetClipboard()->GetSequenceNumber(type);
140 }
141
142 void ClipboardMessageFilter::OnReadAvailableTypes(ui::ClipboardType type,
143                                                   std::vector<string16>* types,
144                                                   bool* contains_filenames) {
145   GetClipboard()->ReadAvailableTypes(type, types, contains_filenames);
146 }
147
148 void ClipboardMessageFilter::OnIsFormatAvailable(
149     const ui::Clipboard::FormatType& format,
150     ui::ClipboardType type,
151     bool* result) {
152   *result = GetClipboard()->IsFormatAvailable(format, type);
153 }
154
155 void ClipboardMessageFilter::OnClear(ui::ClipboardType type) {
156   GetClipboard()->Clear(type);
157 }
158
159 void ClipboardMessageFilter::OnReadText(ui::ClipboardType type,
160                                         string16* result) {
161   GetClipboard()->ReadText(type, result);
162 }
163
164 void ClipboardMessageFilter::OnReadAsciiText(ui::ClipboardType type,
165                                              std::string* result) {
166   GetClipboard()->ReadAsciiText(type, result);
167 }
168
169 void ClipboardMessageFilter::OnReadHTML(ui::ClipboardType type,
170                                         string16* markup,
171                                         GURL* url,
172                                         uint32* fragment_start,
173                                         uint32* fragment_end) {
174   std::string src_url_str;
175   GetClipboard()->ReadHTML(type, markup, &src_url_str, fragment_start,
176                            fragment_end);
177   *url = GURL(src_url_str);
178 }
179
180 void ClipboardMessageFilter::OnReadRTF(ui::ClipboardType type,
181                                        std::string* result) {
182   GetClipboard()->ReadRTF(type, result);
183 }
184
185 void ClipboardMessageFilter::OnReadImage(ui::ClipboardType type,
186                                          IPC::Message* reply_msg) {
187   SkBitmap bitmap = GetClipboard()->ReadImage(type);
188
189 #if defined(USE_X11)
190   BrowserThread::PostTask(
191       BrowserThread::FILE, FROM_HERE,
192       base::Bind(
193           &ClipboardMessageFilter::OnReadImageReply, this, bitmap, reply_msg));
194 #else
195   OnReadImageReply(bitmap, reply_msg);
196 #endif
197 }
198
199 void ClipboardMessageFilter::OnReadImageReply(
200     const SkBitmap& bitmap, IPC::Message* reply_msg) {
201   base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle();
202   uint32 image_size = 0;
203   if (!bitmap.isNull()) {
204     std::vector<unsigned char> png_data;
205     if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &png_data)) {
206       base::SharedMemory buffer;
207       if (buffer.CreateAndMapAnonymous(png_data.size())) {
208         memcpy(buffer.memory(), vector_as_array(&png_data), png_data.size());
209         if (buffer.GiveToProcess(PeerHandle(), &image_handle)) {
210           image_size = png_data.size();
211         }
212       }
213     }
214   }
215   ClipboardHostMsg_ReadImage::WriteReplyParams(reply_msg, image_handle,
216                                                image_size);
217   Send(reply_msg);
218 }
219
220 void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type,
221                                               const string16& type,
222                                               string16* result) {
223   GetClipboard()->ReadCustomData(clipboard_type, type, result);
224 }
225
226 void ClipboardMessageFilter::OnReadData(const ui::Clipboard::FormatType& format,
227                                         std::string* data) {
228   GetClipboard()->ReadData(format, data);
229 }
230
231 // static
232 ui::Clipboard* ClipboardMessageFilter::GetClipboard() {
233   // We have a static instance of the clipboard service for use by all message
234   // filters.  This instance lives for the life of the browser processes.
235   static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
236   return clipboard;
237 }
238
239 }  // namespace content