Index: content/browser/renderer_host/clipboard_message_filter.cc |
diff --git a/content/browser/renderer_host/clipboard_message_filter.cc b/content/browser/renderer_host/clipboard_message_filter.cc |
index 7e46a30d7714faba804ad94e7e13cf3fcd561e47..e317c9e81beccc0dcd4131765ce5eef17ab5ce64 100644 |
--- a/content/browser/renderer_host/clipboard_message_filter.cc |
+++ b/content/browser/renderer_host/clipboard_message_filter.cc |
@@ -4,7 +4,7 @@ |
#include "content/browser/renderer_host/clipboard_message_filter.h" |
-#include <memory> |
+#include <utility> |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
@@ -12,11 +12,16 @@ |
#include "base/macros.h" |
#include "base/pickle.h" |
#include "base/strings/utf_string_conversions.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "base/threading/sequenced_worker_pool.h" |
#include "build/build_config.h" |
+#include "content/browser/fileapi/chrome_blob_storage_context.h" |
#include "content/common/clipboard_messages.h" |
+#include "content/public/browser/blob_handle.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/clipboard.h" |
#include "ui/base/clipboard/custom_data_helper.h" |
#include "ui/base/clipboard/scoped_clipboard_writer.h" |
#include "ui/gfx/codec/png_codec.h" |
@@ -31,13 +36,18 @@ void ReleaseSharedMemoryPixels(void* addr, void* context) { |
delete reinterpret_cast<base::SharedMemory*>(context); |
} |
+// No-op helper for delayed cleanup of BlobHandles generated by reading |
+// clipboard images. |
+void CleanupReadImageBlob(std::unique_ptr<content::BlobHandle>) {} |
+ |
} // namespace |
-ClipboardMessageFilter::ClipboardMessageFilter() |
+ClipboardMessageFilter::ClipboardMessageFilter( |
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context) |
: BrowserMessageFilter(ClipboardMsgStart), |
+ blob_storage_context_(std::move(blob_storage_context)), |
clipboard_writer_( |
- new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE)) { |
-} |
+ new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE)) {} |
void ClipboardMessageFilter::OverrideThreadForMessage( |
const IPC::Message& message, BrowserThread::ID* thread) { |
@@ -54,11 +64,6 @@ void ClipboardMessageFilter::OverrideThreadForMessage( |
if (IPC_MESSAGE_CLASS(message) == ClipboardMsgStart) |
*thread = BrowserThread::UI; |
#endif |
- |
-#if defined(OS_WIN) |
- if (message.type() == ClipboardHostMsg_ReadImage::ID) |
- *thread = BrowserThread::FILE; |
-#endif |
} |
bool ClipboardMessageFilter::OnMessageReceived(const IPC::Message& message) { |
@@ -175,34 +180,58 @@ void ClipboardMessageFilter::OnReadImage(ui::ClipboardType type, |
IPC::Message* reply_msg) { |
SkBitmap bitmap = GetClipboard()->ReadImage(type); |
-#if defined(USE_X11) |
- BrowserThread::PostTask( |
- BrowserThread::FILE, FROM_HERE, |
- base::Bind( |
- &ClipboardMessageFilter::OnReadImageReply, this, bitmap, reply_msg)); |
-#else |
- OnReadImageReply(bitmap, reply_msg); |
-#endif |
+ BrowserThread::GetBlockingPool() |
+ ->GetTaskRunnerWithShutdownBehavior( |
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN) |
+ ->PostTask(FROM_HERE, |
+ base::Bind(&ClipboardMessageFilter::ReadAndEncodeImage, this, |
+ bitmap, reply_msg)); |
} |
-void ClipboardMessageFilter::OnReadImageReply( |
- const SkBitmap& bitmap, IPC::Message* reply_msg) { |
- base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle(); |
- uint32_t image_size = 0; |
+void ClipboardMessageFilter::ReadAndEncodeImage(const SkBitmap& bitmap, |
+ IPC::Message* reply_msg) { |
if (!bitmap.isNull()) { |
- std::vector<unsigned char> png_data; |
- if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &png_data)) { |
- base::SharedMemory buffer; |
- if (buffer.CreateAndMapAnonymous(png_data.size())) { |
- memcpy(buffer.memory(), png_data.data(), png_data.size()); |
- if (buffer.GiveToProcess(PeerHandle(), &image_handle)) { |
- image_size = png_data.size(); |
- } |
- } |
+ std::unique_ptr<std::vector<uint8_t>> png_data(new std::vector<uint8_t>); |
+ if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, png_data.get())) { |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&ClipboardMessageFilter::OnReadAndEncodeImageFinished, |
+ this, base::Passed(&png_data), reply_msg)); |
+ return; |
+ } |
+ } |
+ ClipboardHostMsg_ReadImage::WriteReplyParams(reply_msg, std::string(), |
+ std::string(), -1); |
+ Send(reply_msg); |
+} |
+ |
+void ClipboardMessageFilter::OnReadAndEncodeImageFinished( |
+ std::unique_ptr<std::vector<uint8_t>> png_data, |
+ IPC::Message* reply_msg) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ if (png_data->size() < std::numeric_limits<uint32_t>::max()) { |
+ std::unique_ptr<content::BlobHandle> blob_handle = |
+ blob_storage_context_->CreateMemoryBackedBlob( |
+ reinterpret_cast<char*>(png_data->data()), png_data->size()); |
+ if (blob_handle) { |
+ ClipboardHostMsg_ReadImage::WriteReplyParams( |
+ reply_msg, blob_handle->GetUUID(), ui::Clipboard::kMimeTypePNG, |
+ static_cast<int64_t>(png_data->size())); |
+ Send(reply_msg); |
+ // Give the renderer a minute to pick up a reference to the blob before |
+ // giving up. |
+ // TODO(dmurph): There should be a better way of transferring ownership of |
+ // a blob from the browser to the renderer, rather than relying on this |
+ // timeout to clean up eventually. See https://crbug.com/604800. |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&CleanupReadImageBlob, base::Passed(&blob_handle)), |
+ base::TimeDelta::FromMinutes(1)); |
+ return; |
} |
} |
- ClipboardHostMsg_ReadImage::WriteReplyParams(reply_msg, image_handle, |
- image_size); |
+ ClipboardHostMsg_ReadImage::WriteReplyParams(reply_msg, std::string(), |
+ std::string(), -1); |
Send(reply_msg); |
} |