Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 7 | #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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 11 | #include "content/public/browser/browser_context.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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" |
Ben Murdoch | 7dbb3d5 | 2013-07-17 14:55:54 +0100 | [diff] [blame] | 16 | #include "url/gurl.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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. |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 27 | void WriteObjectsOnUIThread(ui::Clipboard::ObjectMap* objects) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 28 | DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 29 | static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 30 | clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, *objects); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 31 | } |
| 32 | |
| 33 | } // namespace |
| 34 | |
| 35 | #endif |
| 36 | |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 37 | ClipboardMessageFilter::ClipboardMessageFilter() {} |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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( |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 92 | ui::Clipboard::ObjectMap objects, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 93 | base::SharedMemoryHandle bitmap_handle) { |
| 94 | DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle)) |
| 95 | << "Bad bitmap handle"; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 96 | // Splice the shared memory handle into the clipboard data. |
Ben Murdoch | 7dbb3d5 | 2013-07-17 14:55:54 +0100 | [diff] [blame] | 97 | ui::Clipboard::ReplaceSharedMemHandle(&objects, bitmap_handle, PeerHandle()); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 103 | ui::Clipboard::ObjectMap* long_living_objects = new ui::Clipboard::ObjectMap; |
| 104 | long_living_objects->swap(objects); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 105 | |
| 106 | BrowserThread::PostTask( |
| 107 | BrowserThread::UI, |
| 108 | FROM_HERE, |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 109 | base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects))); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 110 | #else |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 111 | GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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, |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 131 | base::Bind(&WriteObjectsOnUIThread, base::Owned(long_living_objects))); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 132 | #else |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 133 | GetClipboard()->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 134 | #endif |
| 135 | } |
| 136 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 137 | void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type, |
| 138 | uint64* sequence_number) { |
| 139 | *sequence_number = GetClipboard()->GetSequenceNumber(type); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 140 | } |
| 141 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 142 | void ClipboardMessageFilter::OnReadAvailableTypes(ui::ClipboardType type, |
| 143 | std::vector<string16>* types, |
| 144 | bool* contains_filenames) { |
| 145 | GetClipboard()->ReadAvailableTypes(type, types, contains_filenames); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | void ClipboardMessageFilter::OnIsFormatAvailable( |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 149 | const ui::Clipboard::FormatType& format, |
| 150 | ui::ClipboardType type, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 151 | bool* result) { |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 152 | *result = GetClipboard()->IsFormatAvailable(format, type); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 153 | } |
| 154 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 155 | void ClipboardMessageFilter::OnClear(ui::ClipboardType type) { |
| 156 | GetClipboard()->Clear(type); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 157 | } |
| 158 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 159 | void ClipboardMessageFilter::OnReadText(ui::ClipboardType type, |
| 160 | string16* result) { |
| 161 | GetClipboard()->ReadText(type, result); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 162 | } |
| 163 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 164 | void ClipboardMessageFilter::OnReadAsciiText(ui::ClipboardType type, |
| 165 | std::string* result) { |
| 166 | GetClipboard()->ReadAsciiText(type, result); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 167 | } |
| 168 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 169 | void ClipboardMessageFilter::OnReadHTML(ui::ClipboardType type, |
| 170 | string16* markup, |
| 171 | GURL* url, |
| 172 | uint32* fragment_start, |
| 173 | uint32* fragment_end) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 174 | std::string src_url_str; |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 175 | GetClipboard()->ReadHTML(type, markup, &src_url_str, fragment_start, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 176 | fragment_end); |
| 177 | *url = GURL(src_url_str); |
| 178 | } |
| 179 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 180 | void ClipboardMessageFilter::OnReadRTF(ui::ClipboardType type, |
| 181 | std::string* result) { |
| 182 | GetClipboard()->ReadRTF(type, result); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 183 | } |
| 184 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 185 | void ClipboardMessageFilter::OnReadImage(ui::ClipboardType type, |
| 186 | IPC::Message* reply_msg) { |
| 187 | SkBitmap bitmap = GetClipboard()->ReadImage(type); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 203 | if (!bitmap.isNull()) { |
| 204 | std::vector<unsigned char> png_data; |
Torne (Richard Coles) | 424c4d7 | 2013-08-30 15:14:49 +0100 | [diff] [blame] | 205 | if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &png_data)) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 206 | base::SharedMemory buffer; |
| 207 | if (buffer.CreateAndMapAnonymous(png_data.size())) { |
| 208 | memcpy(buffer.memory(), vector_as_array(&png_data), png_data.size()); |
Ben Murdoch | 7dbb3d5 | 2013-07-17 14:55:54 +0100 | [diff] [blame] | 209 | if (buffer.GiveToProcess(PeerHandle(), &image_handle)) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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 | |
Torne (Richard Coles) | 4e180b6 | 2013-10-18 15:46:22 +0100 | [diff] [blame^] | 220 | void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type, |
| 221 | const string16& type, |
| 222 | string16* result) { |
| 223 | GetClipboard()->ReadCustomData(clipboard_type, type, result); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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 |