blob: 2866b1009a251a392937713d68826f964ced2d91 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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
Torne (Richard Coles)58218062012-11-14 11:43:16 +00007#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/stl_util.h"
10#include "content/common/clipboard_messages.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000011#include "content/public/browser/browser_context.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000012#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"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010016#include "url/gurl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000017
18namespace content {
19
20#if defined(OS_WIN)
21
22namespace {
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.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010027void WriteObjectsOnUIThread(ui::Clipboard::ObjectMap* objects) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000028 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
29 static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +010030 clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, *objects);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000031}
32
33} // namespace
34
35#endif
36
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010037ClipboardMessageFilter::ClipboardMessageFilter() {}
Torne (Richard Coles)58218062012-11-14 11:43:16 +000038
39void 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
61bool 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
88ClipboardMessageFilter::~ClipboardMessageFilter() {
89}
90
91void ClipboardMessageFilter::OnWriteObjectsSync(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000092 ui::Clipboard::ObjectMap objects,
Torne (Richard Coles)58218062012-11-14 11:43:16 +000093 base::SharedMemoryHandle bitmap_handle) {
94 DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
95 << "Bad bitmap handle";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000096 // Splice the shared memory handle into the clipboard data.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010097 ui::Clipboard::ReplaceSharedMemHandle(&objects, bitmap_handle, PeerHandle());
Torne (Richard Coles)58218062012-11-14 11:43:16 +000098#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.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000103 ui::Clipboard::ObjectMap* long_living_objects = new ui::Clipboard::ObjectMap;
104 long_living_objects->swap(objects);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000105
106 BrowserThread::PostTask(
107 BrowserThread::UI,
108 FROM_HERE,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100109 base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects)));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000110#else
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100111 GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000112#endif
113}
114
115void 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,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100131 base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects)));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000132#else
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100133 GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000134#endif
135}
136
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100137void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type,
138 uint64* sequence_number) {
139 *sequence_number = GetClipboard()->GetSequenceNumber(type);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000140}
141
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100142void ClipboardMessageFilter::OnReadAvailableTypes(ui::ClipboardType type,
143 std::vector<string16>* types,
144 bool* contains_filenames) {
145 GetClipboard()->ReadAvailableTypes(type, types, contains_filenames);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000146}
147
148void ClipboardMessageFilter::OnIsFormatAvailable(
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100149 const ui::Clipboard::FormatType& format,
150 ui::ClipboardType type,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000151 bool* result) {
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100152 *result = GetClipboard()->IsFormatAvailable(format, type);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000153}
154
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100155void ClipboardMessageFilter::OnClear(ui::ClipboardType type) {
156 GetClipboard()->Clear(type);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000157}
158
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100159void ClipboardMessageFilter::OnReadText(ui::ClipboardType type,
160 string16* result) {
161 GetClipboard()->ReadText(type, result);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000162}
163
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100164void ClipboardMessageFilter::OnReadAsciiText(ui::ClipboardType type,
165 std::string* result) {
166 GetClipboard()->ReadAsciiText(type, result);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000167}
168
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100169void ClipboardMessageFilter::OnReadHTML(ui::ClipboardType type,
170 string16* markup,
171 GURL* url,
172 uint32* fragment_start,
173 uint32* fragment_end) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000174 std::string src_url_str;
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100175 GetClipboard()->ReadHTML(type, markup, &src_url_str, fragment_start,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000176 fragment_end);
177 *url = GURL(src_url_str);
178}
179
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100180void ClipboardMessageFilter::OnReadRTF(ui::ClipboardType type,
181 std::string* result) {
182 GetClipboard()->ReadRTF(type, result);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000183}
184
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100185void ClipboardMessageFilter::OnReadImage(ui::ClipboardType type,
186 IPC::Message* reply_msg) {
187 SkBitmap bitmap = GetClipboard()->ReadImage(type);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000188
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
199void ClipboardMessageFilter::OnReadImageReply(
200 const SkBitmap& bitmap, IPC::Message* reply_msg) {
201 base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle();
202 uint32 image_size = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000203 if (!bitmap.isNull()) {
204 std::vector<unsigned char> png_data;
Torne (Richard Coles)424c4d72013-08-30 15:14:49 +0100205 if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &png_data)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000206 base::SharedMemory buffer;
207 if (buffer.CreateAndMapAnonymous(png_data.size())) {
208 memcpy(buffer.memory(), vector_as_array(&png_data), png_data.size());
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100209 if (buffer.GiveToProcess(PeerHandle(), &image_handle)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000210 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
Torne (Richard Coles)4e180b62013-10-18 15:46:22 +0100220void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type,
221 const string16& type,
222 string16* result) {
223 GetClipboard()->ReadCustomData(clipboard_type, type, result);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000224}
225
226void ClipboardMessageFilter::OnReadData(const ui::Clipboard::FormatType& format,
227 std::string* data) {
228 GetClipboard()->ReadData(format, data);
229}
230
231// static
232ui::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