summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-27 10:24:59 +0000
committerjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-27 10:24:59 +0000
commite344c910c5f4a1c88e3da37e074873a6360f3624 (patch)
tree4c3717fd77e4fcd62fbcb5da37cfe10ca25146fe
parent98e053c3baec827f9177a429e46abe36cd4fb9f2 (diff)
downloadchromium_src-e344c910c5f4a1c88e3da37e074873a6360f3624.zip
chromium_src-e344c910c5f4a1c88e3da37e074873a6360f3624.tar.gz
chromium_src-e344c910c5f4a1c88e3da37e074873a6360f3624.tar.bz2
POSIX: Use Shared Mem transport to copy images.
Prior to this change images where copied inline in IPC messages on non-Windows platforms. Copying an oversized image would cause the IPC system to bork and crash the renderer. Changes in this CL: * All platforms use a unified mechanism to copy images using shared memory. * Introduced a new IPC message so the renderer can allocated a shared memory segment on OS X. * On OS X tried to keep as few copies of the image data in memory as possible. BUG=26822 TEST=1)On all platforms: navigate to a webpage, right click on an image and copy. Then try pasting into an image editor. 2)Repro steps in bug should no longer crash the Renderer on Mac/Linux Review URL: http://codereview.chromium.org/552129 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37247 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--app/clipboard/clipboard.cc108
-rw-r--r--app/clipboard/clipboard.h26
-rw-r--r--app/clipboard/clipboard_linux.cc5
-rw-r--r--app/clipboard/clipboard_mac.mm17
-rw-r--r--app/clipboard/clipboard_unittest.cc44
-rw-r--r--app/clipboard/clipboard_win.cc69
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc47
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h9
-rw-r--r--chrome/common/render_messages_internal.h14
-rw-r--r--chrome/renderer/renderer_glue.cc53
-rw-r--r--webkit/glue/scoped_clipboard_writer_glue.h2
-rw-r--r--webkit/tools/test_shell/simple_clipboard_impl.cc2
12 files changed, 268 insertions, 128 deletions
diff --git a/app/clipboard/clipboard.cc b/app/clipboard/clipboard.cc
index a2050a0..54a7d90 100644
--- a/app/clipboard/clipboard.cc
+++ b/app/clipboard/clipboard.cc
@@ -6,11 +6,22 @@
#include "base/gfx/size.h"
#include "base/logging.h"
+#include "base/scoped_ptr.h"
namespace {
// A compromised renderer could send us bad data, so validate it.
-bool IsBitmapSafe(const Clipboard::ObjectMapParams& params) {
+// This function only checks that the size parameter makes sense, the caller
+// is responsible for further validating the bitmap buffer against
+// |bitmap_bytes|.
+//
+// |params| - Clipboard bitmap contents to validate.
+// |bitmap_bytes| - On return contains the number of bytes needed to store
+// the bitmap data or -1 if the data is invalid.
+// returns: true if the bitmap size is valid, false otherwise.
+bool IsBitmapSafe(const Clipboard::ObjectMapParams& params,
+ size_t* bitmap_bytes) {
+ *bitmap_bytes = -1;
if (params[1].size() != sizeof(gfx::Size))
return false;
const gfx::Size* size =
@@ -23,7 +34,40 @@ bool IsBitmapSafe(const Clipboard::ObjectMapParams& params) {
if (INT_MAX / total_size <= 4)
return false;
total_size *= 4;
- return params[0].size() == total_size;
+ *bitmap_bytes = total_size;
+ return true;
+}
+
+// Validates a plain bitmap on the clipboard.
+// Returns true if the clipboard data makes sense and it's safe to access the
+// bitmap.
+bool ValidatePlainBitmap(const Clipboard::ObjectMapParams& params) {
+ size_t bitmap_bytes = -1;
+ if (!IsBitmapSafe(params, &bitmap_bytes))
+ return false;
+ if (bitmap_bytes != params[0].size())
+ return false;
+ return true;
+}
+
+// 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(const Clipboard::ObjectMapParams& params,
+ base::SharedMemory* bitmap_data) {
+ using base::SharedMemory;
+ size_t bitmap_bytes = -1;
+ if (!IsBitmapSafe(params, &bitmap_bytes))
+ return false;
+
+ 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
@@ -33,7 +77,8 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) {
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_BITMAP || type == CBF_DATA) &&
+ if ((type == CBF_BOOKMARK || type == CBF_BITMAP ||
+ type == CBF_SMBITMAP || type == CBF_DATA) &&
(params.size() != 2 || params[1].empty()))
return;
switch (type) {
@@ -62,11 +107,34 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) {
break;
case CBF_BITMAP:
- if (!IsBitmapSafe(params))
+ if (!ValidatePlainBitmap(params))
return;
+
WriteBitmap(&(params[0].front()), &(params[1].front()));
break;
+ case CBF_SMBITMAP: {
+ using base::SharedMemory;
+ using base::SharedMemoryHandle;
+
+ if (params[0].size() != sizeof(SharedMemory*))
+ 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*>(&(params[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(params, bitmap_data.get()))
+ return;
+ WriteBitmap(static_cast<const char*>(bitmap_data->memory()),
+ &(params[1].front()));
+ break;
+ }
+
#if !defined(OS_MACOSX)
case CBF_DATA:
WriteData(&(params[0].front()), params[0].size(),
@@ -78,3 +146,35 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) {
NOTREACHED();
}
}
+
+// static
+void 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 hard if we ever encounter more than one shared bitmap structure to
+ // fill.
+ CHECK(!has_shared_bitmap);
+
+#if defined(OS_WIN)
+ SharedMemory* bitmap = new SharedMemory(bitmap_handle, true, process);
+#else
+ SharedMemory* bitmap = new SharedMemory(bitmap_handle, true);
+#endif
+
+ // 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;
+ }
+ }
+}
+
diff --git a/app/clipboard/clipboard.h b/app/clipboard/clipboard.h
index faaa00c..ee536f6 100644
--- a/app/clipboard/clipboard.h
+++ b/app/clipboard/clipboard.h
@@ -10,7 +10,9 @@
#include <vector>
#include "base/process.h"
+#include "base/shared_memory.h"
#include "base/string16.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
namespace gfx {
class Size;
@@ -61,7 +63,8 @@ class Clipboard {
// CBF_WEBKIT none empty vector
// CBF_BITMAP pixels byte array
// size gfx::Size struct
- // CBF_SMBITMAP shared_mem shared memory handle
+ // CBF_SMBITMAP shared_mem A pointer to an unmapped base::SharedMemory
+ // object containing the bitmap data.
// size gfx::Size struct
// CBF_DATA format char array
// data byte array
@@ -160,21 +163,26 @@ class Clipboard {
static FormatType GetWebKitSmartPasteFormatType();
// Win: MS HTML Format, Other: Generic HTML format
static FormatType GetHtmlFormatType();
-#if defined(OS_WIN)
static FormatType GetBitmapFormatType();
+
+ // 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 void ReplaceSharedMemHandle(ObjectMap* objects,
+ base::SharedMemoryHandle bitmap_handle,
+ base::ProcessHandle process);
+#if defined(OS_WIN)
// Firefox text/html
static FormatType GetTextHtmlFormatType();
static FormatType GetCFHDropFormatType();
static FormatType GetFileDescriptorFormatType();
static FormatType GetFileContentFormatZeroType();
-
- // Duplicates any remote shared memory handle embedded inside |objects| that
- // was created by |process| so that it can be used by this process.
- static void DuplicateRemoteHandles(base::ProcessHandle process,
- ObjectMap* objects);
#endif
private:
+ FRIEND_TEST(ClipboardTest, SharedBitmapTest);
void DispatchObject(ObjectType type, const ObjectMapParams& params);
void WriteText(const char* text_data, size_t text_len);
@@ -200,10 +208,6 @@ class Clipboard {
const char* data_data, size_t data_len);
#endif
#if defined(OS_WIN)
- void WriteBitmapFromSharedMemory(const char* bitmap_data,
- const char* size_data,
- base::ProcessHandle handle);
-
void WriteBitmapFromHandle(HBITMAP source_hbitmap,
const gfx::Size& size);
diff --git a/app/clipboard/clipboard_linux.cc b/app/clipboard/clipboard_linux.cc
index aec46da..740ec76 100644
--- a/app/clipboard/clipboard_linux.cc
+++ b/app/clipboard/clipboard_linux.cc
@@ -378,6 +378,11 @@ Clipboard::FormatType Clipboard::GetHtmlFormatType() {
}
// static
+Clipboard::FormatType Clipboard::GetBitmapFormatType() {
+ return std::string(kMimeBmp);
+}
+
+// static
Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() {
return std::string(kMimeWebkitSmartPaste);
}
diff --git a/app/clipboard/clipboard_mac.mm b/app/clipboard/clipboard_mac.mm
index ae3f1fe..1596eba 100644
--- a/app/clipboard/clipboard_mac.mm
+++ b/app/clipboard/clipboard_mac.mm
@@ -123,9 +123,14 @@ void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
NULL,
false,
kCGRenderingIntentDefault));
+ // Aggressively free storage since image buffers can potentially be very
+ // large.
+ data_provider.reset();
+ data.reset();
scoped_nsobject<NSBitmapImageRep> bitmap(
[[NSBitmapImageRep alloc] initWithCGImage:cgimage]);
+ cgimage.reset();
scoped_nsobject<NSImage> image([[NSImage alloc] init]);
[image addRepresentation:bitmap];
@@ -134,7 +139,11 @@ void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
// For now, spit out the image as a TIFF.
NSPasteboard* pb = GetPasteboard();
[pb addTypes:[NSArray arrayWithObject:NSTIFFPboardType] owner:nil];
- [pb setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
+ NSData *tiff_data = [image TIFFRepresentation];
+ LOG_IF(ERROR, tiff_data == NULL) << "Failed to allocate image for clipboard";
+ if (tiff_data) {
+ [pb setData:tiff_data forType:NSTIFFPboardType];
+ }
}
// Write an extra flavor that signifies WebKit was the last to modify the
@@ -295,6 +304,12 @@ Clipboard::FormatType Clipboard::GetHtmlFormatType() {
}
// static
+Clipboard::FormatType Clipboard::GetBitmapFormatType() {
+ static const std::string type = base::SysNSStringToUTF8(NSTIFFPboardType);
+ return type;
+}
+
+// static
Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() {
static const std::string type =
base::SysNSStringToUTF8(kWebSmartPastePboardType);
diff --git a/app/clipboard/clipboard_unittest.cc b/app/clipboard/clipboard_unittest.cc
index 81f400d..8203bac 100644
--- a/app/clipboard/clipboard_unittest.cc
+++ b/app/clipboard/clipboard_unittest.cc
@@ -213,6 +213,50 @@ TEST_F(ClipboardTest, URLTest) {
#endif // defined(OS_LINUX)
}
+TEST_F(ClipboardTest, SharedBitmapTest) {
+ unsigned int fake_bitmap[] = {
+ 0x46155189, 0xF6A55C8D, 0x79845674, 0xFA57BD89,
+ 0x78FD46AE, 0x87C64F5A, 0x36EDC5AF, 0x4378F568,
+ 0x91E9F63A, 0xC31EA14F, 0x69AB32DF, 0x643A3FD1,
+ };
+ gfx::Size fake_bitmap_size(3, 4);
+ size_t bytes = sizeof(fake_bitmap);
+
+ // Create shared memory region.
+ base::SharedMemory shared_buf;
+ ASSERT_TRUE(shared_buf.Create(L"", false, true, bytes));
+ ASSERT_TRUE(shared_buf.Map(bytes));
+ memcpy(shared_buf.memory(), fake_bitmap, bytes);
+ base::SharedMemoryHandle handle_to_share;
+ base::ProcessHandle current_process = NULL;
+#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*>(&fake_bitmap_size);
+ for (size_t i = 0; i < sizeof(fake_bitmap_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;
+ Clipboard::ReplaceSharedMemHandle(&objects, handle_to_share, current_process);
+
+ Clipboard clipboard;
+ clipboard.WriteObjects(objects);
+
+ EXPECT_TRUE(clipboard.IsFormatAvailable(Clipboard::GetBitmapFormatType(),
+ Clipboard::BUFFER_STANDARD));
+}
+
#if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_MACOSX))
TEST_F(ClipboardTest, DataTest) {
Clipboard clipboard;
diff --git a/app/clipboard/clipboard_win.cc b/app/clipboard/clipboard_win.cc
index 9074fc5..5e3bc42 100644
--- a/app/clipboard/clipboard_win.cc
+++ b/app/clipboard/clipboard_win.cc
@@ -162,12 +162,7 @@ void Clipboard::WriteObjects(const ObjectMap& objects,
for (ObjectMap::const_iterator iter = objects.begin();
iter != objects.end(); ++iter) {
- if (iter->first == CBF_SMBITMAP)
- WriteBitmapFromSharedMemory(&(iter->second[0].front()),
- &(iter->second[1].front()),
- process);
- else
- DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
+ DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
}
}
@@ -250,44 +245,6 @@ void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
::ReleaseDC(NULL, dc);
}
-void Clipboard::WriteBitmapFromSharedMemory(const char* bitmap_data,
- const char* size_data,
- base::ProcessHandle process) {
- const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data);
-
- // bitmap_data has an encoded shared memory object. See
- // DuplicateRemoteHandles().
- char* ptr = const_cast<char*>(bitmap_data);
- scoped_ptr<const base::SharedMemory> bitmap(*
- reinterpret_cast<const base::SharedMemory**>(ptr));
-
- // TODO(darin): share data in gfx/bitmap_header.cc somehow.
- BITMAPINFO bm_info = {0};
- bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bm_info.bmiHeader.biWidth = size->width();
- // Sets the vertical orientation.
- bm_info.bmiHeader.biHeight = -size->height();
- bm_info.bmiHeader.biPlanes = 1;
- bm_info.bmiHeader.biBitCount = 32;
- bm_info.bmiHeader.biCompression = BI_RGB;
-
- HDC dc = ::GetDC(NULL);
-
- // We can create an HBITMAP directly using the shared memory handle, saving
- // a memcpy.
- HBITMAP source_hbitmap =
- ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, NULL,
- bitmap->handle(), 0);
-
- if (source_hbitmap) {
- // Now we can write the HBITMAP to the clipboard
- WriteBitmapFromHandle(source_hbitmap, *size);
- }
-
- ::DeleteObject(source_hbitmap);
- ::ReleaseDC(NULL, dc);
-}
-
void Clipboard::WriteBitmapFromHandle(HBITMAP source_hbitmap,
const gfx::Size& size) {
// We would like to just call ::SetClipboardData on the source_hbitmap,
@@ -615,30 +572,6 @@ Clipboard::FormatType Clipboard::GetFileContentFormatZeroType() {
}
// static
-void Clipboard::DuplicateRemoteHandles(base::ProcessHandle process,
- ObjectMap* objects) {
- for (ObjectMap::iterator iter = objects->begin(); iter != objects->end();
- ++iter) {
- if (iter->first == CBF_SMBITMAP) {
- // There is a shared memory handle encoded on the first ObjectMapParam.
- // Use it to open a local handle to the memory.
- char* bitmap_data = &(iter->second[0].front());
- base::SharedMemoryHandle* remote_bitmap_handle =
- reinterpret_cast<base::SharedMemoryHandle*>(bitmap_data);
-
- base::SharedMemory* bitmap = new base::SharedMemory(*remote_bitmap_handle,
- false, process);
-
- // We store the object where the remote handle was located so it can
- // be retrieved by the UI thread (see WriteBitmapFromSharedMemory()).
- iter->second[0].clear();
- for (size_t i = 0; i < sizeof(bitmap); i++)
- iter->second[0].push_back(reinterpret_cast<char*>(&bitmap)[i]);
- }
- }
-}
-
-// static
Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() {
return IntToString(ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat);
}
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index 12959dc..11d7091 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -340,9 +340,9 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect,
render_widget_helper_->DidReceiveUpdateMsg(msg))
IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsAsync,
- OnClipboardWriteObjects)
+ OnClipboardWriteObjectsAsync)
IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsSync,
- OnClipboardWriteObjects)
+ OnClipboardWriteObjectsSync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardIsFormatAvailable,
OnClipboardIsFormatAvailable)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadText,
@@ -376,7 +376,9 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
#endif
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(ViewHostMsg_AllocatePDFTransport,
- OnAllocatePDFTransport)
+ OnAllocateSharedMemoryBuffer)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateSharedMemoryBuffer,
+ OnAllocateSharedMemoryBuffer)
#endif
IPC_MESSAGE_HANDLER(ViewHostMsg_ResourceTypeStats, OnResourceTypeStats)
IPC_MESSAGE_HANDLER(ViewHostMsg_V8HeapStats, OnV8HeapStats)
@@ -684,25 +686,38 @@ void ResourceMessageFilter::OnDownloadUrl(const IPC::Message& message,
context);
}
-void ResourceMessageFilter::OnClipboardWriteObjects(
- const Clipboard::ObjectMap& objects) {
+void ResourceMessageFilter::OnClipboardWriteObjectsSync(
+ const Clipboard::ObjectMap& objects,
+ base::SharedMemoryHandle bitmap_handle) {
+ DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
+ << "Bad bitmap handle";
// We cannot write directly from the IO thread, and cannot service the IPC
// on the UI thread. We'll copy the relevant data and get a handle to any
// shared memory so it doesn't go away when we resume the renderer, and post
// a task to perform the write on the UI thread.
Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects);
-#if defined(OS_WIN)
- // We pass the renderer handle to assist the clipboard with using shared
- // memory objects. handle() is a handle to the process that would
- // own any shared memory that might be in the object list. We only do this
- // on Windows and it only applies to bitmaps. (On Linux, bitmaps
- // are copied pixel by pixel rather than using shared memory.)
- Clipboard::DuplicateRemoteHandles(handle(), long_living_objects);
-#endif
+ // Splice the shared memory handle into the clipboard data.
+ Clipboard::ReplaceSharedMemHandle(long_living_objects, bitmap_handle,
+ handle());
+
+ ChromeThread::PostTask(
+ ChromeThread::UI,
+ FROM_HERE,
+ new WriteClipboardTask(long_living_objects));
+}
+
+void ResourceMessageFilter::OnClipboardWriteObjectsAsync(
+ const Clipboard::ObjectMap& objects) {
+ // 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.
+ Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects);
ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE, new WriteClipboardTask(long_living_objects));
+ ChromeThread::UI,
+ FROM_HERE,
+ new WriteClipboardTask(long_living_objects));
}
#if !defined(OS_LINUX)
@@ -793,14 +808,14 @@ void ResourceMessageFilter::OnDuplicateSection(
#endif
#if defined(OS_MACOSX)
-void ResourceMessageFilter::OnAllocatePDFTransport(
+void ResourceMessageFilter::OnAllocateSharedMemoryBuffer(
size_t buffer_size,
base::SharedMemoryHandle* handle) {
base::SharedMemory shared_buf;
shared_buf.Create(L"", false, false, buffer_size);
if (!shared_buf.Map(buffer_size)) {
*handle = base::SharedMemory::NULLHandle();
- NOTREACHED() << "Cannot map PDF transport buffer";
+ NOTREACHED() << "Cannot map shared memory buffer";
return;
}
shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), handle);
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index b24d095..585995f 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -197,7 +197,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
#endif
void OnReceiveContextMenuMsg(const IPC::Message& msg);
// Clipboard messages
- void OnClipboardWriteObjects(const Clipboard::ObjectMap& objects);
+ void OnClipboardWriteObjectsAsync(const Clipboard::ObjectMap& objects);
+ void OnClipboardWriteObjectsSync(const Clipboard::ObjectMap& objects,
+ base::SharedMemoryHandle bitmap_handle);
void OnClipboardIsFormatAvailable(Clipboard::FormatType format,
Clipboard::Buffer buffer,
@@ -239,8 +241,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
#endif
#if defined(OS_MACOSX)
// Used to ask the browser to allocate a block of shared memory for the
- // renderer to send PDF across in.
- void OnAllocatePDFTransport(size_t buffer_size,
+ // renderer to send back data in, since shared memory can't be created
+ // in the renderer on OS X due to the sandbox.
+ void OnAllocateSharedMemoryBuffer(size_t buffer_size,
base::SharedMemoryHandle* handle);
#endif
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 2feba45..19d6fae 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -1250,8 +1250,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
// 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_CONTROL1_0(ViewHostMsg_ClipboardWriteObjectsSync,
- Clipboard::ObjectMap /* objects */)
+ IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_ClipboardWriteObjectsSync,
+ Clipboard::ObjectMap /* objects */,
+ base::SharedMemoryHandle /* bitmap handle */)
IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_ClipboardIsFormatAvailable,
std::string /* format */,
Clipboard::Buffer /* buffer */,
@@ -1578,7 +1579,7 @@ IPC_BEGIN_MESSAGES(ViewHost)
#endif
#if defined(OS_LINUX)
- // Asks the browser create a temporary file for the renderer to fill
+ // Asks the browser to create a temporary file for the renderer to fill
// in resulting NativeMetafile in printing.
IPC_SYNC_MESSAGE_CONTROL0_2(ViewHostMsg_AllocateTempFileForPrinting,
base::FileDescriptor /* temp file fd */,
@@ -1588,11 +1589,16 @@ IPC_BEGIN_MESSAGES(ViewHost)
#endif
#if defined(OS_MACOSX)
- // Asks the browser create a block of shared memory for the renderer to pass
+ // Asks the browser to create a block of shared memory for the renderer to pass
// NativeMetafile data to the browser.
IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_AllocatePDFTransport,
size_t /* buffer size */,
base::SharedMemoryHandle /* browser handle */)
+ // Asks the browser to create a block of shared memory for the renderer to
+ // fill in and pass back to the browser.
+ IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_AllocateSharedMemoryBuffer,
+ size_t /* buffer size */,
+ base::SharedMemoryHandle /* browser handle */)
#endif
// Provide the browser process with information about the WebCore resource
diff --git a/chrome/renderer/renderer_glue.cc b/chrome/renderer/renderer_glue.cc
index ec9e3b2..8b5d3fd 100644
--- a/chrome/renderer/renderer_glue.cc
+++ b/chrome/renderer/renderer_glue.cc
@@ -82,7 +82,6 @@ class ResizableStackArray {
size_t cur_capacity_;
};
-#if defined(OS_WIN)
// This definition of WriteBitmapFromPixels uses shared memory to communicate
// across processes.
void ScopedClipboardWriterGlue::WriteBitmapFromPixels(const void* pixels,
@@ -93,7 +92,30 @@ void ScopedClipboardWriterGlue::WriteBitmapFromPixels(const void* pixels,
size_t buf_size = 4 * size.width() * size.height();
- // Allocate a shared memory buffer to hold the bitmap bits
+ // Allocate a shared memory buffer to hold the bitmap bits.
+#if defined(OS_MACOSX)
+ // On OS X, we need to ask the browser to create the shared memory for us,
+ // since this is blocked by the sandbox.
+ base::SharedMemoryHandle shared_mem_handle;
+ ViewHostMsg_AllocateSharedMemoryBuffer *msg =
+ new ViewHostMsg_AllocateSharedMemoryBuffer(buf_size,
+ &shared_mem_handle);
+ if (RenderThread::current()->Send(msg)) {
+ if (base::SharedMemory::IsHandleValid(shared_mem_handle)) {
+ shared_buf_ = new base::SharedMemory(shared_mem_handle, false);
+ if (!shared_buf_ || !shared_buf_->Map(buf_size)) {
+ NOTREACHED() << "Map failed";
+ return;
+ }
+ } else {
+ NOTREACHED() << "Browser failed to allocate shared memory";
+ return;
+ }
+ } else {
+ NOTREACHED() << "Browser allocation request message failed";
+ return;
+ }
+#else
shared_buf_ = new base::SharedMemory;
const bool created = shared_buf_ && shared_buf_->Create(
L"", false /* read write */, true /* open existing */, buf_size);
@@ -101,28 +123,26 @@ void ScopedClipboardWriterGlue::WriteBitmapFromPixels(const void* pixels,
NOTREACHED();
return;
}
+#endif // !OS_MACOSX
// Copy the bits into shared memory
memcpy(shared_buf_->memory(), pixels, buf_size);
shared_buf_->Unmap();
- Clipboard::ObjectMapParam param1, param2;
- base::SharedMemoryHandle smh = shared_buf_->handle();
-
- const char* shared_handle = reinterpret_cast<const char*>(&smh);
- for (size_t i = 0; i < sizeof base::SharedMemoryHandle; i++)
- param1.push_back(shared_handle[i]);
-
+ Clipboard::ObjectMapParam size_param;
const char* size_data = reinterpret_cast<const char*>(&size);
- for (size_t i = 0; i < sizeof gfx::Size; i++)
- param2.push_back(size_data[i]);
+ for (size_t i = 0; i < sizeof(gfx::Size); ++i)
+ size_param.push_back(size_data[i]);
Clipboard::ObjectMapParams params;
- params.push_back(param1);
- params.push_back(param2);
+
+ // 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.
+ Clipboard::ObjectMapParam place_holder_param;
+ params.push_back(place_holder_param);
+ params.push_back(size_param);
objects_[Clipboard::CBF_SMBITMAP] = params;
}
-#endif
// Define a destructor that makes IPCs to flush the contents to the
// system clipboard.
@@ -130,14 +150,13 @@ ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() {
if (objects_.empty())
return;
-#if defined(OS_WIN)
if (shared_buf_) {
RenderThread::current()->Send(
- new ViewHostMsg_ClipboardWriteObjectsSync(objects_));
+ new ViewHostMsg_ClipboardWriteObjectsSync(objects_,
+ shared_buf_->handle()));
delete shared_buf_;
return;
}
-#endif
RenderThread::current()->Send(
new ViewHostMsg_ClipboardWriteObjectsAsync(objects_));
diff --git a/webkit/glue/scoped_clipboard_writer_glue.h b/webkit/glue/scoped_clipboard_writer_glue.h
index 14917a3..7460ddf 100644
--- a/webkit/glue/scoped_clipboard_writer_glue.h
+++ b/webkit/glue/scoped_clipboard_writer_glue.h
@@ -22,9 +22,7 @@ class ScopedClipboardWriterGlue : public ScopedClipboardWriter {
~ScopedClipboardWriterGlue();
-#if defined(OS_WIN)
void WriteBitmapFromPixels(const void* pixels, const gfx::Size& size);
-#endif
private:
base::SharedMemory* shared_buf_;
diff --git a/webkit/tools/test_shell/simple_clipboard_impl.cc b/webkit/tools/test_shell/simple_clipboard_impl.cc
index c727f62..9a8fae0 100644
--- a/webkit/tools/test_shell/simple_clipboard_impl.cc
+++ b/webkit/tools/test_shell/simple_clipboard_impl.cc
@@ -15,12 +15,10 @@
// Clipboard glue
-#if defined(OS_WIN)
void ScopedClipboardWriterGlue::WriteBitmapFromPixels(
const void* pixels, const gfx::Size& size) {
ScopedClipboardWriter::WriteBitmapFromPixels(pixels, size);
}
-#endif
ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() {
}