Reland rewrite clipboard write IPC handling to be easier to understand.
The original implementation sent clipboard data to be written over IPC
as a map of clipboard formats to 'parameters' for that format. The
parameters were just vectors of byte vectors. Needless to say, this
logic was complicated, fragile, and prone to bugs. In the browser
process, this resulted in the IPC validation logic being scattered
between ClipboardMessageFilter and Clipboard::DispatchObject.
The rewrite adds an IPC message for each flavor of data that the
renderer is allowed to write to the clipboard. On the browser side,
the logic is simply delegated to ScopedClipboardWriter. Since the
clipboard object map is no longer under the control of an untrusted
process, this allows the removal of a lot of validation logic.
Unfortunately, bitmap handling is still a bit complicated because it's
sent over shared memory, but all the validation logic has been moved
into ClipboardMessageFilter.
BUG=319285
[email protected],[email protected],[email protected]
Review URL: https://codereview.chromium.org/740763003
Cr-Commit-Position: refs/heads/master@{#304988}
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 285a9d3b..19f8609 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -607,6 +607,7 @@
'<(DEPTH)/net/net.gyp:net',
'<(DEPTH)/third_party/icu/icu.gyp:icui18n',
'<(DEPTH)/third_party/icu/icu.gyp:icuuc',
+ '<(DEPTH)/ui/base/ui_base.gyp:ui_base',
],
'conditions': [
['OS != "ios"', {
diff --git a/chrome/common/net/BUILD.gn b/chrome/common/net/BUILD.gn
index 143512d..0794d869 100644
--- a/chrome/common/net/BUILD.gn
+++ b/chrome/common/net/BUILD.gn
@@ -26,6 +26,7 @@
"//net",
"//net:net_resources",
"//third_party/icu",
+ "//ui/base/",
]
if (is_ios) {
diff --git a/components/bookmarks/browser/BUILD.gn b/components/bookmarks/browser/BUILD.gn
index 61c2974..18f84bf5 100644
--- a/components/bookmarks/browser/BUILD.gn
+++ b/components/bookmarks/browser/BUILD.gn
@@ -73,5 +73,6 @@
deps = [
":browser",
"//testing/gtest",
+ "//ui/base",
]
}
diff --git a/content/browser/renderer_host/clipboard_message_filter.cc b/content/browser/renderer_host/clipboard_message_filter.cc
index 3ea8071..af7e6167 100644
--- a/content/browser/renderer_host/clipboard_message_filter.cc
+++ b/content/browser/renderer_host/clipboard_message_filter.cc
@@ -7,13 +7,17 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/common/clipboard_messages.h"
#include "content/public/browser/browser_context.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/size.h"
#include "url/gurl.h"
@@ -22,38 +26,17 @@
namespace {
-enum BitmapPolicy {
- kFilterBitmap,
- kAllowBitmap,
-};
-void SanitizeObjectMap(ui::Clipboard::ObjectMap* objects,
- BitmapPolicy bitmap_policy) {
- if (bitmap_policy != kAllowBitmap)
- objects->erase(ui::Clipboard::CBF_SMBITMAP);
-
- ui::Clipboard::ObjectMap::iterator data_it =
- objects->find(ui::Clipboard::CBF_DATA);
- if (data_it != objects->end()) {
- const ui::Clipboard::FormatType& web_custom_format =
- ui::Clipboard::GetWebCustomDataFormatType();
- if (data_it->second.size() != 2 ||
- !web_custom_format.Equals(
- ui::Clipboard::FormatType::Deserialize(std::string(
- &data_it->second[0].front(),
- data_it->second[0].size())))) {
- // CBF_DATA should always have two parameters associated with it, and the
- // associated FormatType should always be web custom data. If not, then
- // data is malformed and we'll ignore it.
- objects->erase(ui::Clipboard::CBF_DATA);
- }
- }
+void ReleaseSharedMemoryPixels(void* addr, void* context) {
+ delete reinterpret_cast<base::SharedMemory*>(context);
}
} // namespace
-
ClipboardMessageFilter::ClipboardMessageFilter()
- : BrowserMessageFilter(ClipboardMsgStart) {}
+ : BrowserMessageFilter(ClipboardMsgStart),
+ clipboard_writer_(
+ new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE)) {
+}
void ClipboardMessageFilter::OverrideThreadForMessage(
const IPC::Message& message, BrowserThread::ID* thread) {
@@ -80,8 +63,6 @@
bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ClipboardMessageFilter, message)
- IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsAsync, OnWriteObjectsAsync)
- IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteObjectsSync, OnWriteObjectsSync)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_GetSequenceNumber, OnGetSequenceNumber)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_IsFormatAvailable, OnIsFormatAvailable)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_Clear, OnClear)
@@ -92,6 +73,14 @@
IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadRTF, OnReadRTF)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ClipboardHostMsg_ReadImage, OnReadImage)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_ReadCustomData, OnReadCustomData)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteText, OnWriteText)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteHTML, OnWriteHTML)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteSmartPasteMarker,
+ OnWriteSmartPasteMarker)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteCustomData, OnWriteCustomData)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteBookmark, OnWriteBookmark)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_WriteImage, OnWriteImage)
+ IPC_MESSAGE_HANDLER(ClipboardHostMsg_CommitWrite, OnCommitWrite);
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(ClipboardHostMsg_FindPboardWriteStringAsync,
OnFindPboardWriteString)
@@ -104,71 +93,6 @@
ClipboardMessageFilter::~ClipboardMessageFilter() {
}
-void ClipboardMessageFilter::OnWriteObjectsSync(
- const ui::Clipboard::ObjectMap& objects,
- base::SharedMemoryHandle bitmap_handle) {
- DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
- << "Bad bitmap handle";
-
- // On Windows, we can't write directly from the IO thread, so we copy the data
- // into a heap allocated map and post a task to the UI thread. On other
- // platforms, to lower the amount of time the renderer has to wait for the
- // sync IPC to complete, we also take a copy and post a task to flush the data
- // to the clipboard later.
- scoped_ptr<ui::Clipboard::ObjectMap> long_living_objects(
- new ui::Clipboard::ObjectMap(objects));
- SanitizeObjectMap(long_living_objects.get(), kAllowBitmap);
- // Splice the shared memory handle into the data. |long_living_objects| now
- // contains a heap-allocated SharedMemory object that references
- // |bitmap_handle|. This reference will keep the shared memory section alive
- // when this IPC returns, and the SharedMemory object will eventually be
- // freed by ui::Clipboard::WriteObjects().
- if (!ui::Clipboard::ReplaceSharedMemHandle(
- long_living_objects.get(), bitmap_handle, PeerHandle()))
- return;
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&ClipboardMessageFilter::WriteObjectsOnUIThread,
- base::Owned(long_living_objects.release())));
-}
-
-// On Windows, the write must be performed on the UI thread because the
-// clipboard object from the IO thread cannot create windows so it cannot be
-// the "owner" of the clipboard's contents. See http://crbug.com/5823.
-// TODO(dcheng): Temporarily a member of ClipboardMessageFilter so it can access
-// ui::Clipboard::WriteObjects().
-void ClipboardMessageFilter::WriteObjectsOnUIThread(
- const ui::Clipboard::ObjectMap* objects) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- static ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
- clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, *objects);
-}
-
-void ClipboardMessageFilter::OnWriteObjectsAsync(
- const ui::Clipboard::ObjectMap& objects) {
- // This async message doesn't support shared-memory based bitmaps; they must
- // be removed otherwise we might dereference a rubbish pointer.
- scoped_ptr<ui::Clipboard::ObjectMap> sanitized_objects(
- new ui::Clipboard::ObjectMap(objects));
- SanitizeObjectMap(sanitized_objects.get(), kFilterBitmap);
-
-#if defined(OS_WIN)
- // We cannot write directly from the IO thread, and cannot service the IPC
- // on the UI thread. We'll copy the relevant data and post a task to preform
- // the write on the UI thread.
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &WriteObjectsOnUIThread, base::Owned(sanitized_objects.release())));
-#else
- GetClipboard()->WriteObjects(
- ui::CLIPBOARD_TYPE_COPY_PASTE, *sanitized_objects.get());
-#endif
-}
-
void ClipboardMessageFilter::OnGetSequenceNumber(ui::ClipboardType type,
uint64* sequence_number) {
*sequence_number = GetClipboard()->GetSequenceNumber(type);
@@ -286,6 +210,91 @@
GetClipboard()->ReadCustomData(clipboard_type, type, result);
}
+void ClipboardMessageFilter::OnWriteText(ui::ClipboardType clipboard_type,
+ const base::string16& text) {
+ clipboard_writer_->WriteText(text);
+}
+
+void ClipboardMessageFilter::OnWriteHTML(ui::ClipboardType clipboard_type,
+ const base::string16& markup,
+ const GURL& url) {
+ clipboard_writer_->WriteHTML(markup, url.spec());
+}
+
+void ClipboardMessageFilter::OnWriteSmartPasteMarker(
+ ui::ClipboardType clipboard_type) {
+ clipboard_writer_->WriteWebSmartPaste();
+}
+
+void ClipboardMessageFilter::OnWriteCustomData(
+ ui::ClipboardType clipboard_type,
+ const std::map<base::string16, base::string16>& data) {
+ Pickle pickle;
+ ui::WriteCustomDataToPickle(data, &pickle);
+ clipboard_writer_->WritePickledData(
+ pickle, ui::Clipboard::GetWebCustomDataFormatType());
+}
+
+void ClipboardMessageFilter::OnWriteBookmark(ui::ClipboardType clipboard_type,
+ const GURL& url,
+ const base::string16& title) {
+ clipboard_writer_->WriteBookmark(title, url.spec());
+}
+
+void ClipboardMessageFilter::OnWriteImage(ui::ClipboardType clipboard_type,
+ const gfx::Size& size,
+ base::SharedMemoryHandle handle) {
+ if (!base::SharedMemory::IsHandleValid(handle)) {
+ return;
+ }
+
+ scoped_ptr<base::SharedMemory> bitmap_buffer(
+#if defined(OS_WIN)
+ new base::SharedMemory(handle, true, PeerHandle()));
+#else
+ new base::SharedMemory(handle, true));
+#endif
+
+ SkBitmap bitmap;
+ // Let Skia do some sanity checking for (no negative widths/heights, no
+ // overflows while calculating bytes per row, etc).
+ if (!bitmap.setInfo(
+ SkImageInfo::MakeN32Premul(size.width(), size.height()))) {
+ return;
+ }
+
+ // Make sure the size is representable as a signed 32-bit int, so
+ // SkBitmap::getSize() won't be truncated.
+ if (!sk_64_isS32(bitmap.computeSize64()))
+ return;
+
+ if (!bitmap_buffer->Map(bitmap.getSize()))
+ return;
+
+ if (!bitmap.installPixels(bitmap.info(), bitmap_buffer->memory(),
+ bitmap.rowBytes(), NULL, &ReleaseSharedMemoryPixels,
+ bitmap_buffer.get()))
+ return;
+
+ // On success, SkBitmap now owns the SharedMemory.
+ ignore_result(bitmap_buffer.release());
+ clipboard_writer_->WriteImage(bitmap);
+}
+
+void ClipboardMessageFilter::OnCommitWrite(ui::ClipboardType clipboard_type) {
+#if defined(OS_WIN)
+ // On non-Windows platforms, all clipboard IPCs are handled on the UI thread.
+ // However, Windows handles the clipboard IPCs on the IO thread to prevent
+ // deadlocks. Clipboard writes must still occur on the UI thread because the
+ // clipboard object from the IO thread cannot create windows so it cannot be
+ // the "owner" of the clipboard's contents. See http://crbug.com/5823.
+ BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
+ clipboard_writer_.release());
+#endif
+ clipboard_writer_.reset(
+ new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE));
+}
+
// static
ui::Clipboard* ClipboardMessageFilter::GetClipboard() {
// We have a static instance of the clipboard service for use by all message
diff --git a/content/browser/renderer_host/clipboard_message_filter.h b/content/browser/renderer_host/clipboard_message_filter.h
index 792bfc5b..3f01e86 100644
--- a/content/browser/renderer_host/clipboard_message_filter.h
+++ b/content/browser/renderer_host/clipboard_message_filter.h
@@ -9,15 +9,23 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/memory/shared_memory.h"
#include "content/common/clipboard_format.h"
+#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
#include "ui/base/clipboard/clipboard.h"
class GURL;
+namespace ui {
+class ScopedClipboardWriter;
+} // namespace ui
+
namespace content {
-class ClipboardMessageFilter : public BrowserMessageFilter {
+class ClipboardMessageFilterTest;
+
+class CONTENT_EXPORT ClipboardMessageFilter : public BrowserMessageFilter {
public:
ClipboardMessageFilter();
@@ -26,12 +34,9 @@
bool OnMessageReceived(const IPC::Message& message) override;
private:
- ~ClipboardMessageFilter() override;
+ friend class ClipboardMessageFilterTest;
- void OnWriteObjectsAsync(const ui::Clipboard::ObjectMap& objects);
- void OnWriteObjectsSync(const ui::Clipboard::ObjectMap& objects,
- base::SharedMemoryHandle bitmap_handle);
- static void WriteObjectsOnUIThread(const ui::Clipboard::ObjectMap* objects);
+ ~ClipboardMessageFilter() override;
void OnGetSequenceNumber(const ui::ClipboardType type,
uint64* sequence_number);
@@ -57,6 +62,22 @@
void OnReadData(const ui::Clipboard::FormatType& format,
std::string* data);
+ void OnWriteText(ui::ClipboardType clipboard_type,
+ const base::string16& text);
+ void OnWriteHTML(ui::ClipboardType clipboard_type,
+ const base::string16& markup,
+ const GURL& url);
+ void OnWriteSmartPasteMarker(ui::ClipboardType clipboard_type);
+ void OnWriteCustomData(ui::ClipboardType clipboard_type,
+ const std::map<base::string16, base::string16>& data);
+ void OnWriteBookmark(ui::ClipboardType clipboard_type,
+ const GURL& url,
+ const base::string16& title);
+ void OnWriteImage(ui::ClipboardType clipboard_type,
+ const gfx::Size& size,
+ base::SharedMemoryHandle handle);
+ void OnCommitWrite(ui::ClipboardType clipboard_type);
+
#if defined(OS_MACOSX)
void OnFindPboardWriteString(const base::string16& text);
#endif
@@ -67,6 +88,8 @@
// thread.
static ui::Clipboard* GetClipboard();
+ scoped_ptr<ui::ScopedClipboardWriter> clipboard_writer_;
+
DISALLOW_COPY_AND_ASSIGN(ClipboardMessageFilter);
};
diff --git a/content/browser/renderer_host/clipboard_message_filter_unittest.cc b/content/browser/renderer_host/clipboard_message_filter_unittest.cc
new file mode 100644
index 0000000..70761b756
--- /dev/null
+++ b/content/browser/renderer_host/clipboard_message_filter_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/clipboard_message_filter.h"
+
+#include <string.h>
+
+#include "base/memory/ref_counted.h"
+#include "base/process/process_handle.h"
+#include "base/run_loop.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/test/test_clipboard.h"
+#include "ui/gfx/size.h"
+
+namespace content {
+
+class ClipboardMessageFilterTest : public ::testing::Test {
+ protected:
+ ClipboardMessageFilterTest()
+ : filter_(new ClipboardMessageFilter),
+ clipboard_(ui::TestClipboard::CreateForCurrentThread()) {
+ filter_->set_peer_pid_for_testing(base::GetCurrentProcId());
+ }
+
+ virtual ~ClipboardMessageFilterTest() override {
+ ui::Clipboard::DestroyClipboardForCurrentThread();
+ }
+
+ scoped_ptr<base::SharedMemory> CreateAndMapReadOnlySharedMemory(size_t size) {
+ scoped_ptr<base::SharedMemory> m = CreateReadOnlySharedMemory(size);
+ if (!m->Map(size))
+ return nullptr;
+ return m;
+ }
+
+ scoped_ptr<base::SharedMemory> CreateReadOnlySharedMemory(size_t size) {
+ scoped_ptr<base::SharedMemory> m(new base::SharedMemory());
+ base::SharedMemoryCreateOptions options;
+ options.size = size;
+ options.share_read_only = true;
+ if (!m->Create(options))
+ return nullptr;
+ return m;
+ }
+
+ void CallWriteImage(const gfx::Size& size,
+ base::SharedMemory* shared_memory) {
+ base::SharedMemoryHandle handle;
+ ASSERT_TRUE(shared_memory->GiveReadOnlyToProcess(
+ base::GetCurrentProcessHandle(), &handle));
+ CallWriteImageDirectly(size, handle);
+ }
+
+ // Prefer to use CallWriteImage() in tests.
+ void CallWriteImageDirectly(const gfx::Size& size,
+ base::SharedMemoryHandle handle) {
+ filter_->OnWriteImage(ui::CLIPBOARD_TYPE_COPY_PASTE, size, handle);
+ }
+
+ void CallCommitWrite() {
+ filter_->OnCommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ ui::Clipboard* clipboard() { return clipboard_; }
+
+ private:
+ const TestBrowserThreadBundle thread_bundle_;
+ const scoped_refptr<ClipboardMessageFilter> filter_;
+ ui::Clipboard* const clipboard_;
+};
+
+// Test that it actually works.
+TEST_F(ClipboardMessageFilterTest, SimpleImage) {
+ static const uint32_t bitmap_data[] = {
+ 0x33333333, 0xdddddddd, 0xeeeeeeee, 0x00000000,
+ 0x88888888, 0x66666666, 0x55555555, 0xbbbbbbbb,
+ 0x44444444, 0xaaaaaaaa, 0x99999999, 0x77777777,
+ 0xffffffff, 0x11111111, 0x22222222, 0xcccccccc,
+ };
+
+ scoped_ptr<base::SharedMemory> shared_memory =
+ CreateAndMapReadOnlySharedMemory(sizeof(bitmap_data));
+ memcpy(shared_memory->memory(), bitmap_data, sizeof(bitmap_data));
+
+ CallWriteImage(gfx::Size(4, 4), shared_memory.get());
+ uint64_t sequence_number =
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ CallCommitWrite();
+
+ EXPECT_NE(sequence_number,
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_FALSE(clipboard()->IsFormatAvailable(
+ ui::Clipboard::GetPlainTextFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_TRUE(clipboard()->IsFormatAvailable(
+ ui::Clipboard::GetBitmapFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE));
+
+ SkBitmap actual = clipboard()->ReadImage(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ SkAutoLockPixels locked(actual);
+ EXPECT_EQ(sizeof(bitmap_data), actual.getSize());
+ EXPECT_EQ(0,
+ memcmp(bitmap_data, actual.getAddr32(0, 0), sizeof(bitmap_data)));
+}
+
+// Test with a size that would overflow a naive 32-bit row bytes calculation.
+TEST_F(ClipboardMessageFilterTest, ImageSizeOverflows32BitRowBytes) {
+ scoped_ptr<base::SharedMemory> shared_memory =
+ CreateReadOnlySharedMemory(0x20000000);
+
+ CallWriteImage(gfx::Size(0x20000000, 1), shared_memory.get());
+ uint64_t sequence_number =
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ CallCommitWrite();
+
+ EXPECT_EQ(sequence_number,
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE));
+}
+
+TEST_F(ClipboardMessageFilterTest, InvalidSharedMemoryHandle) {
+ CallWriteImageDirectly(gfx::Size(5, 5), base::SharedMemory::NULLHandle());
+ uint64_t sequence_number =
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ CallCommitWrite();
+
+ EXPECT_EQ(sequence_number,
+ clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE));
+}
+
+} // namespace content
diff --git a/content/common/clipboard_messages.h b/content/common/clipboard_messages.h
index add55e4..ff02524 100644
--- a/content/common/clipboard_messages.h
+++ b/content/common/clipboard_messages.h
@@ -4,10 +4,12 @@
// Multiply-included message file, so no include guard.
+#include <map>
#include <string>
#include <vector>
#include "base/memory/shared_memory.h"
+#include "base/strings/string16.h"
#include "content/common/clipboard_format.h"
#include "content/public/common/common_param_traits.h"
#include "ipc/ipc_message_macros.h"
@@ -21,15 +23,6 @@
// Clipboard IPC messages sent from the renderer to the browser.
-// This message is used when the object list does not contain a bitmap.
-IPC_MESSAGE_CONTROL1(ClipboardHostMsg_WriteObjectsAsync,
- ui::Clipboard::ObjectMap /* objects */)
-// This message is used when the object list contains a bitmap.
-// It is synchronized so that the renderer knows when it is safe to
-// free the shared memory used to transfer the bitmap.
-IPC_SYNC_MESSAGE_CONTROL2_0(ClipboardHostMsg_WriteObjectsSync,
- ui::Clipboard::ObjectMap /* objects */,
- base::SharedMemoryHandle /* bitmap handle */)
IPC_SYNC_MESSAGE_CONTROL1_1(ClipboardHostMsg_GetSequenceNumber,
ui::ClipboardType /* type */,
uint64 /* result */)
@@ -64,6 +57,35 @@
base::string16 /* type */,
base::string16 /* result */)
+// Writing to the clipboard via IPC is a two-phase operation. First, the sender
+// sends the different types of data it'd like to write to the receiver. Then,
+// it sends a commit message to commit the data to the system clipboard.
+IPC_MESSAGE_CONTROL2(ClipboardHostMsg_WriteText,
+ ui::ClipboardType /* type */,
+ base::string16 /* text */)
+IPC_MESSAGE_CONTROL3(ClipboardHostMsg_WriteHTML,
+ ui::ClipboardType /* type */,
+ base::string16 /* markup */,
+ GURL /* url */)
+IPC_MESSAGE_CONTROL1(ClipboardHostMsg_WriteSmartPasteMarker,
+ ui::ClipboardType /* type */);
+// Custom data consists of arbitrary MIME types an untrusted sender wants to
+// write to the clipboard. Note that exposing a general interface to do this is
+// dangerous--an untrusted sender could cause a DoS or code execution.
+typedef std::map<base::string16, base::string16> CustomDataMap;
+IPC_MESSAGE_CONTROL2(ClipboardHostMsg_WriteCustomData,
+ ui::ClipboardType /* type */,
+ CustomDataMap /* custom data */)
+IPC_MESSAGE_CONTROL3(ClipboardHostMsg_WriteBookmark,
+ ui::ClipboardType /* type */,
+ GURL /* url */,
+ base::string16 /* title */)
+IPC_SYNC_MESSAGE_CONTROL3_0(ClipboardHostMsg_WriteImage,
+ ui::ClipboardType /* type */,
+ gfx::Size /* size */,
+ base::SharedMemoryHandle /* bitmap handle */)
+IPC_MESSAGE_CONTROL1(ClipboardHostMsg_CommitWrite, ui::ClipboardType /* type */)
+
#if defined(OS_MACOSX)
IPC_MESSAGE_CONTROL1(ClipboardHostMsg_FindPboardWriteStringAsync,
base::string16 /* text */)
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 6518e02..18a6fca 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -332,8 +332,8 @@
'renderer/render_widget_fullscreen.h',
'renderer/renderer_blink_platform_impl.cc',
'renderer/renderer_blink_platform_impl.h',
- 'renderer/renderer_clipboard_client.cc',
- 'renderer/renderer_clipboard_client.h',
+ 'renderer/renderer_clipboard_delegate.cc',
+ 'renderer/renderer_clipboard_delegate.h',
'renderer/renderer_main.cc',
'renderer/renderer_main_platform_delegate.h',
'renderer/renderer_main_platform_delegate_android.cc',
@@ -371,8 +371,6 @@
'renderer/screen_orientation/screen_orientation_dispatcher.h',
'renderer/screen_orientation/screen_orientation_observer.cc',
'renderer/screen_orientation/screen_orientation_observer.h',
- 'renderer/scoped_clipboard_writer_glue.cc',
- 'renderer/scoped_clipboard_writer_glue.h',
'renderer/service_worker/embedded_worker_context_client.cc',
'renderer/service_worker/embedded_worker_context_client.h',
'renderer/service_worker/embedded_worker_context_message_filter.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 906493f..16459962 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -571,6 +571,7 @@
'browser/quota/quota_temporary_storage_evictor_unittest.cc',
'browser/quota/storage_monitor_unittest.cc',
'browser/quota/usage_tracker_unittest.cc',
+ 'browser/renderer_host/clipboard_message_filter_unittest.cc',
'browser/renderer_host/input/gesture_event_queue_unittest.cc',
'browser/renderer_host/input/gesture_text_selector_unittest.cc',
'browser/renderer_host/input/input_router_impl_unittest.cc',
diff --git a/content/renderer/clipboard_client.h b/content/renderer/clipboard_client.h
deleted file mode 100644
index 7f1b2dcf..0000000
--- a/content/renderer/clipboard_client.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_CLIPBOARD_CLIENT_H_
-#define CONTENT_RENDERER_CLIPBOARD_CLIENT_H_
-
-#include "content/common/clipboard_format.h"
-#include "ui/base/clipboard/clipboard.h"
-
-class GURL;
-
-namespace content {
-
-// Interface for the content embedder to implement to support clipboard.
-class ClipboardClient {
- public:
- class WriteContext {
- public:
- virtual ~WriteContext() { }
-
- // Writes bitmap data into the context, updating the ObjectMap.
- virtual void WriteBitmapFromPixels(ui::Clipboard::ObjectMap* objects,
- const void* pixels,
- const gfx::Size& size) = 0;
-
- // Flushes all gathered data.
- virtual void Flush(const ui::Clipboard::ObjectMap& objects) = 0;
- };
-
- virtual ~ClipboardClient() { }
-
- // Get a clipboard that can be used to construct a ScopedClipboardWriterGlue.
- virtual ui::Clipboard* GetClipboard() = 0;
-
- // Get a sequence number which uniquely identifies clipboard state.
- virtual uint64 GetSequenceNumber(ui::ClipboardType type) = 0;
-
- // Tests whether the clipboard contains a certain format
- virtual bool IsFormatAvailable(ClipboardFormat format,
- ui::ClipboardType type) = 0;
-
- // Clear the contents of the clipboard.
- virtual void Clear(ui::ClipboardType type) = 0;
-
- // Reads the available types from the clipboard, if available.
- virtual void ReadAvailableTypes(ui::ClipboardType type,
- std::vector<base::string16>* types,
- bool* contains_filenames) = 0;
-
- // Reads text from the clipboard, trying UNICODE first, then falling back to
- // ASCII.
- virtual void ReadText(ui::ClipboardType type,
- base::string16* result) = 0;
-
- // Reads HTML from the clipboard, if available.
- virtual void ReadHTML(ui::ClipboardType type,
- base::string16* markup,
- GURL* url,
- uint32* fragment_start,
- uint32* fragment_end) = 0;
-
- // Reads RTF from the clipboard, if available.
- virtual void ReadRTF(ui::ClipboardType type, std::string* result) = 0;
-
- // Reads and image from the clipboard, if available.
- virtual void ReadImage(ui::ClipboardType type, std::string* data) = 0;
-
- // Reads a custom data type from the clipboard, if available.
- virtual void ReadCustomData(ui::ClipboardType clipboard_type,
- const base::string16& type,
- base::string16* data) = 0;
-
- // Creates a context to write clipboard data. May return NULL.
- virtual WriteContext* CreateWriteContext() = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_CLIPBOARD_CLIENT_H_
-
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 29a519d3..9ff5b4f 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -48,7 +48,7 @@
#include "content/renderer/media/renderer_webaudiodevice_impl.h"
#include "content/renderer/media/renderer_webmidiaccessor_impl.h"
#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/renderer_clipboard_client.h"
+#include "content/renderer/renderer_clipboard_delegate.h"
#include "content/renderer/scheduler/renderer_scheduler.h"
#include "content/renderer/scheduler/web_scheduler_impl.h"
#include "content/renderer/screen_orientation/screen_orientation_observer.h"
@@ -231,8 +231,8 @@
RendererScheduler* renderer_scheduler)
: BlinkPlatformImpl(renderer_scheduler->DefaultTaskRunner()),
web_scheduler_(new WebSchedulerImpl(renderer_scheduler)),
- clipboard_client_(new RendererClipboardClient),
- clipboard_(new WebClipboardImpl(clipboard_client_.get())),
+ clipboard_delegate_(new RendererClipboardDelegate),
+ clipboard_(new WebClipboardImpl(clipboard_delegate_.get())),
mime_registry_(new RendererBlinkPlatformImpl::MimeRegistry),
sudden_termination_disables_(0),
plugin_refresh_allowed_(true),
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 493bec7..cfa25123 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -42,7 +42,7 @@
class DeviceOrientationEventPump;
class PlatformEventObserverBase;
class QuotaMessageFilter;
-class RendererClipboardClient;
+class RendererClipboardDelegate;
class RendererScheduler;
class RenderView;
class ThreadSafeSender;
@@ -206,7 +206,7 @@
scoped_ptr<WebSchedulerImpl> web_scheduler_;
- scoped_ptr<RendererClipboardClient> clipboard_client_;
+ scoped_ptr<RendererClipboardDelegate> clipboard_delegate_;
scoped_ptr<WebClipboardImpl> clipboard_;
class FileUtilities;
diff --git a/content/renderer/renderer_clipboard_client.cc b/content/renderer/renderer_clipboard_client.cc
deleted file mode 100644
index 1e2953e..0000000
--- a/content/renderer/renderer_clipboard_client.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file provides the embedder's side of the Clipboard interface.
-
-#include "content/renderer/renderer_clipboard_client.h"
-
-#include "base/memory/shared_memory.h"
-#include "base/numerics/safe_math.h"
-#include "base/strings/string16.h"
-#include "content/common/clipboard_messages.h"
-#include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/scoped_clipboard_writer_glue.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/gfx/size.h"
-
-namespace content {
-
-namespace {
-
-class RendererClipboardWriteContext : public ClipboardClient::WriteContext {
- public:
- RendererClipboardWriteContext();
- ~RendererClipboardWriteContext() override;
- void WriteBitmapFromPixels(ui::Clipboard::ObjectMap* objects,
- const void* pixels,
- const gfx::Size& size) override;
- void Flush(const ui::Clipboard::ObjectMap& objects) override;
-
- private:
- scoped_ptr<base::SharedMemory> shared_buf_;
- DISALLOW_COPY_AND_ASSIGN(RendererClipboardWriteContext);
-};
-
-RendererClipboardWriteContext::RendererClipboardWriteContext() {
-}
-
-RendererClipboardWriteContext::~RendererClipboardWriteContext() {
-}
-
-// This definition of WriteBitmapFromPixels uses shared memory to communicate
-// across processes.
-void RendererClipboardWriteContext::WriteBitmapFromPixels(
- ui::Clipboard::ObjectMap* objects,
- const void* pixels,
- const gfx::Size& size) {
- // Do not try to write a bitmap more than once
- if (shared_buf_)
- return;
-
- base::CheckedNumeric<uint32> checked_buf_size = 4;
- checked_buf_size *= size.width();
- checked_buf_size *= size.height();
- if (!checked_buf_size.IsValid())
- return;
-
- uint32 buf_size = checked_buf_size.ValueOrDie();
-
- // Allocate a shared memory buffer to hold the bitmap bits.
- shared_buf_.reset(ChildThread::current()->AllocateSharedMemory(buf_size));
- if (!shared_buf_)
- return;
-
- // Copy the bits into shared memory
- DCHECK(shared_buf_->memory());
- memcpy(shared_buf_->memory(), pixels, buf_size);
- shared_buf_->Unmap();
-
- ui::Clipboard::ObjectMapParam size_param;
- const char* size_data = reinterpret_cast<const char*>(&size);
- for (size_t i = 0; i < sizeof(gfx::Size); ++i)
- size_param.push_back(size_data[i]);
-
- ui::Clipboard::ObjectMapParams params;
-
- // The first parameter is replaced on the receiving end with a pointer to
- // a shared memory object containing the bitmap. We reserve space for it here.
- ui::Clipboard::ObjectMapParam place_holder_param;
- params.push_back(place_holder_param);
- params.push_back(size_param);
- (*objects)[ui::Clipboard::CBF_SMBITMAP] = params;
-}
-
-// Flushes the objects to the clipboard with an IPC.
-void RendererClipboardWriteContext::Flush(
- const ui::Clipboard::ObjectMap& objects) {
- if (shared_buf_) {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_WriteObjectsSync(objects, shared_buf_->handle()));
- } else {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_WriteObjectsAsync(objects));
- }
-}
-
-} // anonymous namespace
-
-RendererClipboardClient::RendererClipboardClient() {
-}
-
-RendererClipboardClient::~RendererClipboardClient() {
-}
-
-ui::Clipboard* RendererClipboardClient::GetClipboard() {
- return NULL;
-}
-
-uint64 RendererClipboardClient::GetSequenceNumber(ui::ClipboardType type) {
- uint64 sequence_number = 0;
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_GetSequenceNumber(type, &sequence_number));
- return sequence_number;
-}
-
-bool RendererClipboardClient::IsFormatAvailable(content::ClipboardFormat format,
- ui::ClipboardType type) {
- bool result = false;
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_IsFormatAvailable(format, type, &result));
- return result;
-}
-
-void RendererClipboardClient::Clear(ui::ClipboardType type) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_Clear(type));
-}
-
-void RendererClipboardClient::ReadAvailableTypes(
- ui::ClipboardType type,
- std::vector<base::string16>* types,
- bool* contains_filenames) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadAvailableTypes(
- type, types, contains_filenames));
-}
-
-void RendererClipboardClient::ReadText(ui::ClipboardType type,
- base::string16* result) {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_ReadText(type, result));
-}
-
-void RendererClipboardClient::ReadHTML(ui::ClipboardType type,
- base::string16* markup,
- GURL* url, uint32* fragment_start,
- uint32* fragment_end) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadHTML(
- type, markup, url, fragment_start, fragment_end));
-}
-
-void RendererClipboardClient::ReadRTF(ui::ClipboardType type,
- std::string* result) {
- RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadRTF(type, result));
-}
-
-void RendererClipboardClient::ReadImage(ui::ClipboardType type,
- std::string* data) {
- base::SharedMemoryHandle image_handle;
- uint32 image_size = 0;
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_ReadImage(type, &image_handle, &image_size));
- if (base::SharedMemory::IsHandleValid(image_handle)) {
- base::SharedMemory buffer(image_handle, true);
- buffer.Map(image_size);
- data->append(static_cast<char*>(buffer.memory()), image_size);
- }
-}
-
-void RendererClipboardClient::ReadCustomData(ui::ClipboardType clipboard_type,
- const base::string16& type,
- base::string16* data) {
- RenderThreadImpl::current()->Send(
- new ClipboardHostMsg_ReadCustomData(clipboard_type, type, data));
-}
-
-ClipboardClient::WriteContext* RendererClipboardClient::CreateWriteContext() {
- return new RendererClipboardWriteContext;
-}
-
-} // namespace content
diff --git a/content/renderer/renderer_clipboard_client.h b/content/renderer/renderer_clipboard_client.h
deleted file mode 100644
index de9e9c1..0000000
--- a/content/renderer/renderer_clipboard_client.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_RENDERER_CLIPBOARD_CLIENT_H_
-#define CONTENT_RENDERER_RENDERER_CLIPBOARD_CLIENT_H_
-
-#include "base/compiler_specific.h"
-#include "content/renderer/clipboard_client.h"
-
-namespace content {
-
-// An implementation of ClipboardClient that gets and sends data over IPC.
-class RendererClipboardClient : public ClipboardClient {
- public:
- RendererClipboardClient();
- ~RendererClipboardClient() override;
-
- ui::Clipboard* GetClipboard() override;
- uint64 GetSequenceNumber(ui::ClipboardType type) override;
- bool IsFormatAvailable(ClipboardFormat format,
- ui::ClipboardType type) override;
- void Clear(ui::ClipboardType type) override;
- void ReadAvailableTypes(ui::ClipboardType type,
- std::vector<base::string16>* types,
- bool* contains_filenames) override;
- void ReadText(ui::ClipboardType type, base::string16* result) override;
- void ReadHTML(ui::ClipboardType type,
- base::string16* markup,
- GURL* url,
- uint32* fragment_start,
- uint32* fragment_end) override;
- void ReadRTF(ui::ClipboardType type, std::string* result) override;
- void ReadImage(ui::ClipboardType type, std::string* data) override;
- void ReadCustomData(ui::ClipboardType clipboard_type,
- const base::string16& type,
- base::string16* data) override;
- WriteContext* CreateWriteContext() override;
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_RENDERER_CLIPBOARD_CLIENT_H_
diff --git a/content/renderer/renderer_clipboard_delegate.cc b/content/renderer/renderer_clipboard_delegate.cc
new file mode 100644
index 0000000..5033220
--- /dev/null
+++ b/content/renderer/renderer_clipboard_delegate.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides the embedder's side of the Clipboard interface.
+
+#include "content/renderer/renderer_clipboard_delegate.h"
+
+#include "base/memory/shared_memory.h"
+#include "base/numerics/safe_math.h"
+#include "content/common/clipboard_messages.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/renderer/render_thread_impl.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/gfx/size.h"
+
+namespace content {
+
+RendererClipboardDelegate::RendererClipboardDelegate() {
+}
+
+uint64 RendererClipboardDelegate::GetSequenceNumber(ui::ClipboardType type) {
+ uint64 sequence_number = 0;
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_GetSequenceNumber(type, &sequence_number));
+ return sequence_number;
+}
+
+bool RendererClipboardDelegate::IsFormatAvailable(
+ content::ClipboardFormat format,
+ ui::ClipboardType type) {
+ bool result = false;
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_IsFormatAvailable(format, type, &result));
+ return result;
+}
+
+void RendererClipboardDelegate::Clear(ui::ClipboardType type) {
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_Clear(type));
+}
+
+void RendererClipboardDelegate::ReadAvailableTypes(
+ ui::ClipboardType type,
+ std::vector<base::string16>* types,
+ bool* contains_filenames) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadAvailableTypes(type, types, contains_filenames));
+}
+
+void RendererClipboardDelegate::ReadText(ui::ClipboardType type,
+ base::string16* result) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadText(type, result));
+}
+
+void RendererClipboardDelegate::ReadHTML(ui::ClipboardType type,
+ base::string16* markup,
+ GURL* url,
+ uint32* fragment_start,
+ uint32* fragment_end) {
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadHTML(
+ type, markup, url, fragment_start, fragment_end));
+}
+
+void RendererClipboardDelegate::ReadRTF(ui::ClipboardType type,
+ std::string* result) {
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_ReadRTF(type, result));
+}
+
+void RendererClipboardDelegate::ReadImage(ui::ClipboardType type,
+ std::string* data) {
+ base::SharedMemoryHandle image_handle;
+ uint32 image_size = 0;
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadImage(type, &image_handle, &image_size));
+ if (base::SharedMemory::IsHandleValid(image_handle)) {
+ base::SharedMemory buffer(image_handle, true);
+ buffer.Map(image_size);
+ data->append(static_cast<char*>(buffer.memory()), image_size);
+ }
+}
+
+void RendererClipboardDelegate::ReadCustomData(ui::ClipboardType clipboard_type,
+ const base::string16& type,
+ base::string16* data) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_ReadCustomData(clipboard_type, type, data));
+}
+
+void RendererClipboardDelegate::WriteText(ui::ClipboardType clipboard_type,
+ const base::string16& text) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteText(clipboard_type, text));
+}
+
+void RendererClipboardDelegate::WriteHTML(ui::ClipboardType clipboard_type,
+ const base::string16& markup,
+ const GURL& url) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteHTML(clipboard_type, markup, url));
+}
+
+void RendererClipboardDelegate::WriteSmartPasteMarker(
+ ui::ClipboardType clipboard_type) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteSmartPasteMarker(clipboard_type));
+}
+
+void RendererClipboardDelegate::WriteCustomData(
+ ui::ClipboardType clipboard_type,
+ const std::map<base::string16, base::string16>& data) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteCustomData(clipboard_type, data));
+}
+
+void RendererClipboardDelegate::WriteBookmark(ui::ClipboardType clipboard_type,
+ const GURL& url,
+ const base::string16& title) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_WriteBookmark(clipboard_type, url, title));
+}
+
+bool RendererClipboardDelegate::WriteImage(ui::ClipboardType clipboard_type,
+ const SkBitmap& bitmap) {
+ // Only 32-bit bitmaps are supported.
+ DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
+ const gfx::Size size(bitmap.width(), bitmap.height());
+ scoped_ptr<base::SharedMemory> shared_buf;
+ {
+ SkAutoLockPixels locked(bitmap);
+ void* pixels = bitmap.getPixels();
+ // TODO(piman): this should not be NULL, but it is. crbug.com/369621
+ if (!pixels)
+ return false;
+
+ base::CheckedNumeric<uint32> checked_buf_size = 4;
+ checked_buf_size *= size.width();
+ checked_buf_size *= size.height();
+ if (!checked_buf_size.IsValid())
+ return false;
+
+ // Allocate a shared memory buffer to hold the bitmap bits.
+ uint32 buf_size = checked_buf_size.ValueOrDie();
+ shared_buf.reset(ChildThread::current()->AllocateSharedMemory(buf_size));
+ if (!shared_buf)
+ return false;
+ // Copy the bits into shared memory
+ DCHECK(shared_buf->memory());
+ memcpy(shared_buf->memory(), pixels, buf_size);
+ shared_buf->Unmap();
+ }
+
+ RenderThreadImpl::current()->Send(new ClipboardHostMsg_WriteImage(
+ clipboard_type, size, shared_buf->handle()));
+ return true;
+}
+
+void RendererClipboardDelegate::CommitWrite(ui::ClipboardType clipboard_type) {
+ RenderThreadImpl::current()->Send(
+ new ClipboardHostMsg_CommitWrite(clipboard_type));
+}
+
+} // namespace content
diff --git a/content/renderer/renderer_clipboard_delegate.h b/content/renderer/renderer_clipboard_delegate.h
new file mode 100644
index 0000000..ef8e034
--- /dev/null
+++ b/content/renderer/renderer_clipboard_delegate.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_RENDERER_CLIPBOARD_DELEGATE_H_
+#define CONTENT_RENDERER_RENDERER_CLIPBOARD_DELEGATE_H_
+
+#include <stdint.h>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "content/common/clipboard_format.h"
+#include "ui/base/clipboard/clipboard_types.h"
+
+class GURL;
+class SkBitmap;
+
+namespace content {
+
+// Renderer interface to read/write from the clipboard over IPC.
+class RendererClipboardDelegate {
+ public:
+ RendererClipboardDelegate();
+
+ uint64 GetSequenceNumber(ui::ClipboardType type);
+ bool IsFormatAvailable(ClipboardFormat format, ui::ClipboardType type);
+ void Clear(ui::ClipboardType type);
+ void ReadAvailableTypes(ui::ClipboardType type,
+ std::vector<base::string16>* types,
+ bool* contains_filenames);
+ void ReadText(ui::ClipboardType type, base::string16* result);
+ void ReadHTML(ui::ClipboardType type,
+ base::string16* markup,
+ GURL* url,
+ uint32* fragment_start,
+ uint32* fragment_end);
+ void ReadRTF(ui::ClipboardType type, std::string* result);
+ void ReadImage(ui::ClipboardType type, std::string* data);
+ void ReadCustomData(ui::ClipboardType clipboard_type,
+ const base::string16& type,
+ base::string16* data);
+
+ void WriteText(ui::ClipboardType type, const base::string16& text);
+ void WriteHTML(ui::ClipboardType type,
+ const base::string16& markup,
+ const GURL& url);
+ void WriteSmartPasteMarker(ui::ClipboardType type);
+ void WriteCustomData(ui::ClipboardType type,
+ const std::map<base::string16, base::string16>& data);
+ void WriteBookmark(ui::ClipboardType type,
+ const GURL& url,
+ const base::string16& title);
+ bool WriteImage(ui::ClipboardType type, const SkBitmap& bitmap);
+ void CommitWrite(ui::ClipboardType type);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RendererClipboardDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_RENDERER_CLIPBOARD_DELEGATE_H_
diff --git a/content/renderer/scoped_clipboard_writer_glue.cc b/content/renderer/scoped_clipboard_writer_glue.cc
deleted file mode 100644
index 7147134..0000000
--- a/content/renderer/scoped_clipboard_writer_glue.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/scoped_clipboard_writer_glue.h"
-#include "base/logging.h"
-
-namespace content {
-
-ScopedClipboardWriterGlue::ScopedClipboardWriterGlue(ClipboardClient* client)
- : ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE),
- context_(client->CreateWriteContext()) {
- DCHECK(context_);
-}
-
-ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() {
- if (!objects_.empty() && context_) {
- context_->Flush(objects_);
- // TODO(dcheng): Temporary hack while the clipboard IPCs are cleaned up.
- // This prevents the base class destructor from also trying to (probably
- // unsuccessfully) flush things to the clipboard.
- objects_.clear();
- }
-}
-
-void ScopedClipboardWriterGlue::WriteBitmapFromPixels(const void* pixels,
- const gfx::Size& size) {
- if (context_) {
- context_->WriteBitmapFromPixels(&objects_, pixels, size);
- } else {
- NOTREACHED();
- }
-}
-
-} // namespace content
-
diff --git a/content/renderer/scoped_clipboard_writer_glue.h b/content/renderer/scoped_clipboard_writer_glue.h
deleted file mode 100644
index d64ae63..0000000
--- a/content/renderer/scoped_clipboard_writer_glue.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SCOPED_CLIPBOARD_WRITER_GLUE_H_
-#define CONTENT_RENDERER_SCOPED_CLIPBOARD_WRITER_GLUE_H_
-
-#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/renderer/clipboard_client.h"
-
-namespace content {
-
-class ScopedClipboardWriterGlue
- : public ui::ScopedClipboardWriter {
- public:
- explicit ScopedClipboardWriterGlue(ClipboardClient* client);
-
- virtual ~ScopedClipboardWriterGlue();
-
- void WriteBitmapFromPixels(const void* pixels, const gfx::Size& size);
-
- private:
- scoped_ptr<ClipboardClient::WriteContext> context_;
- DISALLOW_COPY_AND_ASSIGN(ScopedClipboardWriterGlue);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_SCOPED_CLIPBOARD_WRITER_GLUE_H_
diff --git a/content/renderer/webclipboard_impl.cc b/content/renderer/webclipboard_impl.cc
index e248c517..19f2362 100644
--- a/content/renderer/webclipboard_impl.cc
+++ b/content/renderer/webclipboard_impl.cc
@@ -5,14 +5,13 @@
#include "content/renderer/webclipboard_impl.h"
#include "base/logging.h"
-#include "base/pickle.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/common/clipboard_format.h"
#include "content/public/common/drop_data.h"
#include "content/renderer/clipboard_utils.h"
#include "content/renderer/drop_data_builder.h"
-#include "content/renderer/scoped_clipboard_writer_glue.h"
+#include "content/renderer/renderer_clipboard_delegate.h"
#include "third_party/WebKit/public/platform/WebData.h"
#include "third_party/WebKit/public/platform/WebDragData.h"
#include "third_party/WebKit/public/platform/WebImage.h"
@@ -20,9 +19,6 @@
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebVector.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/custom_data_helper.h"
#include "url/gurl.h"
using blink::WebClipboard;
@@ -35,8 +31,9 @@
namespace content {
-WebClipboardImpl::WebClipboardImpl(ClipboardClient* client)
- : client_(client) {
+WebClipboardImpl::WebClipboardImpl(RendererClipboardDelegate* delegate)
+ : delegate_(delegate) {
+ DCHECK(delegate);
}
WebClipboardImpl::~WebClipboardImpl() {
@@ -47,7 +44,7 @@
if (!ConvertBufferType(buffer, &clipboard_type))
return 0;
- return client_->GetSequenceNumber(clipboard_type);
+ return delegate_->GetSequenceNumber(clipboard_type);
}
bool WebClipboardImpl::isFormatAvailable(Format format, Buffer buffer) {
@@ -58,16 +55,17 @@
switch (format) {
case FormatPlainText:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_PLAINTEXT,
- clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_PLAINTEXT,
+ clipboard_type);
case FormatHTML:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_HTML, clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_HTML,
+ clipboard_type);
case FormatSmartPaste:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_SMART_PASTE,
- clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_SMART_PASTE,
+ clipboard_type);
case FormatBookmark:
- return client_->IsFormatAvailable(CLIPBOARD_FORMAT_BOOKMARK,
- clipboard_type);
+ return delegate_->IsFormatAvailable(CLIPBOARD_FORMAT_BOOKMARK,
+ clipboard_type);
default:
NOTREACHED();
}
@@ -80,7 +78,7 @@
ui::ClipboardType clipboard_type;
std::vector<base::string16> types;
if (ConvertBufferType(buffer, &clipboard_type)) {
- client_->ReadAvailableTypes(clipboard_type, &types, contains_filenames);
+ delegate_->ReadAvailableTypes(clipboard_type, &types, contains_filenames);
}
return types;
}
@@ -91,7 +89,7 @@
return WebString();
base::string16 text;
- client_->ReadText(clipboard_type, &text);
+ delegate_->ReadText(clipboard_type, &text);
return text;
}
@@ -104,9 +102,9 @@
base::string16 html_stdstr;
GURL gurl;
- client_->ReadHTML(clipboard_type, &html_stdstr, &gurl,
- static_cast<uint32*>(fragment_start),
- static_cast<uint32*>(fragment_end));
+ delegate_->ReadHTML(clipboard_type, &html_stdstr, &gurl,
+ static_cast<uint32*>(fragment_start),
+ static_cast<uint32*>(fragment_end));
*source_url = gurl;
return html_stdstr;
}
@@ -117,7 +115,7 @@
return WebData();
std::string png_data;
- client_->ReadImage(clipboard_type, &png_data);
+ delegate_->ReadImage(clipboard_type, &png_data);
return WebData(png_data);
}
@@ -128,46 +126,36 @@
return WebString();
base::string16 data;
- client_->ReadCustomData(clipboard_type, type, &data);
+ delegate_->ReadCustomData(clipboard_type, type, &data);
return data;
}
void WebClipboardImpl::writePlainText(const WebString& plain_text) {
- ScopedClipboardWriterGlue scw(client_);
- scw.WriteText(plain_text);
+ delegate_->WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE, plain_text);
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
void WebClipboardImpl::writeHTML(
const WebString& html_text, const WebURL& source_url,
const WebString& plain_text, bool write_smart_paste) {
- ScopedClipboardWriterGlue scw(client_);
- scw.WriteHTML(html_text, source_url.spec());
- scw.WriteText(plain_text);
+ delegate_->WriteHTML(ui::CLIPBOARD_TYPE_COPY_PASTE, html_text, source_url);
+ delegate_->WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE, plain_text);
if (write_smart_paste)
- scw.WriteWebSmartPaste();
+ delegate_->WriteSmartPasteMarker(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
void WebClipboardImpl::writeImage(const WebImage& image,
const WebURL& url,
const WebString& title) {
- ScopedClipboardWriterGlue scw(client_);
-
- if (!image.isNull()) {
- const SkBitmap& bitmap = image.getSkBitmap();
- // WriteBitmapFromPixels expects 32-bit data.
- DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
-
- SkAutoLockPixels locked(bitmap);
- void *pixels = bitmap.getPixels();
- // TODO(piman): this should not be NULL, but it is. crbug.com/369621
- if (!pixels)
- return;
- scw.WriteBitmapFromPixels(pixels, image.size());
- }
+ DCHECK(!image.isNull());
+ const SkBitmap& bitmap = image.getSkBitmap();
+ if (!delegate_->WriteImage(ui::CLIPBOARD_TYPE_COPY_PASTE, bitmap))
+ return;
if (!url.isEmpty()) {
- scw.WriteBookmark(title, url.spec());
+ delegate_->WriteBookmark(ui::CLIPBOARD_TYPE_COPY_PASTE, url, title);
#if !defined(OS_MACOSX)
// When writing the image, we also write the image markup so that pasting
// into rich text editors, such as Gmail, reveals the image. We also don't
@@ -176,31 +164,30 @@
// We also don't want to write HTML on a Mac, since Mail.app prefers to use
// the image markup over attaching the actual image. See
// http://crbug.com/33016 for details.
- scw.WriteHTML(base::UTF8ToUTF16(URLToImageMarkup(url, title)),
- std::string());
+ delegate_->WriteHTML(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ base::UTF8ToUTF16(URLToImageMarkup(url, title)),
+ GURL());
#endif
}
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
void WebClipboardImpl::writeDataObject(const WebDragData& data) {
- ScopedClipboardWriterGlue scw(client_);
-
const DropData& data_object = DropDataBuilder::Build(data);
// TODO(dcheng): Properly support text/uri-list here.
+ // Avoid calling the WriteFoo functions if there is no data associated with a
+ // type. This prevents stomping on clipboard contents that might have been
+ // written by extension functions such as chrome.bookmarkManagerPrivate.copy.
if (!data_object.text.is_null())
- scw.WriteText(data_object.text.string());
+ delegate_->WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ data_object.text.string());
if (!data_object.html.is_null())
- scw.WriteHTML(data_object.html.string(), std::string());
- // If there is no custom data, avoid calling WritePickledData. This ensures
- // that ScopedClipboardWriterGlue's dtor remains a no-op if the page didn't
- // modify the DataTransfer object, which is important to avoid stomping on
- // any clipboard contents written by extension functions such as
- // chrome.bookmarkManagerPrivate.copy.
- if (!data_object.custom_data.empty()) {
- Pickle pickle;
- ui::WriteCustomDataToPickle(data_object.custom_data, &pickle);
- scw.WritePickledData(pickle, ui::Clipboard::GetWebCustomDataFormatType());
- }
+ delegate_->WriteHTML(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ data_object.html.string(), GURL());
+ if (!data_object.custom_data.empty())
+ delegate_->WriteCustomData(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ data_object.custom_data);
+ delegate_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
}
bool WebClipboardImpl::ConvertBufferType(Buffer buffer,
diff --git a/content/renderer/webclipboard_impl.h b/content/renderer/webclipboard_impl.h
index 477f53b0..9288546 100644
--- a/content/renderer/webclipboard_impl.h
+++ b/content/renderer/webclipboard_impl.h
@@ -6,18 +6,17 @@
#define CONTENT_RENDERER_WEBCLIPBOARD_IMPL_H_
#include "base/compiler_specific.h"
-
#include "third_party/WebKit/public/platform/WebClipboard.h"
#include "ui/base/clipboard/clipboard.h"
#include <string>
namespace content {
-class ClipboardClient;
+class RendererClipboardDelegate;
class WebClipboardImpl : public blink::WebClipboard {
public:
- explicit WebClipboardImpl(ClipboardClient* client);
+ explicit WebClipboardImpl(RendererClipboardDelegate* delegate);
virtual ~WebClipboardImpl();
@@ -49,7 +48,7 @@
private:
bool ConvertBufferType(Buffer, ui::ClipboardType*);
- ClipboardClient* client_;
+ RendererClipboardDelegate* const delegate_;
};
} // namespace content
diff --git a/ui/base/clipboard/clipboard.cc b/ui/base/clipboard/clipboard.cc
index 0bd542d..aedc54b2 100644
--- a/ui/base/clipboard/clipboard.cc
+++ b/ui/base/clipboard/clipboard.cc
@@ -14,27 +14,6 @@
namespace ui {
-namespace {
-
-// Valides a shared bitmap on the clipboard.
-// Returns true if the clipboard data makes sense and it's safe to access the
-// bitmap.
-bool ValidateAndMapSharedBitmap(size_t bitmap_bytes,
- base::SharedMemory* bitmap_data) {
- using base::SharedMemory;
-
- if (!bitmap_data || !SharedMemory::IsHandleValid(bitmap_data->handle()))
- return false;
-
- if (!bitmap_data->Map(bitmap_bytes)) {
- PLOG(ERROR) << "Failed to map bitmap memory";
- return false;
- }
- return true;
-}
-
-} // namespace
-
base::LazyInstance<Clipboard::AllowedThreadsVector>
Clipboard::allowed_threads_ = LAZY_INSTANCE_INITIALIZER;
base::LazyInstance<Clipboard::ClipboardMap> Clipboard::clipboard_map_ =
@@ -95,13 +74,12 @@
}
void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) {
- // All types apart from CBF_WEBKIT need at least 1 non-empty param.
- if (type != CBF_WEBKIT && (params.empty() || params[0].empty()))
- return;
- // Some other types need a non-empty 2nd param.
- if ((type == CBF_BOOKMARK || type == CBF_SMBITMAP || type == CBF_DATA) &&
- (params.size() != 2 || params[1].empty()))
- return;
+ // Ignore writes with empty parameters.
+ for (const auto& param : params) {
+ if (param.empty())
+ return;
+ }
+
switch (type) {
case CBF_TEXT:
WriteText(&(params[0].front()), params[0].size());
@@ -132,41 +110,12 @@
break;
case CBF_SMBITMAP: {
- using base::SharedMemory;
- using base::SharedMemoryHandle;
-
- if (params[0].size() != sizeof(SharedMemory*) ||
- params[1].size() != sizeof(gfx::Size)) {
- return;
- }
-
- SkBitmap bitmap;
- const gfx::Size* unvalidated_size =
- reinterpret_cast<const gfx::Size*>(¶ms[1].front());
- // Let Skia do some sanity checking for us (no negative widths/heights, no
- // overflows while calculating bytes per row, etc).
- if (!bitmap.setInfo(SkImageInfo::MakeN32Premul(
- unvalidated_size->width(), unvalidated_size->height()))) {
- return;
- }
- // Make sure the size is representable as a signed 32-bit int, so
- // SkBitmap::getSize() won't be truncated.
- if (!sk_64_isS32(bitmap.computeSize64()))
- return;
-
- // It's OK to cast away constness here since we map the handle as
- // read-only.
- const char* raw_bitmap_data_const =
- reinterpret_cast<const char*>(¶ms[0].front());
- char* raw_bitmap_data = const_cast<char*>(raw_bitmap_data_const);
- scoped_ptr<SharedMemory> bitmap_data(
- *reinterpret_cast<SharedMemory**>(raw_bitmap_data));
-
- if (!ValidateAndMapSharedBitmap(bitmap.getSize(), bitmap_data.get()))
- return;
- bitmap.setPixels(bitmap_data->memory());
-
- WriteBitmap(bitmap);
+ // Usually, the params are just UTF-8 strings. However, for images,
+ // ScopedClipboardWriter actually sizes the buffer to sizeof(SkBitmap*),
+ // aliases the contents of the vector to a SkBitmap**, and writes the
+ // pointer to the actual SkBitmap in the clipboard object param.
+ const char* packed_pointer_buffer = ¶ms[0].front();
+ WriteBitmap(**reinterpret_cast<SkBitmap* const*>(packed_pointer_buffer));
break;
}
@@ -183,40 +132,4 @@
}
}
-// static
-bool Clipboard::ReplaceSharedMemHandle(ObjectMap* objects,
- base::SharedMemoryHandle bitmap_handle,
- base::ProcessHandle process) {
- using base::SharedMemory;
- bool has_shared_bitmap = false;
-
- for (ObjectMap::iterator iter = objects->begin(); iter != objects->end();
- ++iter) {
- if (iter->first == CBF_SMBITMAP) {
- // The code currently only accepts sending a single bitmap over this way.
- // Fail if we ever encounter more than one shmem bitmap structure to fill.
- if (has_shared_bitmap)
- return false;
-
-#if defined(OS_WIN)
- SharedMemory* bitmap = new SharedMemory(bitmap_handle, true, process);
-#else
- SharedMemory* bitmap = new SharedMemory(bitmap_handle, true);
-#endif
-
- // There must always be two parameters associated with each shmem bitmap.
- if (iter->second.size() != 2)
- return false;
-
- // We store the shared memory object pointer so it can be retrieved by the
- // UI thread (see DispatchObject()).
- iter->second[0].clear();
- for (size_t i = 0; i < sizeof(SharedMemory*); ++i)
- iter->second[0].push_back(reinterpret_cast<char*>(&bitmap)[i]);
- has_shared_bitmap = true;
- }
- }
- return true;
-}
-
} // namespace ui
diff --git a/ui/base/clipboard/clipboard.h b/ui/base/clipboard/clipboard.h
index ab3d34b..6c23a6da 100644
--- a/ui/base/clipboard/clipboard.h
+++ b/ui/base/clipboard/clipboard.h
@@ -32,11 +32,6 @@
} // namespace win
} // namespace base
-// TODO(dcheng): Temporary until the IPC layer doesn't use WriteObjects().
-namespace content {
-class ClipboardMessageFilter;
-}
-
namespace gfx {
class Size;
}
@@ -118,48 +113,6 @@
// Copyable and assignable, since this is essentially an opaque value type.
};
- // TODO(dcheng): Make this private once the IPC layer no longer needs to
- // serialize this information.
- // ObjectType designates the type of data to be stored in the clipboard. This
- // designation is shared across all OSes. The system-specific designation
- // is defined by FormatType. A single ObjectType might be represented by
- // several system-specific FormatTypes. For example, on Linux the CBF_TEXT
- // ObjectType maps to "text/plain", "STRING", and several other formats. On
- // windows it maps to CF_UNICODETEXT.
- enum ObjectType {
- CBF_TEXT,
- CBF_HTML,
- CBF_RTF,
- CBF_BOOKMARK,
- CBF_WEBKIT,
- CBF_SMBITMAP, // Bitmap from shared memory.
- CBF_DATA, // Arbitrary block of bytes.
- };
-
- // ObjectMap is a map from ObjectType to associated data.
- // The data is organized differently for each ObjectType. The following
- // table summarizes what kind of data is stored for each key.
- // * indicates an optional argument.
- //
- // Key Arguments Type
- // -------------------------------------
- // CBF_TEXT text char array
- // CBF_HTML html char array
- // url* char array
- // CBF_RTF data byte array
- // CBF_BOOKMARK html char array
- // url char array
- // CBF_WEBKIT none empty vector
- // CBF_SMBITMAP shared_mem A pointer to an unmapped base::SharedMemory
- // object containing the bitmap data. The bitmap
- // data should be premultiplied.
- // size gfx::Size struct
- // CBF_DATA format char array
- // data byte array
- typedef std::vector<char> ObjectMapParam;
- typedef std::vector<ObjectMapParam> ObjectMapParams;
- typedef std::map<int /* ObjectType */, ObjectMapParams> ObjectMap;
-
static bool IsSupportedClipboardType(int32 type) {
switch (type) {
case CLIPBOARD_TYPE_COPY_PASTE:
@@ -267,15 +220,6 @@
static const FormatType& GetWebCustomDataFormatType();
static const FormatType& GetPepperCustomDataFormatType();
- // Embeds a pointer to a SharedMemory object pointed to by |bitmap_handle|
- // belonging to |process| into a shared bitmap [CBF_SMBITMAP] slot in
- // |objects|. The pointer is deleted by DispatchObjects().
- //
- // On non-Windows platforms, |process| is ignored.
- static bool ReplaceSharedMemHandle(ObjectMap* objects,
- base::SharedMemoryHandle bitmap_handle,
- base::ProcessHandle process)
- WARN_UNUSED_RESULT;
#if defined(OS_WIN)
// Firefox text/html
static const FormatType& GetTextHtmlFormatType();
@@ -291,6 +235,45 @@
Clipboard() {}
virtual ~Clipboard() {}
+ // ObjectType designates the type of data to be stored in the clipboard. This
+ // designation is shared across all OSes. The system-specific designation
+ // is defined by FormatType. A single ObjectType might be represented by
+ // several system-specific FormatTypes. For example, on Linux the CBF_TEXT
+ // ObjectType maps to "text/plain", "STRING", and several other formats. On
+ // windows it maps to CF_UNICODETEXT.
+ enum ObjectType {
+ CBF_TEXT,
+ CBF_HTML,
+ CBF_RTF,
+ CBF_BOOKMARK,
+ CBF_WEBKIT,
+ CBF_SMBITMAP, // Bitmap from shared memory.
+ CBF_DATA, // Arbitrary block of bytes.
+ };
+
+ // ObjectMap is a map from ObjectType to associated data.
+ // The data is organized differently for each ObjectType. The following
+ // table summarizes what kind of data is stored for each key.
+ // * indicates an optional argument.
+ //
+ // Key Arguments Type
+ // -------------------------------------
+ // CBF_TEXT text char array
+ // CBF_HTML html char array
+ // url* char array
+ // CBF_RTF data byte array
+ // CBF_BOOKMARK html char array
+ // url char array
+ // CBF_WEBKIT none empty vector
+ // CBF_SMBITMAP bitmap A pointer to a SkBitmap. The caller must ensure
+ // the SkBitmap remains live for the duration of
+ // the WriteObjects call.
+ // CBF_DATA format char array
+ // data byte array
+ typedef std::vector<char> ObjectMapParam;
+ typedef std::vector<ObjectMapParam> ObjectMapParams;
+ typedef std::map<int /* ObjectType */, ObjectMapParams> ObjectMap;
+
// Write a bunch of objects to the system clipboard. Copies are made of the
// contents of |objects|.
virtual void WriteObjects(ClipboardType type, const ObjectMap& objects) = 0;
@@ -320,11 +303,7 @@
size_t data_len) = 0;
private:
- template <typename T>
- friend class ClipboardTest;
// For access to WriteObjects().
- // TODO(dcheng): Remove the temporary exception for content.
- friend class content::ClipboardMessageFilter;
friend class ScopedClipboardWriter;
friend class TestClipboard;
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h
index 2a6c2a7..b5df843 100644
--- a/ui/base/clipboard/clipboard_test_template.h
+++ b/ui/base/clipboard/clipboard_test_template.h
@@ -61,18 +61,9 @@
~ClipboardTest() override { ClipboardTraits::Destroy(clipboard_); }
- static void WriteObjectsToClipboard(ui::Clipboard* clipboard,
- const Clipboard::ObjectMap& objects) {
- clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
- }
-
protected:
Clipboard& clipboard() { return *clipboard_; }
- void WriteObjectsToClipboard(const Clipboard::ObjectMap& objects) {
- WriteObjectsToClipboard(&clipboard(), objects);
- }
-
private:
base::MessageLoopForUI message_loop_;
#if defined(USE_AURA)
@@ -349,54 +340,18 @@
#endif
}
-// TODO(dcheng): The tests for copying to the clipboard also test IPC
-// interaction... consider moving them to a different layer so we can
-// consolidate the validation logic.
-// Note that |bitmap_data| is not premultiplied!
static void TestBitmapWrite(Clipboard* clipboard,
- const uint32* bitmap_data,
- size_t bitmap_data_size,
- const gfx::Size& size) {
- // Create shared memory region.
- base::SharedMemory shared_buf;
- ASSERT_TRUE(shared_buf.CreateAndMapAnonymous(bitmap_data_size));
- memcpy(shared_buf.memory(), bitmap_data, bitmap_data_size);
- // CBF_SMBITMAP expects premultiplied bitmap data so do that now.
- uint32* pixel_buffer = static_cast<uint32*>(shared_buf.memory());
- for (int j = 0; j < size.height(); ++j) {
- for (int i = 0; i < size.width(); ++i) {
- uint32& pixel = pixel_buffer[i + j * size.width()];
- pixel = SkPreMultiplyColor(pixel);
- }
+ const gfx::Size& size,
+ const uint32* bitmap_data) {
+ {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ SkBitmap bitmap;
+ ASSERT_TRUE(bitmap.setInfo(
+ SkImageInfo::MakeN32Premul(size.width(), size.height())));
+ bitmap.setPixels(
+ const_cast<void*>(reinterpret_cast<const void*>(bitmap_data)));
+ scw.WriteImage(bitmap);
}
- base::SharedMemoryHandle handle_to_share;
- base::ProcessHandle current_process = base::kNullProcessHandle;
-#if defined(OS_WIN)
- current_process = GetCurrentProcess();
-#endif
- shared_buf.ShareToProcess(current_process, &handle_to_share);
- ASSERT_TRUE(shared_buf.Unmap());
-
- // Setup data for clipboard().
- Clipboard::ObjectMapParam placeholder_param;
- Clipboard::ObjectMapParam size_param;
- const char* size_data = reinterpret_cast<const char*>(&size);
- for (size_t i = 0; i < sizeof(size); ++i)
- size_param.push_back(size_data[i]);
-
- Clipboard::ObjectMapParams params;
- params.push_back(placeholder_param);
- params.push_back(size_param);
-
- Clipboard::ObjectMap objects;
- objects[Clipboard::CBF_SMBITMAP] = params;
- ASSERT_TRUE(Clipboard::ReplaceSharedMemHandle(&objects, handle_to_share,
- current_process));
-
- // This is pretty ugly, but the template type parameter is irrelevant... and
- // this test will be going away anyway.
- ClipboardTest<NullClipboardTraits>::WriteObjectsToClipboard(clipboard,
- objects);
EXPECT_TRUE(clipboard->IsFormatAvailable(Clipboard::GetBitmapFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
@@ -407,145 +362,38 @@
const uint32* row_address = image.getAddr32(0, j);
for (int i = 0; i < image.width(); ++i) {
int offset = i + j * image.width();
- uint32 pixel = SkPreMultiplyColor(bitmap_data[offset]);
- EXPECT_EQ(pixel, row_address[i]) << "i = " << i << ", j = " << j;
+ EXPECT_EQ(bitmap_data[offset], row_address[i]) << "i = " << i
+ << ", j = " << j;
}
}
}
TYPED_TEST(ClipboardTest, SharedBitmapTest) {
const uint32 fake_bitmap_1[] = {
- 0x46155189, 0xF6A55C8D, 0x79845674, 0xFA57BD89,
- 0x78FD46AE, 0x87C64F5A, 0x36EDC5AF, 0x4378F568,
- 0x91E9F63A, 0xC31EA14F, 0x69AB32DF, 0x643A3FD1,
+ 0x46061626, 0xf69f5988, 0x793f2937, 0xfa55b986,
+ 0x78772152, 0x87692a30, 0x36322a25, 0x4320401b,
+ 0x91848c21, 0xc3177b3c, 0x6946155c, 0x64171952,
};
{
SCOPED_TRACE("first bitmap");
- TestBitmapWrite(&this->clipboard(), fake_bitmap_1, sizeof(fake_bitmap_1),
- gfx::Size(4, 3));
+ TestBitmapWrite(&this->clipboard(), gfx::Size(4, 3), fake_bitmap_1);
}
const uint32 fake_bitmap_2[] = {
- 0x46155189, 0xF6A55C8D,
- 0x79845674, 0xFA57BD89,
- 0x78FD46AE, 0x87C64F5A,
- 0x36EDC5AF, 0x4378F568,
- 0x91E9F63A, 0xC31EA14F,
- 0x69AB32DF, 0x643A3FD1,
- 0xA6DF041D, 0x83046278,
+ 0x46061626, 0xf69f5988,
+ 0x793f2937, 0xfa55b986,
+ 0x78772152, 0x87692a30,
+ 0x36322a25, 0x4320401b,
+ 0x91848c21, 0xc3177b3c,
+ 0x6946155c, 0x64171952,
+ 0xa6910313, 0x8302323e,
};
{
SCOPED_TRACE("second bitmap");
- TestBitmapWrite(&this->clipboard(), fake_bitmap_2, sizeof(fake_bitmap_2),
- gfx::Size(2, 7));
+ TestBitmapWrite(&this->clipboard(), gfx::Size(2, 7), fake_bitmap_2);
}
}
-namespace {
-// A size class that just happens to have the same layout as gfx::Size!
-struct UnsafeSize {
- int width;
- int height;
-};
-COMPILE_ASSERT(sizeof(UnsafeSize) == sizeof(gfx::Size),
- UnsafeSize_must_be_same_size_as_gfx_Size);
-} // namespace
-
-TYPED_TEST(ClipboardTest, SharedBitmapWithTwoNegativeSizes) {
- Clipboard::ObjectMapParam placeholder_param;
- void* crash_me = reinterpret_cast<void*>(57);
- placeholder_param.resize(sizeof(crash_me));
- memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
-
- Clipboard::ObjectMapParam size_param;
- UnsafeSize size = {-100, -100};
- size_param.resize(sizeof(size));
- memcpy(&size_param.front(), &size, sizeof(size));
-
- Clipboard::ObjectMapParams params;
- params.push_back(placeholder_param);
- params.push_back(size_param);
-
- Clipboard::ObjectMap objects;
- objects[Clipboard::CBF_SMBITMAP] = params;
-
- this->WriteObjectsToClipboard(objects);
- EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
-}
-
-TYPED_TEST(ClipboardTest, SharedBitmapWithOneNegativeSize) {
- Clipboard::ObjectMapParam placeholder_param;
- void* crash_me = reinterpret_cast<void*>(57);
- placeholder_param.resize(sizeof(crash_me));
- memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
-
- Clipboard::ObjectMapParam size_param;
- UnsafeSize size = {-100, 100};
- size_param.resize(sizeof(size));
- memcpy(&size_param.front(), &size, sizeof(size));
-
- Clipboard::ObjectMapParams params;
- params.push_back(placeholder_param);
- params.push_back(size_param);
-
- Clipboard::ObjectMap objects;
- objects[Clipboard::CBF_SMBITMAP] = params;
-
- this->WriteObjectsToClipboard(objects);
- EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
-}
-
-TYPED_TEST(ClipboardTest, BitmapWithSuperSize) {
- Clipboard::ObjectMapParam placeholder_param;
- void* crash_me = reinterpret_cast<void*>(57);
- placeholder_param.resize(sizeof(crash_me));
- memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
-
- Clipboard::ObjectMapParam size_param;
- // Width just big enough that bytes per row won't fit in a 32-bit
- // representation.
- gfx::Size size(0x20000000, 1);
- size_param.resize(sizeof(size));
- memcpy(&size_param.front(), &size, sizeof(size));
-
- Clipboard::ObjectMapParams params;
- params.push_back(placeholder_param);
- params.push_back(size_param);
-
- Clipboard::ObjectMap objects;
- objects[Clipboard::CBF_SMBITMAP] = params;
-
- this->WriteObjectsToClipboard(objects);
- EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
-}
-
-TYPED_TEST(ClipboardTest, BitmapWithSuperSize2) {
- Clipboard::ObjectMapParam placeholder_param;
- void* crash_me = reinterpret_cast<void*>(57);
- placeholder_param.resize(sizeof(crash_me));
- memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
-
- Clipboard::ObjectMapParam size_param;
- // Width and height large enough that SkBitmap::getSize() will be truncated.
- gfx::Size size(0x0fffffff, 0x0fffffff);
- size_param.resize(sizeof(size));
- memcpy(&size_param.front(), &size, sizeof(size));
-
- Clipboard::ObjectMapParams params;
- params.push_back(placeholder_param);
- params.push_back(size_param);
-
- Clipboard::ObjectMap objects;
- objects[Clipboard::CBF_SMBITMAP] = params;
-
- this->WriteObjectsToClipboard(objects);
- EXPECT_FALSE(this->clipboard().IsFormatAvailable(
- Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
-}
-
TYPED_TEST(ClipboardTest, DataTest) {
const ui::Clipboard::FormatType kFormat =
ui::Clipboard::GetFormatType("chromium/x-test-format");
@@ -754,4 +602,46 @@
}
#endif
+// Test that writing empty parameters doesn't try to dereference an empty data
+// vector. Not crashing = passing.
+TYPED_TEST(ClipboardTest, WriteTextEmptyParams) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WriteText(base::string16());
+}
+
+TYPED_TEST(ClipboardTest, WriteURLEmptyParams) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WriteURL(base::string16());
+}
+
+TYPED_TEST(ClipboardTest, WriteHTMLEmptyParams) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WriteHTML(base::string16(), std::string());
+}
+
+TYPED_TEST(ClipboardTest, WriteRTFEmptyParams) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WriteRTF(std::string());
+}
+
+TYPED_TEST(ClipboardTest, WriteBookmarkEmptyParams) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WriteBookmark(base::string16(), std::string());
+}
+
+TYPED_TEST(ClipboardTest, WriteHyperlinkEmptyParams) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WriteHyperlink(base::string16(), std::string());
+}
+
+TYPED_TEST(ClipboardTest, WritePickledData) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WritePickledData(Pickle(), Clipboard::GetPlainTextFormatType());
+}
+
+TYPED_TEST(ClipboardTest, WriteImageEmptyParams) {
+ ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
+ scw.WriteImage(SkBitmap());
+}
+
} // namespace ui
diff --git a/ui/base/clipboard/clipboard_util_win.cc b/ui/base/clipboard/clipboard_util_win.cc
index 687f0ff0..91d58a0 100644
--- a/ui/base/clipboard/clipboard_util_win.cc
+++ b/ui/base/clipboard/clipboard_util_win.cc
@@ -9,6 +9,7 @@
#include <wininet.h> // For INTERNET_MAX_URL_LENGTH.
#include "base/basictypes.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc
index 50a7ba3..599b565 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.cc
+++ b/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -86,6 +86,22 @@
objects_[Clipboard::CBF_WEBKIT] = Clipboard::ObjectMapParams();
}
+void ScopedClipboardWriter::WriteImage(const SkBitmap& bitmap) {
+ if (bitmap.drawsNothing()) {
+ return;
+ }
+ bitmap_ = bitmap;
+ // TODO(dcheng): This is slightly less horrible than what we used to do, but
+ // only very slightly less.
+ SkBitmap* bitmap_pointer = &bitmap_;
+ Clipboard::ObjectMapParam packed_pointer;
+ packed_pointer.resize(sizeof(bitmap_pointer));
+ *reinterpret_cast<SkBitmap**>(&*packed_pointer.begin()) = bitmap_pointer;
+ Clipboard::ObjectMapParams parameters;
+ parameters.push_back(packed_pointer);
+ objects_[Clipboard::CBF_SMBITMAP] = parameters;
+}
+
void ScopedClipboardWriter::WritePickledData(
const Pickle& pickle, const Clipboard::FormatType& format) {
std::string format_string = format.Serialize();
@@ -106,6 +122,7 @@
void ScopedClipboardWriter::Reset() {
url_text_.clear();
objects_.clear();
+ bitmap_.reset();
}
void ScopedClipboardWriter::WriteTextOrURL(const base::string16& text,
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
index ab799bd..ba7f1a5 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
@@ -14,6 +14,7 @@
#include <string>
#include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/ui_base_export.h"
@@ -61,10 +62,12 @@
void WritePickledData(const Pickle& pickle,
const Clipboard::FormatType& format);
+ void WriteImage(const SkBitmap& bitmap);
+
// Removes all objects that would be written to the clipboard.
void Reset();
- protected:
+ private:
// Converts |text| to UTF-8 and adds it to the clipboard. If it's a URL, we
// also notify the clipboard of that fact.
void WriteTextOrURL(const base::string16& text, bool is_url);
@@ -74,11 +77,12 @@
Clipboard::ObjectMap objects_;
const ClipboardType type_;
+ SkBitmap bitmap_;
+
// We keep around the UTF-8 text of the URL in order to pass it to
// Clipboard::DidWriteURL().
std::string url_text_;
- private:
DISALLOW_COPY_AND_ASSIGN(ScopedClipboardWriter);
};
diff --git a/ui/base/test/test_clipboard.cc b/ui/base/test/test_clipboard.cc
index df51c99..cbea7e850 100644
--- a/ui/base/test/test_clipboard.cc
+++ b/ui/base/test/test_clipboard.cc
@@ -17,10 +17,12 @@
TestClipboard::~TestClipboard() {
}
-void TestClipboard::UseForCurrentThread() {
+Clipboard* TestClipboard::CreateForCurrentThread() {
base::AutoLock lock(Clipboard::clipboard_map_lock_.Get());
+ Clipboard* clipboard = new TestClipboard;
Clipboard::clipboard_map_.Get()[base::PlatformThread::CurrentId()] =
- new TestClipboard;
+ clipboard;
+ return clipboard;
}
uint64 TestClipboard::GetSequenceNumber(ClipboardType type) const {
diff --git a/ui/base/test/test_clipboard.h b/ui/base/test/test_clipboard.h
index c1701bf7..58fa5075 100644
--- a/ui/base/test/test_clipboard.h
+++ b/ui/base/test/test_clipboard.h
@@ -16,7 +16,10 @@
TestClipboard();
~TestClipboard() override;
- static void UseForCurrentThread();
+ // Creates and associates a TestClipboard with the current thread. When no
+ // longer needed, the returned clipboard must be freed by calling
+ // Clipboard::DestroyClipboardForCurrentThread() on the same thread.
+ static Clipboard* CreateForCurrentThread();
// Clipboard overrides.
uint64 GetSequenceNumber(ClipboardType type) const override;
diff --git a/ui/base/test/test_clipboard_unittest.cc b/ui/base/test/test_clipboard_unittest.cc
index e2f7a3b..8d3a436 100644
--- a/ui/base/test/test_clipboard_unittest.cc
+++ b/ui/base/test/test_clipboard_unittest.cc
@@ -9,10 +9,7 @@
namespace ui {
struct TestClipboardTraits {
- static Clipboard* Create() {
- TestClipboard::UseForCurrentThread();
- return Clipboard::GetForCurrentThread();
- }
+ static Clipboard* Create() { return TestClipboard::CreateForCurrentThread(); }
static void Destroy(Clipboard* clipboard) {
ASSERT_EQ(Clipboard::GetForCurrentThread(), clipboard);
diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp
index ef9779d..6b64c7a 100644
--- a/ui/base/ui_base.gyp
+++ b/ui/base/ui_base.gyp
@@ -34,6 +34,7 @@
],
'export_dependent_settings': [
'../../net/net.gyp:net',
+ '../../skia/skia.gyp:skia',
'../gfx/gfx.gyp:gfx',
],
'sources' : [