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.
5 #include "content/browser/renderer_host/clipboard_message_filter.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"
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);
37 ClipboardMessageFilter::ClipboardMessageFilter() {}
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.
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
51 if (IPC_MESSAGE_CLASS(message) == ClipboardMsgStart)
52 *thread = BrowserThread::UI;
56 if (message.type() == ClipboardHostMsg_ReadImage::ID)
57 *thread = BrowserThread::FILE;
61 bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message,
62 bool* message_was_ok) {
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,
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)
83 IPC_MESSAGE_UNHANDLED(handled = false)
88 ClipboardMessageFilter::~ClipboardMessageFilter() {
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());
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);
106 BrowserThread::PostTask(
109 base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects)));
111 GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
115 void ClipboardMessageFilter::OnWriteObjectsAsync(
116 const ui::Clipboard::ObjectMap& objects) {
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);
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);
128 BrowserThread::PostTask(
131 base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects)));
133 GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
137 void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type,
138 uint64* sequence_number) {
139 *sequence_number = GetClipboard()->GetSequenceNumber(type);
142 void ClipboardMessageFilter::OnReadAvailableTypes(ui::ClipboardType type,
143 std::vector<string16>* types,
144 bool* contains_filenames) {
145 GetClipboard()->ReadAvailableTypes(type, types, contains_filenames);
148 void ClipboardMessageFilter::OnIsFormatAvailable(
149 const ui::Clipboard::FormatType& format,
150 ui::ClipboardType type,
152 *result = GetClipboard()->IsFormatAvailable(format, type);
155 void ClipboardMessageFilter::OnClear(ui::ClipboardType type) {
156 GetClipboard()->Clear(type);
159 void ClipboardMessageFilter::OnReadText(ui::ClipboardType type,
161 GetClipboard()->ReadText(type, result);
164 void ClipboardMessageFilter::OnReadAsciiText(ui::ClipboardType type,
165 std::string* result) {
166 GetClipboard()->ReadAsciiText(type, result);
169 void ClipboardMessageFilter::OnReadHTML(ui::ClipboardType type,
172 uint32* fragment_start,
173 uint32* fragment_end) {
174 std::string src_url_str;
175 GetClipboard()->ReadHTML(type, markup, &src_url_str, fragment_start,
177 *url = GURL(src_url_str);
180 void ClipboardMessageFilter::OnReadRTF(ui::ClipboardType type,
181 std::string* result) {
182 GetClipboard()->ReadRTF(type, result);
185 void ClipboardMessageFilter::OnReadImage(ui::ClipboardType type,
186 IPC::Message* reply_msg) {
187 SkBitmap bitmap = GetClipboard()->ReadImage(type);
190 BrowserThread::PostTask(
191 BrowserThread::FILE, FROM_HERE,
193 &ClipboardMessageFilter::OnReadImageReply, this, bitmap, reply_msg));
195 OnReadImageReply(bitmap, reply_msg);
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();
215 ClipboardHostMsg_ReadImage::WriteReplyParams(reply_msg, image_handle,
220 void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type,
221 const string16& type,
223 GetClipboard()->ReadCustomData(clipboard_type, type, result);
226 void ClipboardMessageFilter::OnReadData(const ui::Clipboard::FormatType& format,
228 GetClipboard()->ReadData(format, data);
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();
239 } // namespace content