Add some missing break statements.
[chromium-blink-merge.git] / content / browser / renderer_host / clipboard_message_filter.cc
blobe4f0240efdb24f382961a5f6007739acd1c2538b
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"
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"
21 namespace content {
23 namespace {
25 enum BitmapPolicy {
26 kFilterBitmap,
27 kAllowBitmap,
29 void SanitizeObjectMap(ui::Clipboard::ObjectMap* objects,
30 BitmapPolicy bitmap_policy) {
31 if (bitmap_policy != kAllowBitmap)
32 objects->erase(ui::Clipboard::CBF_SMBITMAP);
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);
52 } // namespace
55 ClipboardMessageFilter::ClipboardMessageFilter()
56 : BrowserMessageFilter(ClipboardMsgStart) {}
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.
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
74 #if defined(OS_WIN)
75 if (message.type() == ClipboardHostMsg_ReadImage::ID)
76 *thread = BrowserThread::FILE;
77 #endif
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;
105 ClipboardMessageFilter::~ClipboardMessageFilter() {
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";
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;
131 BrowserThread::PostTask(
132 BrowserThread::UI,
133 FROM_HERE,
134 base::Bind(&ClipboardMessageFilter::WriteObjectsOnUIThread,
135 base::Owned(long_living_objects.release())));
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(BrowserThread::CurrentlyOn(BrowserThread::UI));
146 static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
147 clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, *objects);
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);
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
173 void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type,
174 uint64* sequence_number) {
175 *sequence_number = GetClipboard()->GetSequenceNumber(type);
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);
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;
214 void ClipboardMessageFilter::OnClear(ui::ClipboardType type) {
215 GetClipboard()->Clear(type);
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();
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);
244 void ClipboardMessageFilter::OnReadRTF(ui::ClipboardType type,
245 std::string* result) {
246 GetClipboard()->ReadRTF(type, result);
249 void ClipboardMessageFilter::OnReadImage(ui::ClipboardType type,
250 IPC::Message* reply_msg) {
251 SkBitmap bitmap = GetClipboard()->ReadImage(type);
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
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();
279 ClipboardHostMsg_ReadImage::WriteReplyParams(reply_msg, image_handle,
280 image_size);
281 Send(reply_msg);
284 void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type,
285 const base::string16& type,
286 base::string16* result) {
287 GetClipboard()->ReadCustomData(clipboard_type, type, result);
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;
298 } // namespace content