diff options
30 files changed, 737 insertions, 895 deletions
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 285a9d3..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..0794d86 100644 --- a/chrome/common/net/BUILD.gn +++ b/chrome/common/net/BUILD.gn @@ -26,6 +26,7 @@ static_library("net") { "//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..18f84bf 100644 --- a/components/bookmarks/browser/BUILD.gn +++ b/components/bookmarks/browser/BUILD.gn @@ -73,5 +73,6 @@ source_set("unit_tests") { 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..af7e616 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 content { 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 @@ void ClipboardMessageFilter::OverrideThreadForMessage( 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 @@ bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message) { 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 @@ bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message) { 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 @@ void ClipboardMessageFilter::OnReadCustomData(ui::ClipboardType clipboard_type, 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 792bfc5..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 @@ class ClipboardMessageFilter : public BrowserMessageFilter { 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 @@ class ClipboardMessageFilter : public BrowserMessageFilter { 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 @@ class ClipboardMessageFilter : public BrowserMessageFilter { // 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..70761b7 --- /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 @@ IPC_ENUM_TRAITS_MAX_VALUE(ui::ClipboardType, ui::CLIPBOARD_TYPE_LAST) // 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 @@ IPC_SYNC_MESSAGE_CONTROL2_1(ClipboardHostMsg_ReadCustomData, 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..1645996 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 7f1b2dc..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 29a519d..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 @@ RendererBlinkPlatformImpl::RendererBlinkPlatformImpl( 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..cfa2512 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h @@ -42,7 +42,7 @@ class DeviceMotionEventPump; class DeviceOrientationEventPump; class PlatformEventObserverBase; class QuotaMessageFilter; -class RendererClipboardClient; +class RendererClipboardDelegate; class RendererScheduler; class RenderView; class ThreadSafeSender; @@ -206,7 +206,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { 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 e248c51..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 @@ using blink::WebVector; namespace content { -WebClipboardImpl::WebClipboardImpl(ClipboardClient* client) - : client_(client) { +WebClipboardImpl::WebClipboardImpl(RendererClipboardDelegate* delegate) + : delegate_(delegate) { + DCHECK(delegate); } WebClipboardImpl::~WebClipboardImpl() { @@ -47,7 +44,7 @@ uint64 WebClipboardImpl::sequenceNumber(Buffer buffer) { 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 @@ bool WebClipboardImpl::isFormatAvailable(Format format, Buffer buffer) { 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 @@ WebVector<WebString> WebClipboardImpl::readAvailableTypes( 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 @@ WebString WebClipboardImpl::readPlainText(Buffer buffer) { return WebString(); base::string16 text; - client_->ReadText(clipboard_type, &text); + delegate_->ReadText(clipboard_type, &text); return text; } @@ -104,9 +102,9 @@ WebString WebClipboardImpl::readHTML(Buffer buffer, WebURL* source_url, 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 @@ WebData WebClipboardImpl::readImage(Buffer buffer) { 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 @@ WebString WebClipboardImpl::readCustomData(Buffer buffer, 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 @@ void WebClipboardImpl::writeImage(const WebImage& image, // 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 477f53b..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 @@ class WebClipboardImpl : public blink::WebClipboard { 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..aedc54b 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::DestroyClipboardForCurrentThread() { } 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 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) { 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 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) { } } -// 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..6c23a6d 100644 --- a/ui/base/clipboard/clipboard.h +++ b/ui/base/clipboard/clipboard.h @@ -32,11 +32,6 @@ class MessageWindow; } // 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 @@ class UI_BASE_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) { // 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 @@ class UI_BASE_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) { 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 @@ class UI_BASE_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) { 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 @@ class UI_BASE_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) { 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 @@ class ClipboardTest : public PlatformTest { ~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 @@ TYPED_TEST(ClipboardTest, URLTest) { #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 @@ static void TestBitmapWrite(Clipboard* clipboard, 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 @@ TYPED_TEST(ClipboardTest, GetSequenceNumber) { } #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 687f0ff..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 @@ void ScopedClipboardWriter::WriteWebSmartPaste() { 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::WritePickledData( 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 @@ class UI_BASE_EXPORT ScopedClipboardWriter { 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 @@ class UI_BASE_EXPORT ScopedClipboardWriter { 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..cbea7e8 100644 --- a/ui/base/test/test_clipboard.cc +++ b/ui/base/test/test_clipboard.cc @@ -17,10 +17,12 @@ TestClipboard::TestClipboard() 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 c1701bf..58fa507 100644 --- a/ui/base/test/test_clipboard.h +++ b/ui/base/test/test_clipboard.h @@ -16,7 +16,10 @@ class TestClipboard : public Clipboard { 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' : [ |