summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/shared_memory.h17
-rw-r--r--base/shared_memory_posix.cc16
-rw-r--r--base/timer.h63
-rw-r--r--base/timer_unittest.cc118
-rw-r--r--chrome/browser/renderer_host/backing_store.cc4
-rw-r--r--chrome/browser/renderer_host/backing_store.h8
-rw-r--r--chrome/browser/renderer_host/backing_store_posix.cc25
-rw-r--r--chrome/browser/renderer_host/backing_store_win.cc19
-rw-r--r--chrome/browser/renderer_host/backing_store_xcb.cc40
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc66
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h18
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.cc12
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.h1
-rw-r--r--chrome/browser/renderer_host/render_process_host.h10
-rw-r--r--chrome/browser/renderer_host/render_widget_helper.cc59
-rw-r--r--chrome/browser/renderer_host/render_widget_helper.h35
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc40
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h8
-rw-r--r--chrome/browser/renderer_host/render_widget_host_unittest.cc28
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc18
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h9
-rw-r--r--chrome/chrome.xcodeproj/project.pbxproj4
-rw-r--r--chrome/common/bitmap_wire_data.h35
-rw-r--r--chrome/common/common.scons15
-rw-r--r--chrome/common/common.vcproj10
-rw-r--r--chrome/common/ipc_maybe.h19
-rw-r--r--chrome/common/ipc_message_utils.h51
-rw-r--r--chrome/common/render_messages.h6
-rw-r--r--chrome/common/render_messages_internal.h17
-rw-r--r--chrome/common/transport_dib.h112
-rw-r--r--chrome/common/transport_dib_linux.cc85
-rw-r--r--chrome/common/transport_dib_mac.cc63
-rw-r--r--chrome/common/transport_dib_win.cc72
-rw-r--r--chrome/renderer/render_process.cc163
-rw-r--r--chrome/renderer/render_process.h64
-rw-r--r--chrome/renderer/render_process_unittest.cc14
-rw-r--r--chrome/renderer/render_widget.cc76
-rw-r--r--chrome/renderer/render_widget.h13
-rw-r--r--chrome/renderer/renderer_glue.cc6
-rw-r--r--skia/ext/bitmap_platform_device_linux.h2
-rwxr-xr-xskia/ext/bitmap_platform_device_mac.cc32
-rw-r--r--skia/ext/platform_canvas_linux.cc19
-rw-r--r--skia/ext/platform_canvas_linux.h1
-rwxr-xr-xskia/ext/platform_canvas_mac.cc35
-rwxr-xr-xskia/ext/platform_canvas_mac.h3
45 files changed, 1242 insertions, 289 deletions
diff --git a/base/shared_memory.h b/base/shared_memory.h
index b44367a..744b348 100644
--- a/base/shared_memory.h
+++ b/base/shared_memory.h
@@ -8,6 +8,7 @@
#include "build/build_config.h"
#if defined(OS_POSIX)
+#include <sys/types.h>
#include <semaphore.h>
#include "base/file_descriptor_posix.h"
#endif
@@ -24,7 +25,10 @@ namespace base {
typedef HANDLE SharedMemoryHandle;
typedef HANDLE SharedMemoryLock;
#elif defined(OS_POSIX)
+// A SharedMemoryId is sufficient to identify a given shared memory segment on a
+// system, but insufficient to map it.
typedef FileDescriptor SharedMemoryHandle;
+typedef ino_t SharedMemoryId;
// On POSIX, the lock is implemented as a lockf() on the mapped file,
// so no additional member (or definition of SharedMemoryLock) is
// needed.
@@ -99,6 +103,14 @@ class SharedMemory {
// identifier is not portable.
SharedMemoryHandle handle() const;
+#if defined(OS_POSIX)
+ // Return a unique identifier for this shared memory segment. Inode numbers
+ // are technically only unique to a single filesystem. However, we always
+ // allocate shared memory backing files from the same directory, so will end
+ // up on the same filesystem.
+ SharedMemoryId id() const { return inode_; }
+#endif
+
// Closes the open shared memory segment.
// It is safe to call Close repeatedly.
void Close();
@@ -153,9 +165,10 @@ class SharedMemory {
std::wstring name_;
#if defined(OS_WIN)
- HANDLE mapped_file_;
+ HANDLE mapped_file_;
#elif defined(OS_POSIX)
- int mapped_file_;
+ int mapped_file_;
+ ino_t inode_;
#endif
void* memory_;
bool read_only_;
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc
index e6f81c5..c948e58 100644
--- a/base/shared_memory_posix.cc
+++ b/base/shared_memory_posix.cc
@@ -7,6 +7,8 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include "base/file_util.h"
#include "base/logging.h"
@@ -23,6 +25,7 @@ const char kSemaphoreSuffix[] = "-sem";
SharedMemory::SharedMemory()
: mapped_file_(-1),
+ inode_(0),
memory_(NULL),
read_only_(false),
max_size_(0) {
@@ -30,9 +33,16 @@ SharedMemory::SharedMemory()
SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
: mapped_file_(handle.fd),
+ inode_(0),
memory_(NULL),
read_only_(read_only),
max_size_(0) {
+ struct stat st;
+ if (fstat(handle.fd, &st) == 0) {
+ // If fstat fails, then the file descriptor is invalid and we'll learn this
+ // fact when Map() fails.
+ inode_ = st.st_ino;
+ }
}
SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
@@ -206,6 +216,12 @@ bool SharedMemory::CreateOrOpen(const std::wstring &name,
mapped_file_ = dup(fileno(fp));
DCHECK(mapped_file_ >= 0);
+
+ struct stat st;
+ if (fstat(mapped_file_, &st))
+ NOTREACHED();
+ inode_ = st.st_ino;
+
return true;
}
diff --git a/base/timer.h b/base/timer.h
index 698d59d..eb00486 100644
--- a/base/timer.h
+++ b/base/timer.h
@@ -89,7 +89,7 @@ class BaseTimer_Helper {
// Used to orphan delayed_task_ so that when it runs it does nothing.
void OrphanDelayedTask();
-
+
// Used to initiated a new delayed task. This has the side-effect of
// orphaning delayed_task_ if it is non-null.
void InitiateDelayedTask(TimerTask* timer_task);
@@ -128,7 +128,7 @@ class BaseTimer : public BaseTimer_Helper {
private:
typedef BaseTimer<Receiver, kIsRepeating> SelfType;
-
+
class TimerTask : public BaseTimer_Helper::TimerTask {
public:
TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
@@ -198,6 +198,65 @@ class OneShotTimer : public BaseTimer<Receiver, false> {};
template <class Receiver>
class RepeatingTimer : public BaseTimer<Receiver, true> {};
+//-----------------------------------------------------------------------------
+// A Delay timer is like The Button from Lost. Once started, you have to keep
+// calling Reset otherwise it will call the given method in the MessageLoop
+// thread.
+//
+// Once created, it is inactive until Reset is called. Once |delay| seconds have
+// passed since the last call to Reset, the callback is made. Once the callback
+// has been made, it's inactive until Reset is called again.
+template <class Receiver>
+class DelayTimer {
+ public:
+ typedef void (Receiver::*ReceiverMethod)();
+
+ DelayTimer(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
+ : receiver_(receiver),
+ method_(method),
+ delay_(delay) {
+ }
+
+ void Reset() {
+ DelayFor(delay_);
+ }
+
+ private:
+ void DelayFor(TimeDelta delay) {
+ trigger_time_ = Time::Now() + delay;
+
+ // If we already have a timer that will expire at or before the given delay,
+ // then we have nothing more to do now.
+ if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay)
+ return;
+
+ // The timer isn't running, or will expire too late, so restart it.
+ timer_.Stop();
+ timer_.Start(delay, this, &DelayTimer<Receiver>::Check);
+ }
+
+ void Check() {
+ if (trigger_time_.is_null())
+ return;
+
+ // If we have not waited long enough, then wait some more.
+ const Time now = Time::Now();
+ if (now < trigger_time_) {
+ DelayFor(trigger_time_ - now);
+ return;
+ }
+
+ (receiver_->*method_)();
+ }
+
+ Receiver *const receiver_;
+ const ReceiverMethod method_;
+ const TimeDelta delay_;
+
+ OneShotTimer<DelayTimer<Receiver> > timer_;
+ Time trigger_time_;
+};
+
} // namespace base
#endif // BASE_TIMER_H_
diff --git a/base/timer_unittest.cc b/base/timer_unittest.cc
index 8c1d58e..d441636 100644
--- a/base/timer_unittest.cc
+++ b/base/timer_unittest.cc
@@ -14,10 +14,12 @@ namespace {
class OneShotTimerTester {
public:
- OneShotTimerTester(bool* did_run) : did_run_(did_run) {
+ OneShotTimerTester(bool* did_run, unsigned milliseconds = 10)
+ : did_run_(did_run),
+ delay_ms_(milliseconds) {
}
void Start() {
- timer_.Start(TimeDelta::FromMilliseconds(10), this,
+ timer_.Start(TimeDelta::FromMilliseconds(delay_ms_), this,
&OneShotTimerTester::Run);
}
private:
@@ -27,6 +29,7 @@ class OneShotTimerTester {
}
bool* did_run_;
base::OneShotTimer<OneShotTimerTester> timer_;
+ const unsigned delay_ms_;
};
class OneShotSelfDeletingTimerTester {
@@ -138,7 +141,7 @@ void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type) {
// Now start the timer.
a->Start();
-
+
bool did_run_b = false;
RepeatingTimerTester b(&did_run_b);
b.Start();
@@ -149,6 +152,97 @@ void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type) {
EXPECT_TRUE(did_run_b);
}
+class DelayTimerTarget {
+ public:
+ DelayTimerTarget()
+ : signaled_(false) {
+ }
+
+ bool signaled() const { return signaled_; }
+
+ void Signal() {
+ ASSERT_FALSE(signaled_);
+ signaled_ = true;
+ }
+
+ private:
+ bool signaled_;
+};
+
+void RunTest_DelayTimer_NoCall(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
+ // If Delay is never called, the timer shouldn't go off.
+ DelayTimerTarget target;
+ base::DelayTimer<DelayTimerTarget> timer(
+ TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+
+ bool did_run = false;
+ OneShotTimerTester tester(&did_run);
+ tester.Start();
+ MessageLoop::current()->Run();
+
+ ASSERT_FALSE(target.signaled());
+}
+
+void RunTest_DelayTimer_OneCall(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
+ DelayTimerTarget target;
+ base::DelayTimer<DelayTimerTarget> timer(
+ TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+ timer.Reset();
+
+ bool did_run = false;
+ OneShotTimerTester tester(&did_run, 100 /* milliseconds */);
+ tester.Start();
+ MessageLoop::current()->Run();
+
+ ASSERT_TRUE(target.signaled());
+}
+
+struct ResetHelper {
+ ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
+ DelayTimerTarget* target)
+ : timer_(timer),
+ target_(target) {
+ }
+
+ void Reset() {
+ ASSERT_FALSE(target_->signaled());
+ timer_->Reset();
+ }
+
+ private:
+ base::DelayTimer<DelayTimerTarget> *const timer_;
+ DelayTimerTarget *const target_;
+};
+
+void RunTest_DelayTimer_Reset(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
+ // If Delay is never called, the timer shouldn't go off.
+ DelayTimerTarget target;
+ base::DelayTimer<DelayTimerTarget> timer(
+ TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+ timer.Reset();
+
+ ResetHelper reset_helper(&timer, &target);
+
+ base::OneShotTimer<ResetHelper> timers[20];
+ for (size_t i = 0; i < arraysize(timers); ++i) {
+ timers[i].Start(TimeDelta::FromMilliseconds(i * 10), &reset_helper,
+ &ResetHelper::Reset);
+ }
+
+ bool did_run = false;
+ OneShotTimerTester tester(&did_run, 300);
+ tester.Start();
+ MessageLoop::current()->Run();
+
+ ASSERT_TRUE(target.signaled());
+}
+
} // namespace
//-----------------------------------------------------------------------------
@@ -187,6 +281,24 @@ TEST(TimerTest, RepeatingTimer_Cancel) {
RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_IO);
}
+TEST(TimerTest, DelayTimer_NoCall) {
+ RunTest_DelayTimer_NoCall(MessageLoop::TYPE_DEFAULT);
+ RunTest_DelayTimer_NoCall(MessageLoop::TYPE_UI);
+ RunTest_DelayTimer_NoCall(MessageLoop::TYPE_IO);
+}
+
+TEST(TimerTest, DelayTimer_OneCall) {
+ RunTest_DelayTimer_OneCall(MessageLoop::TYPE_DEFAULT);
+ RunTest_DelayTimer_OneCall(MessageLoop::TYPE_UI);
+ RunTest_DelayTimer_OneCall(MessageLoop::TYPE_IO);
+}
+
+TEST(TimerTest, DelayTimer_Reset) {
+ RunTest_DelayTimer_Reset(MessageLoop::TYPE_DEFAULT);
+ RunTest_DelayTimer_Reset(MessageLoop::TYPE_UI);
+ RunTest_DelayTimer_Reset(MessageLoop::TYPE_IO);
+}
+
TEST(TimerTest, MessageLoopShutdown) {
// This test is designed to verify that shutdown of the
// message loop does not cause crashes if there were pending
diff --git a/chrome/browser/renderer_host/backing_store.cc b/chrome/browser/renderer_host/backing_store.cc
index da988768..a68e785 100644
--- a/chrome/browser/renderer_host/backing_store.cc
+++ b/chrome/browser/renderer_host/backing_store.cc
@@ -60,7 +60,7 @@ BackingStore* BackingStoreManager::PrepareBackingStore(
RenderWidgetHost* host,
const gfx::Rect& backing_store_rect,
base::ProcessHandle process_handle,
- BitmapWireData bitmap_section,
+ TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
bool* needs_full_paint) {
BackingStore* backing_store = GetBackingStore(host,
@@ -76,7 +76,7 @@ BackingStore* BackingStoreManager::PrepareBackingStore(
}
DCHECK(backing_store != NULL);
- backing_store->PaintRect(process_handle, bitmap_section, bitmap_rect);
+ backing_store->PaintRect(process_handle, bitmap, bitmap_rect);
return backing_store;
}
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index 29415a8..e6113f5 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -10,7 +10,6 @@
#include "base/gfx/size.h"
#include "base/process.h"
#include "build/build_config.h"
-#include "chrome/common/bitmap_wire_data.h"
#include "chrome/common/mru_cache.h"
#if defined(OS_WIN)
@@ -20,6 +19,7 @@
#endif
class RenderWidgetHost;
+class TransportDIB;
// BackingStore ----------------------------------------------------------------
@@ -39,14 +39,14 @@ class BackingStore {
// Paints the bitmap from the renderer onto the backing store.
bool PaintRect(base::ProcessHandle process,
- BitmapWireData bitmap_section,
+ TransportDIB* bitmap,
const gfx::Rect& bitmap_rect);
// Scrolls the given rect in the backing store, replacing the given region
// identified by |bitmap_rect| by the bitmap in the file identified by the
// given file handle.
void ScrollRect(base::ProcessHandle process,
- BitmapWireData bitmap, const gfx::Rect& bitmap_rect,
+ TransportDIB* bitmap, const gfx::Rect& bitmap_rect,
int dx, int dy,
const gfx::Rect& clip_rect,
const gfx::Size& view_size);
@@ -113,7 +113,7 @@ class BackingStoreManager {
static BackingStore* PrepareBackingStore(RenderWidgetHost* host,
const gfx::Rect& backing_store_rect,
base::ProcessHandle process_handle,
- BitmapWireData bitmap_section,
+ TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
bool* needs_full_paint);
diff --git a/chrome/browser/renderer_host/backing_store_posix.cc b/chrome/browser/renderer_host/backing_store_posix.cc
index f925ef9..1d195fb 100644
--- a/chrome/browser/renderer_host/backing_store_posix.cc
+++ b/chrome/browser/renderer_host/backing_store_posix.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/renderer_host/backing_store.h"
#include "base/logging.h"
+#include "chrome/common/transport_dib.h"
#include "skia/ext/platform_canvas.h"
#include "skia/include/SkBitmap.h"
#include "skia/include/SkCanvas.h"
@@ -19,20 +20,20 @@ BackingStore::~BackingStore() {
}
bool BackingStore::PaintRect(base::ProcessHandle process,
- BitmapWireData bitmap,
+ TransportDIB* bitmap,
const gfx::Rect& bitmap_rect) {
- if (bitmap.width() != bitmap_rect.width() ||
- bitmap.height() != bitmap_rect.height() ||
- bitmap.config() != SkBitmap::kARGB_8888_Config) {
- return false;
- }
+ SkBitmap skbitmap;
+ skbitmap.setConfig(SkBitmap::kARGB_8888_Config, bitmap_rect.width(),
+ bitmap_rect.height(), 4 * bitmap_rect.width());
+
+ skbitmap.setPixels(bitmap->memory());
- canvas_.drawBitmap(bitmap, bitmap_rect.x(), bitmap_rect.y());
+ canvas_.drawBitmap(skbitmap, bitmap_rect.x(), bitmap_rect.y());
return true;
}
void BackingStore::ScrollRect(base::ProcessHandle process,
- BitmapWireData bitmap,
+ TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
int dx, int dy,
const gfx::Rect& clip_rect,
@@ -59,12 +60,6 @@ void BackingStore::ScrollRect(base::ProcessHandle process,
DCHECK(clip_rect.bottom() <= canvas_.getDevice()->height());
DCHECK(clip_rect.right() <= canvas_.getDevice()->width());
- if (bitmap.width() != bitmap_rect.width() ||
- bitmap.height() != bitmap_rect.height() ||
- bitmap.config() != SkBitmap::kARGB_8888_Config) {
- return;
- }
-
const SkBitmap &backing_bitmap = canvas_.getDevice()->accessBitmap(true);
const int stride = backing_bitmap.rowBytes();
uint8_t* x = static_cast<uint8_t*>(backing_bitmap.getPixels());
@@ -123,6 +118,6 @@ void BackingStore::ScrollRect(base::ProcessHandle process,
}
// Now paint the new bitmap data.
- canvas_.drawBitmap(bitmap, bitmap_rect.x(), bitmap_rect.y());
+ PaintRect(process, bitmap, bitmap_rect);
return;
}
diff --git a/chrome/browser/renderer_host/backing_store_win.cc b/chrome/browser/renderer_host/backing_store_win.cc
index 2ca9396..dcc1ad4 100644
--- a/chrome/browser/renderer_host/backing_store_win.cc
+++ b/chrome/browser/renderer_host/backing_store_win.cc
@@ -6,7 +6,7 @@
#include "base/gfx/gdi_util.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
-#include "chrome/common/win_util.h"
+#include "chrome/common/transport_dib.h"
// BackingStore (Windows) ------------------------------------------------------
@@ -31,14 +31,8 @@ BackingStore::~BackingStore() {
}
bool BackingStore::PaintRect(base::ProcessHandle process,
- BitmapWireData bitmap_section,
+ TransportDIB* bitmap,
const gfx::Rect& bitmap_rect) {
- // The bitmap received is valid only in the renderer process.
- HANDLE valid_bitmap =
- win_util::GetSectionFromProcess(bitmap_section, process, false);
- if (!valid_bitmap)
- return false;
-
if (!backing_store_dib_) {
backing_store_dib_ = CreateDIB(hdc_, size_.width(), size_.height(), true,
NULL);
@@ -48,8 +42,7 @@ bool BackingStore::PaintRect(base::ProcessHandle process,
// TODO(darin): protect against integer overflow
DWORD size = 4 * bitmap_rect.width() * bitmap_rect.height();
- void* backing_store_data = MapViewOfFile(valid_bitmap, FILE_MAP_READ, 0, 0,
- size);
+
// These values are shared with gfx::PlatformDevice
BITMAPINFOHEADER hdr;
gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr);
@@ -65,18 +58,16 @@ bool BackingStore::PaintRect(base::ProcessHandle process,
0, 0, // source x,y
paint_rect.width(),
paint_rect.height(),
- backing_store_data,
+ bitmap->memory(),
reinterpret_cast<BITMAPINFO*>(&hdr),
DIB_RGB_COLORS,
SRCCOPY);
- UnmapViewOfFile(backing_store_data);
- CloseHandle(valid_bitmap);
return true;
}
void BackingStore::ScrollRect(base::ProcessHandle process,
- BitmapWireData bitmap,
+ TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
int dx, int dy,
const gfx::Rect& clip_rect,
diff --git a/chrome/browser/renderer_host/backing_store_xcb.cc b/chrome/browser/renderer_host/backing_store_xcb.cc
new file mode 100644
index 0000000..ba6a12b
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_xcb.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2006-2008 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 "chrome/browser/renderer_host/backing_store.h"
+
+#include <xcb/xcb.h>
+
+#include "base/logging.h"
+#include "chrome/common/transport_dib.h"
+
+#ifdef NDEBUG
+#define XCB_CALL(func, ...) func(__VA_ARGS__)
+#else
+#define XCB_CALL(func, ...) do { \
+ xcb_void_cookie_t cookie = func##_checked(__VA_ARGS__); \
+ xcb_generic_error_t* error = xcb_request_check(connection_, cookie); \
+ if (error) { \
+ CHECK(false) << "XCB error" \
+ << " code:" << error->error_code \
+ << " type:" << error->response_type \
+ << " sequence:" << error->sequence; \
+ } \
+} while(false);
+#endif
+
+BackingStore::BackingStore(const gfx::Size& size,
+ xcb_connection_t* connection,
+ xcb_window_t window,
+ bool use_shared_memory)
+ : connection_(connection),
+ use_shared_memory_(use_shared_memory),
+ pixmap_(xcb_generate_id(connection)) {
+ XCB_CALL(xcb_create_pixmap, connection_, 32, pixmap, window, size.width(),
+ size.height());
+}
+
+BackingStore::~BackingStore() {
+ XCB_CALL(xcb_free_pixmap, pixmap_);
+}
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index eda2f1a..d17ab83 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -128,7 +128,10 @@ void BrowserRenderProcessHost::RegisterPrefs(PrefService* prefs) {
BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
: RenderProcessHost(profile),
visible_widgets_(0),
- backgrounded_(true) {
+ backgrounded_(true),
+ ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_(
+ base::TimeDelta::FromSeconds(5),
+ this, &BrowserRenderProcessHost::ClearTransportDIBCache)) {
DCHECK(host_id() >= 0); // We use a negative host_id_ in destruction.
widget_helper_ = new RenderWidgetHelper(host_id());
@@ -170,6 +173,8 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() {
NotificationService::current()->RemoveObserver(this,
NotificationType::USER_SCRIPTS_LOADED, NotificationService::AllSources());
+
+ ClearTransportDIBCache();
}
// When we're started with the --start-renderers-manually flag, we pop up a
@@ -605,6 +610,65 @@ bool BrowserRenderProcessHost::FastShutdownIfPossible() {
return true;
}
+// This is a platform specific function for mapping a transport DIB given its id
+TransportDIB* BrowserRenderProcessHost::MapTransportDIB(
+ TransportDIB::Id dib_id) {
+#if defined(OS_WIN)
+ // On Windows we need to duplicate the handle from the remote process
+ HANDLE section = win_util::GetSectionFromProcess(
+ dib_id.handle, GetRendererProcessHandle(), false /* read write */);
+ return TransportDIB::Map(section);
+#elif defined(OS_MACOSX)
+ // On OSX, the browser allocates all DIBs and keeps a file descriptor around
+ // for each.
+ return widget_helper_->MapTransportDIB(dib_id);
+#elif defined(OS_LINUX)
+ return TransportDIB::Map(dib_id);
+#endif // defined(OS_LINUX)
+}
+
+TransportDIB* BrowserRenderProcessHost::GetTransportDIB(
+ TransportDIB::Id dib_id) {
+ const std::map<TransportDIB::Id, TransportDIB*>::iterator
+ i = cached_dibs_.find(dib_id);
+ if (i != cached_dibs_.end()) {
+ cached_dibs_cleaner_.Reset();
+ return i->second;
+ }
+
+ TransportDIB* dib = MapTransportDIB(dib_id);
+ if (!dib)
+ return NULL;
+
+ if (cached_dibs_.size() >= MAX_MAPPED_TRANSPORT_DIBS) {
+ // Clean a single entry from the cache
+ std::map<TransportDIB::Id, TransportDIB*>::iterator smallest_iterator;
+ size_t smallest_size = std::numeric_limits<size_t>::max();
+
+ for (std::map<TransportDIB::Id, TransportDIB*>::iterator
+ i = cached_dibs_.begin(); i != cached_dibs_.end(); ++i) {
+ if (i->second->size() <= smallest_size)
+ smallest_iterator = i;
+ }
+
+ delete smallest_iterator->second;
+ cached_dibs_.erase(smallest_iterator);
+ }
+
+ cached_dibs_[dib_id] = dib;
+ cached_dibs_cleaner_.Reset();
+ return dib;
+}
+
+void BrowserRenderProcessHost::ClearTransportDIBCache() {
+ for (std::map<TransportDIB::Id, TransportDIB*>::iterator
+ i = cached_dibs_.begin(); i != cached_dibs_.end(); ++i) {
+ delete i->second;
+ }
+
+ cached_dibs_.clear();
+}
+
bool BrowserRenderProcessHost::Send(IPC::Message* msg) {
if (!channel_.get()) {
delete msg;
diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h
index be7e225..dad06b5 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -13,6 +13,8 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
+#include "base/timer.h"
+#include "chrome/common/transport_dib.h"
#include "chrome/browser/renderer_host/audio_renderer_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/notification_observer.h"
@@ -62,6 +64,7 @@ class BrowserRenderProcessHost : public RenderProcessHost,
virtual void WidgetHidden();
virtual void AddWord(const std::wstring& word);
virtual bool FastShutdownIfPossible();
+ virtual TransportDIB* GetTransportDIB(TransportDIB::Id dib_id);
// IPC::Channel::Sender via RenderProcessHost.
virtual bool Send(IPC::Message* msg);
@@ -99,6 +102,7 @@ class BrowserRenderProcessHost : public RenderProcessHost,
void OnClipboardReadText(std::wstring* result);
void OnClipboardReadAsciiText(std::string* result);
void OnClipboardReadHTML(std::wstring* markup, GURL* src_url);
+
void OnUpdatedCacheStats(const CacheManager::UsageStats& stats);
// Initialize support for visited links. Send the renderer process its initial
@@ -140,6 +144,20 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// The host of audio renderers in the renderer process.
scoped_refptr<AudioRendererHost> audio_renderer_host_;
+ // A map of transport DIB ids to cached TransportDIBs
+ std::map<TransportDIB::Id, TransportDIB*> cached_dibs_;
+ enum {
+ // This is the maximum size of |cached_dibs_|
+ MAX_MAPPED_TRANSPORT_DIBS = 3,
+ };
+
+ // Map a transport DIB from its Id and return it. Returns NULL on error.
+ TransportDIB* MapTransportDIB(TransportDIB::Id dib_id);
+
+ void ClearTransportDIBCache();
+ // This is used to clear our cache five seconds after the last use.
+ base::DelayTimer<BrowserRenderProcessHost> cached_dibs_cleaner_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserRenderProcessHost);
};
diff --git a/chrome/browser/renderer_host/mock_render_process_host.cc b/chrome/browser/renderer_host/mock_render_process_host.cc
index c345b59..dc33bc1 100644
--- a/chrome/browser/renderer_host/mock_render_process_host.cc
+++ b/chrome/browser/renderer_host/mock_render_process_host.cc
@@ -57,6 +57,18 @@ bool MockRenderProcessHost::Send(IPC::Message* msg) {
return true;
}
+TransportDIB* MockRenderProcessHost::GetTransportDIB(TransportDIB::Id dib_id) {
+#if defined(OS_WIN)
+ return TransportDIB::Map(dib_id.handle);
+#elif defined(OS_MACOSX)
+ // On Mac, TransportDIBs are always created in the browser, so we cannot map
+ // one from a dib_id.
+ return TransportDIB::Create(100 * 100 * 4, 0);
+#elif defined(OS_LINUX)
+ return TransportDIB::Map(dib_id);
+#endif
+}
+
void MockRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
}
diff --git a/chrome/browser/renderer_host/mock_render_process_host.h b/chrome/browser/renderer_host/mock_render_process_host.h
index d1ed58d..bfe49ee 100644
--- a/chrome/browser/renderer_host/mock_render_process_host.h
+++ b/chrome/browser/renderer_host/mock_render_process_host.h
@@ -35,6 +35,7 @@ class MockRenderProcessHost : public RenderProcessHost {
virtual void WidgetHidden();
virtual void AddWord(const std::wstring& word);
virtual bool FastShutdownIfPossible();
+ virtual TransportDIB* GetTransportDIB(TransportDIB::Id dib_id);
// IPC::Channel::Sender via RenderProcessHost.
virtual bool Send(IPC::Message* msg);
diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h
index 8b90b3d..4f8179c 100644
--- a/chrome/browser/renderer_host/render_process_host.h
+++ b/chrome/browser/renderer_host/render_process_host.h
@@ -11,6 +11,7 @@
#include "base/process.h"
#include "base/scoped_ptr.h"
#include "chrome/common/ipc_sync_channel.h"
+#include "chrome/common/transport_dib.h"
class Profile;
@@ -124,6 +125,15 @@ class RenderProcessHost : public IPC::Channel::Sender,
// Returns True if it was able to do fast shutdown.
virtual bool FastShutdownIfPossible() = 0;
+ // Transport DIB functions ---------------------------------------------------
+
+ // Return the TransportDIB for the given id. On Linux, this can involve
+ // mapping shared memory. On Mac, the shared memory is created in the browser
+ // process and the cached metadata is returned. On Windows, this involves
+ // duplicating the handle from the remote process. The RenderProcessHost
+ // still owns the returned DIB.
+ virtual TransportDIB* GetTransportDIB(TransportDIB::Id dib_id) = 0;
+
// Static management functions -----------------------------------------------
// Flag to run the renderer in process. This is primarily
diff --git a/chrome/browser/renderer_host/render_widget_helper.cc b/chrome/browser/renderer_host/render_widget_helper.cc
index a03bb1b..715a85b 100644
--- a/chrome/browser/renderer_host/render_widget_helper.cc
+++ b/chrome/browser/renderer_host/render_widget_helper.cc
@@ -56,6 +56,10 @@ RenderWidgetHelper::~RenderWidgetHelper() {
// The elements of pending_paints_ each hold an owning reference back to this
// object, so we should not be destroyed unless pending_paints_ is empty!
DCHECK(pending_paints_.empty());
+
+#if defined(OS_MACOSX)
+ ClearAllocatedDIBs();
+#endif
}
int RenderWidgetHelper::GetNextRoutingID() {
@@ -244,3 +248,58 @@ void RenderWidgetHelper::OnSimulateReceivedMessage(
if (host)
host->OnMessageReceived(message);
}
+
+#if defined(OS_MACOSX)
+TransportDIB* RenderWidgetHelper::MapTransportDIB(TransportDIB::Id dib_id) {
+ AutoLock locked(allocated_dibs_lock_);
+
+ const std::map<TransportDIB::Id, int>::iterator
+ i = allocated_dibs_.find(dib_id);
+ if (i == allocated_dibs_.end())
+ return NULL;
+
+ base::FileDescriptor fd(dup(i->second), true);
+ return TransportDIB::Map(fd);
+}
+
+void RenderWidgetHelper::AllocTransportDIB(
+ size_t size, IPC::Maybe<TransportDIB::Handle>* result) {
+ base::SharedMemory* shared_memory = new base::SharedMemory();
+ if (!shared_memory->Create(L"", false /* read write */,
+ false /* do not open existing */, size)) {
+ result->valid = false;
+ delete shared_memory;
+ return;
+ }
+
+ result->valid = true;
+ shared_memory->GiveToProcess(0 /* pid, not needed */, &result->value);
+
+ // Keep a copy of the file descriptor around
+ AutoLock locked(allocated_dibs_lock_);
+ allocated_dibs_[shared_memory->id()] = dup(result->value.fd);
+}
+
+void RenderWidgetHelper::FreeTransportDIB(TransportDIB::Id dib_id) {
+ AutoLock locked(allocated_dibs_lock_);
+
+ const std::map<TransportDIB::Id, int>::iterator
+ i = allocated_dibs_.find(dib_id);
+
+ if (i != allocated_dibs_.end()) {
+ close(i->second);
+ allocated_dibs_.erase(i);
+ } else {
+ DLOG(WARNING) << "Renderer asked us to free unknown transport DIB";
+ }
+}
+
+void RenderWidgetHelper::ClearAllocatedDIBs() {
+ for (std::map<TransportDIB::Id, int>::iterator
+ i = allocated_dibs_.begin(); i != allocated_dibs_.end(); ++i) {
+ close(i->second);
+ }
+
+ allocated_dibs_.clear();
+}
+#endif
diff --git a/chrome/browser/renderer_host/render_widget_helper.h b/chrome/browser/renderer_host/render_widget_helper.h
index 83cedb0..eb13ff0 100644
--- a/chrome/browser/renderer_host/render_widget_helper.h
+++ b/chrome/browser/renderer_host/render_widget_helper.h
@@ -1,4 +1,3 @@
-
// Copyright (c) 2006-2008 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.
@@ -12,7 +11,9 @@
#include "base/ref_counted.h"
#include "base/lock.h"
#include "base/waitable_event.h"
+#include "chrome/common/ipc_maybe.h"
#include "chrome/common/modal_dialog_event.h"
+#include "chrome/common/transport_dib.h"
namespace IPC {
class Message;
@@ -74,6 +75,15 @@ class ResourceDispatcherHost;
// GetBackingStore method is called, it will call WaitForPaintMsg if it has
// no backingstore.
//
+// TRANSPORT DIB CREATION
+//
+// On some platforms (currently the Mac) the renderer cannot create transport
+// DIBs because of sandbox limitations. Thus, it has to make synchronous IPCs
+// to the browser for them. Since these requests are synchronous, they cannot
+// terminate on the UI thread. Thus, in this case, this object performs the
+// allocation and maintains the set of allocated transport DIBs which the
+// renderers can refer to.
+//
class RenderWidgetHelper :
public base::RefCountedThreadSafe<RenderWidgetHelper> {
public:
@@ -99,6 +109,11 @@ class RenderWidgetHelper :
const base::TimeDelta& max_delay,
IPC::Message* msg);
+#if defined(OS_MACOSX)
+ // Given the id of a transport DIB, return a mapping to it or NULL on error.
+ TransportDIB* MapTransportDIB(TransportDIB::Id dib_id);
+#endif
+
// IO THREAD ONLY -----------------------------------------------------------
@@ -114,6 +129,14 @@ class RenderWidgetHelper :
ModalDialogEvent* modal_dialog_event);
void CreateNewWidget(int opener_id, bool activatable, int* route_id);
+#if defined(OS_MACOSX)
+ // Called on the IO thread to handle the allocation of a transport DIB
+ void AllocTransportDIB(size_t size, IPC::Maybe<TransportDIB::Handle>* result);
+
+ // Called on the IO thread to handle the freeing of a transport DIB
+ void FreeTransportDIB(TransportDIB::Id dib_id);
+#endif
+
private:
// A class used to proxy a paint message. PaintMsgProxy objects are created
// on the IO thread and destroyed on the UI thread.
@@ -141,6 +164,16 @@ class RenderWidgetHelper :
int new_render_process_host_id,
int new_request_id);
+#if defined(OS_MACOSX)
+ // Called on destruction to release all allocated transport DIBs
+ void ClearAllocatedDIBs();
+
+ // On OSX we keep file descriptors to all the allocated DIBs around until
+ // the renderer frees them.
+ Lock allocated_dibs_lock_;
+ std::map<TransportDIB::Id, int> allocated_dibs_;
+#endif
+
// A map of live paint messages. Must hold pending_paints_lock_ to access.
// The PaintMsgProxy objects are not owned by this map. (See PaintMsgProxy
// for details about how the lifetime of instances are managed.)
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index a3c3018..1bd81cd 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -424,10 +424,20 @@ void RenderWidgetHost::OnMsgPaintRect(
DCHECK(!params.bitmap_rect.IsEmpty());
DCHECK(!params.view_size.IsEmpty());
- // Paint the backing store. This will update it with the renderer-supplied
- // bits. The view will read out of the backing store later to actually draw
- // to the screen.
- PaintBackingStoreRect(params.bitmap, params.bitmap_rect, params.view_size);
+ const size_t size = params.bitmap_rect.height() *
+ params.bitmap_rect.width() * 4;
+ TransportDIB* dib = process_->GetTransportDIB(params.bitmap);
+ if (dib) {
+ if (dib->size() < size) {
+ DLOG(WARNING) << "Transport DIB too small for given rectangle";
+ process()->ReceivedBadMessage(ViewHostMsg_PaintRect__ID);
+ } else {
+ // Paint the backing store. This will update it with the renderer-supplied
+ // bits. The view will read out of the backing store later to actually draw
+ // to the screen.
+ PaintBackingStoreRect(dib, params.bitmap_rect, params.view_size);
+ }
+ }
// ACK early so we can prefetch the next PaintRect if there is a next one.
// This must be done AFTER we're done painting with the bitmap supplied by the
@@ -474,10 +484,20 @@ void RenderWidgetHost::OnMsgScrollRect(
DCHECK(!params.view_size.IsEmpty());
- // Scroll the backing store.
- ScrollBackingStoreRect(params.bitmap, params.bitmap_rect,
- params.dx, params.dy,
- params.clip_rect, params.view_size);
+ const size_t size = params.bitmap_rect.height() *
+ params.bitmap_rect.width() * 4;
+ TransportDIB* dib = process_->GetTransportDIB(params.bitmap);
+ if (dib) {
+ if (dib->size() < size) {
+ LOG(WARNING) << "Transport DIB too small for given rectangle";
+ process()->ReceivedBadMessage(ViewHostMsg_PaintRect__ID);
+ } else {
+ // Scroll the backing store.
+ ScrollBackingStoreRect(dib, params.bitmap_rect,
+ params.dx, params.dy,
+ params.clip_rect, params.view_size);
+ }
+ }
// ACK early so we can prefetch the next ScrollRect if there is a next one.
// This must be done AFTER we're done painting with the bitmap supplied by the
@@ -561,7 +581,7 @@ void RenderWidgetHost::OnMsgImeUpdateStatus(int control,
}
}
-void RenderWidgetHost::PaintBackingStoreRect(BitmapWireData bitmap,
+void RenderWidgetHost::PaintBackingStoreRect(TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
const gfx::Size& view_size) {
if (is_hidden_) {
@@ -590,7 +610,7 @@ void RenderWidgetHost::PaintBackingStoreRect(BitmapWireData bitmap,
}
}
-void RenderWidgetHost::ScrollBackingStoreRect(BitmapWireData bitmap,
+void RenderWidgetHost::ScrollBackingStoreRect(TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
int dx, int dy,
const gfx::Rect& clip_rect,
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index 48fc912..8c8f007 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -9,7 +9,6 @@
#include "base/gfx/size.h"
#include "base/timer.h"
-#include "chrome/common/bitmap_wire_data.h"
#include "chrome/common/ipc_channel.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
@@ -21,6 +20,7 @@ class BackingStore;
class PaintObserver;
class RenderProcessHost;
class RenderWidgetHostView;
+class TransportDIB;
class WebInputEvent;
class WebKeyboardEvent;
class WebMouseEvent;
@@ -262,14 +262,14 @@ class RenderWidgetHost : public IPC::Channel::Listener {
void OnMsgImeUpdateStatus(int control, const gfx::Rect& caret_rect);
// Paints the given bitmap to the current backing store at the given location.
- void PaintBackingStoreRect(BitmapWireData bitmap,
+ void PaintBackingStoreRect(TransportDIB* dib,
const gfx::Rect& bitmap_rect,
const gfx::Size& view_size);
// Scrolls the given |clip_rect| in the backing by the given dx/dy amount. The
- // |bitmap| and its corresponding location |bitmap_rect| in the backing store
+ // |dib| and its corresponding location |bitmap_rect| in the backing store
// is the newly painted pixels by the renderer.
- void ScrollBackingStoreRect(BitmapWireData bitmap,
+ void ScrollBackingStoreRect(TransportDIB* dib,
const gfx::Rect& bitmap_rect,
int dx, int dy,
const gfx::Rect& clip_rect,
diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc
index 4f0bfb6..8a31ec91 100644
--- a/chrome/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc
@@ -10,10 +10,6 @@
#include "chrome/common/render_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_POSIX)
-#include "skia/ext/platform_canvas.h"
-#endif
-
namespace {
// RenderWidgetHostProcess -----------------------------------------------------
@@ -22,9 +18,7 @@ class RenderWidgetHostProcess : public MockRenderProcessHost {
public:
explicit RenderWidgetHostProcess(Profile* profile)
: MockRenderProcessHost(profile),
-#if defined(OS_WIN)
current_paint_buf_(NULL),
-#endif
paint_msg_should_reply_(false),
paint_msg_reply_flags_(0) {
// DANGER! This is a hack. The RenderWidgetHost checks the channel to see
@@ -54,11 +48,7 @@ class RenderWidgetHostProcess : public MockRenderProcessHost {
const base::TimeDelta& max_delay,
IPC::Message* msg);
-#if defined(OS_WIN)
- scoped_ptr<base::SharedMemory> current_paint_buf_;
-#elif defined(OS_POSIX)
- skia::PlatformCanvas canvas;
-#endif
+ TransportDIB* current_paint_buf_;
// Set to true when WaitForPaintMsg should return a successful paint messaage
// reply. False implies timeout.
@@ -75,20 +65,10 @@ void RenderWidgetHostProcess::InitPaintRectParams(
ViewHostMsg_PaintRect_Params* params) {
// Create the shared backing store.
const int w = 100, h = 100;
+ const size_t pixel_size = w * h * 4;
-#if defined(OS_WIN)
- int pixel_size = w * h * 4;
-
- current_paint_buf_.reset(new base::SharedMemory());
- ASSERT_TRUE(current_paint_buf_->Create(std::wstring(), false, true,
- pixel_size));
-
- params->bitmap = current_paint_buf_->handle();
-#elif defined(OS_POSIX)
- ASSERT_TRUE(canvas.initialize(w, h, true));
- params->bitmap = canvas.getDevice()->accessBitmap(false);
-#endif
-
+ current_paint_buf_ = TransportDIB::Create(pixel_size, 0);
+ params->bitmap = current_paint_buf_->id();
params->bitmap_rect = gfx::Rect(0, 0, w, h);
params->view_size = gfx::Size(w, h);
params->flags = paint_msg_reply_flags_;
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index 8616e29..2215257 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -234,6 +234,12 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnNotifyAudioPacketReady)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetAudioVolume, OnGetAudioVolume)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetAudioVolume, OnSetAudioVolume)
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB,
+ OnAllocTransportDIB)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB,
+ OnFreeTransportDIB)
+#endif
IPC_MESSAGE_UNHANDLED(
handled = false)
IPC_END_MESSAGE_MAP_EX()
@@ -794,3 +800,15 @@ void ResourceMessageFilter::OnSetAudioVolume(
double left_channel, double right_channel) {
// TODO(hclam): delegate to AudioRendererHost and handle this message.
}
+
+#if defined(OS_MACOSX)
+void ResourceMessageFilter::OnAllocTransportDIB(
+ size_t size, IPC::Maybe<TransportDIB::Handle>* handle) {
+ render_widget_helper_->AllocTransportDIB(size, handle);
+}
+
+void ResourceMessageFilter::OnFreeTransportDIB(
+ TransportDIB::Id dib_id) {
+ render_widget_helper_->FreeTransportDIB(dib_id);
+}
+#endif
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index 85ad101..ef389a8 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -15,8 +15,10 @@
#include "chrome/browser/net/resolve_proxy_msg_helper.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/ipc_channel_proxy.h"
+#include "chrome/common/ipc_maybe.h"
#include "chrome/common/modal_dialog_event.h"
#include "chrome/common/notification_observer.h"
+#include "chrome/common/transport_dib.h"
#include "webkit/glue/cache_manager.h"
#if defined(OS_WIN)
@@ -167,7 +169,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnResourceTypeStats(const CacheManager::ResourceTypeStats& stats);
void OnResolveProxy(const GURL& url, IPC::Message* reply_msg);
-
+
// ResolveProxyMsgHelper::Delegate implementation:
virtual void OnResolveProxyCompleted(IPC::Message* reply_msg,
int result,
@@ -203,6 +205,11 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnSetAudioVolume(const IPC::Message& msg, int stream_id,
double left_channel, double right_channel);
+ // Browser side transport DIB allocation
+ void OnAllocTransportDIB(size_t size,
+ IPC::Maybe<TransportDIB::Handle>* result);
+ void OnFreeTransportDIB(TransportDIB::Id dib_id);
+
// We have our own clipboard service because we want to access the clipboard
// on the IO thread instead of forwarding (possibly synchronous) messages to
// the UI thread.
diff --git a/chrome/chrome.xcodeproj/project.pbxproj b/chrome/chrome.xcodeproj/project.pbxproj
index 8ab2f18..706b762 100644
--- a/chrome/chrome.xcodeproj/project.pbxproj
+++ b/chrome/chrome.xcodeproj/project.pbxproj
@@ -294,6 +294,7 @@
82FA32330F3A4CC400271C5A /* web_contents_view.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6CCB9F20F1EC32700106F0D /* web_contents_view.cc */; };
82FA32760F3A537C00271C5A /* web_contents_view_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 82FA32750F3A537C00271C5A /* web_contents_view_mac.mm */; };
82FA33460F3A7F6900271C5A /* render_widget_host_view_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 82FA33450F3A7F6900271C5A /* render_widget_host_view_mac.mm */; };
+ 8385551004565907D74AD2E0 /* transport_dib_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = F174BA4A5FF6B3DFC64105AD /* transport_dib_mac.cc */; };
844EA0870F3E0C3B00B0EF26 /* debugger_host_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 844EA0750F3E0C1000B0EF26 /* debugger_host_impl.cpp */; };
844EA0880F3E0C4500B0EF26 /* debugger_io_socket.cc in Sources */ = {isa = PBXBuildFile; fileRef = 844EA0780F3E0C1000B0EF26 /* debugger_io_socket.cc */; };
844EA08D0F3E0C5000B0EF26 /* debugger_node.cc in Sources */ = {isa = PBXBuildFile; fileRef = 844EA07A0F3E0C1000B0EF26 /* debugger_node.cc */; };
@@ -2779,6 +2780,7 @@
E4F324790EE5D17E002533CE /* referrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = referrer.cc; sourceTree = "<group>"; };
EA72C084DB3FC0FC595E525E /* template_url_model.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_model.cc; sourceTree = "<group>"; };
EA72CF50C0AB4492A644C703 /* url_fetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url_fetcher.h; sourceTree = "<group>"; };
+ F174BA4A5FF6B3DFC64105AD /* transport_dib_mac.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transport_dib_mac.cc; sourceTree = "<group>"; };
F4143C8B0F4B1D07008C8F73 /* renderer.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = renderer.sb; sourceTree = "<group>"; };
F60D7722C1302E1EC789B67A /* ssl_host_state.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ssl_host_state.cc; path = ssl/ssl_host_state.cc; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -3781,6 +3783,7 @@
4D7BFC0A0E9D4C9F009A6919 /* time_format.cc */,
4D7BFC0B0E9D4C9F009A6919 /* time_format.h */,
4D7BFC0C0E9D4C9F009A6919 /* time_format_unittest.cc */,
+ F174BA4A5FF6B3DFC64105AD /* transport_dib_mac.cc */,
E45076E40F153AB6003BE099 /* unzip.cc */,
E45076E30F153AB6003BE099 /* unzip.h */,
E45076E80F153B06003BE099 /* unzip_unittest.cc */,
@@ -5667,6 +5670,7 @@
4D7BFC970E9D4D3E009A6919 /* throb_animation.cc in Sources */,
4D7BFC9C0E9D4D46009A6919 /* thumbnail_score.cc in Sources */,
E45076AB0F153629003BE099 /* time_format.cc in Sources */,
+ 8385551004565907D74AD2E0 /* transport_dib_mac.cc in Sources */,
E45076E50F153AB6003BE099 /* unzip.cc in Sources */,
406DFE278638D6132B21B2C9 /* url_pattern.cc in Sources */,
E46C4B3F0F21095400B393B8 /* url_request_intercept_job.cc in Sources */,
diff --git a/chrome/common/bitmap_wire_data.h b/chrome/common/bitmap_wire_data.h
deleted file mode 100644
index c4e1edd..0000000
--- a/chrome/common/bitmap_wire_data.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2006-2008 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 CHROME_COMMON_BITMAP_WIRE_DATA_H_
-#define CHROME_COMMON_BITMAP_WIRE_DATA_H_
-
-#if defined(OS_POSIX)
-class SkBitmap;
-#endif
-
-// BitmapWireData is the type of the bitmap data which is carried from renderer
-// to browser over the wire.
-
-#if defined(OS_WIN)
-
-// On Windows, the bitmap data is carried out-of-band in a shared memory
-// segment. This is the handle to the shared memory. These handles are valid
-// only in the context of the renderer process.
-// TODO(agl): get a clarification on that last sentence. It doesn't make any
-// sense to me
-typedef HANDLE BitmapWireData;
-
-#elif defined(OS_POSIX)
-
-// On POSIX, we currently serialise the bitmap data over the wire. This will
-// change at some point when we too start using shared memory, but we wish to
-// use shared memory in a different way so this is a temporary work-around.
-// TODO(port): implement drawing with shared backing stores and replace this
-// with an IPC no-op type.
-typedef SkBitmap BitmapWireData;
-
-#endif // defined(OS_WIN)
-
-#endif // CHROME_COMMON_BITMAP_WIRE_DATA_H_
diff --git a/chrome/common/common.scons b/chrome/common/common.scons
index 06a9888..b2cc936 100644
--- a/chrome/common/common.scons
+++ b/chrome/common/common.scons
@@ -275,6 +275,21 @@ if not env.Bit('posix'):
'ipc_channel_posix.cc',
)
+if env.Bit('windows'):
+ input_files.Append(
+ 'transport_dib_win.cc'
+ )
+
+if env.Bit('linux'):
+ input_files.Append(
+ 'transport_dib_linux.cc'
+ )
+
+if env.Bit('mac'):
+ input_files.Append(
+ 'transport_dib_mac.cc'
+ )
+
if not env.Bit('mac'):
# TODO(port): This should be enabled for all platforms.
env.ChromeLibrary('common', input_files)
diff --git a/chrome/common/common.vcproj b/chrome/common/common.vcproj
index 8ac8d29..67a664e 100644
--- a/chrome/common/common.vcproj
+++ b/chrome/common/common.vcproj
@@ -537,7 +537,7 @@
RelativePath=".\notification_details.h"
>
</File>
- <File
+ <File
RelativePath=".\notification_observer.h"
>
</File>
@@ -742,6 +742,14 @@
>
</File>
<File
+ RelativePath=".\transport_dib.h"
+ >
+ </File>
+ <File
+ RelativePath=".\transport_dib_win.cc"
+ >
+ </File>
+ <File
RelativePath=".\unzip.cc"
>
</File>
diff --git a/chrome/common/ipc_maybe.h b/chrome/common/ipc_maybe.h
new file mode 100644
index 0000000..de45dc0
--- /dev/null
+++ b/chrome/common/ipc_maybe.h
@@ -0,0 +1,19 @@
+#ifndef CHROME_COMMON_MAYBE_H_
+#define CHROME_COMMON_MAYBE_H_
+
+namespace IPC {
+
+// The Maybe type can be used to avoid serialising a type when it's invalid.
+// This is most useful in conjunction with FileDescriptor, as there's no
+// possible invalid value which can be serialised (one can type to use -1, but
+// the IPC channel will fail). It may also be useful if the invalid value is
+// otherwise expensive to serialise.
+template<typename A>
+struct Maybe {
+ bool valid;
+ A value;
+};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_MAYBE_H_
diff --git a/chrome/common/ipc_message_utils.h b/chrome/common/ipc_message_utils.h
index ae42bb0..428c889 100644
--- a/chrome/common/ipc_message_utils.h
+++ b/chrome/common/ipc_message_utils.h
@@ -15,8 +15,10 @@
#if defined(OS_POSIX)
#include "chrome/common/file_descriptor_set_posix.h"
#endif
+#include "chrome/common/ipc_maybe.h"
#include "chrome/common/ipc_sync_message.h"
#include "chrome/common/thumbnail_score.h"
+#include "chrome/common/transport_dib.h"
#include "webkit/glue/cache_manager.h"
#include "webkit/glue/console_message_level.h"
#include "webkit/glue/find_in_page_request.h"
@@ -1045,6 +1047,55 @@ struct ParamTraits< Tuple6<A, B, C, D, E, F> > {
}
};
+#if defined(OS_WIN)
+template<>
+struct ParamTraits<TransportDIB::Id> {
+ typedef TransportDIB::Id param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.handle);
+ WriteParam(m, p.sequence_num);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return (ReadParam(m, iter, &r->handle) &&
+ ReadParam(m, iter, &r->sequence_num));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(L"TransportDIB(");
+ LogParam(p.handle, l);
+ l->append(L", ");
+ LogParam(p.sequence_num, l);
+ l->append(L")");
+ }
+};
+#endif
+
+template<typename A>
+struct ParamTraits<Maybe<A> > {
+ typedef struct Maybe<A> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.valid);
+ if (p.valid)
+ WriteParam(m, p.value);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ if (!ReadParam(m, iter, &r->valid))
+ return false;
+
+ if (r->valid)
+ return ReadParam(m, iter, &r->value);
+ return true;
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ if (p.valid) {
+ l->append(L"Just ");
+ ParamTraits<A>::Log(p.value, l);
+ } else {
+ l->append(L"Nothing");
+ }
+
+ }
+};
+
template <>
struct ParamTraits<webkit_glue::WebApplicationInfo> {
typedef webkit_glue::WebApplicationInfo param_type;
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 8c91097..e78970e 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -15,11 +15,11 @@
#include "base/shared_memory.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/common/accessibility.h"
-#include "chrome/common/bitmap_wire_data.h"
#include "chrome/common/filter_policy.h"
#include "chrome/common/ipc_message_utils.h"
#include "chrome/common/modal_dialog_event.h"
#include "chrome/common/page_transition_types.h"
+#include "chrome/common/transport_dib.h"
#include "googleurl/src/gurl.h"
#include "media/audio/audio_output.h"
#include "net/base/upload_data.h"
@@ -150,7 +150,7 @@ struct ViewHostMsg_PaintRect_Flags {
struct ViewHostMsg_PaintRect_Params {
// The bitmap to be painted into the rect given by bitmap_rect.
- BitmapWireData bitmap;
+ TransportDIB::Id bitmap;
// The position and size of the bitmap.
gfx::Rect bitmap_rect;
@@ -183,7 +183,7 @@ struct ViewHostMsg_PaintRect_Params {
// parameters to be reasonably put in a predefined IPC message.
struct ViewHostMsg_ScrollRect_Params {
// The bitmap to be painted into the rect exposed by scrolling.
- BitmapWireData bitmap;
+ TransportDIB::Id bitmap;
// The position and size of the bitmap.
gfx::Rect bitmap_rect;
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 02a9a43..f02f5cf 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -16,6 +16,8 @@
#include "base/gfx/native_widget_types.h"
#include "base/shared_memory.h"
#include "chrome/common/ipc_message_macros.h"
+#include "chrome/common/ipc_maybe.h"
+#include "chrome/common/transport_dib.h"
#include "skia/include/SkBitmap.h"
#include "webkit/glue/console_message_level.h"
#include "webkit/glue/dom_operations.h"
@@ -1168,4 +1170,19 @@ IPC_BEGIN_MESSAGES(ViewHost)
double /* left_channel */,
double /* right_channel */)
+#if defined(OS_MACOSX)
+ // On OSX, we cannot allocated shared memory from within the sandbox, so
+ // this call exists for the renderer to ask the browser to allocate memory
+ // on its behalf. We return a file descriptor to the POSIX shared memory.
+ IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_AllocTransportDIB,
+ size_t, /* bytes requested */
+ IPC::Maybe<TransportDIB::Handle> /* DIB */)
+
+ // Since the browser keeps handles to the allocated transport DIBs, this
+ // message is sent to tell the browser that it may release them when the
+ // renderer is finished with them.
+ IPC_MESSAGE_CONTROL1(ViewHostMsg_FreeTransportDIB,
+ TransportDIB::Id /* DIB id */)
+#endif
+
IPC_END_MESSAGES(ViewHost)
diff --git a/chrome/common/transport_dib.h b/chrome/common/transport_dib.h
new file mode 100644
index 0000000..e5fc009
--- /dev/null
+++ b/chrome/common/transport_dib.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2006-2009 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 CHROME_COMMON_TRANSPORT_DIB_H_
+#define CHROME_COMMON_TRANSPORT_DIB_H_
+
+#include "base/basictypes.h"
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#include "base/shared_memory.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+// -----------------------------------------------------------------------------
+// A TransportDIB is a block of memory that is used to transport pixels
+// from the renderer process to the browser.
+// -----------------------------------------------------------------------------
+class TransportDIB {
+ public:
+ ~TransportDIB();
+
+ // Two typedefs are defined. A Handle is the type which can be sent over
+ // the wire so that the remote side can map the transport DIB. The Id typedef
+ // is sufficient to identify the transport DIB when you know that the remote
+ // side already may have it mapped.
+#if defined(OS_WIN)
+ typedef HANDLE Handle;
+ // On Windows, the Id type includes a sequence number (epoch) to solve an ABA
+ // issue:
+ // 1) Process A creates a transport DIB with HANDLE=1 and sends to B.
+ // 2) Process B maps the transport DIB and caches 1 -> DIB.
+ // 3) Process A closes the transport DIB and creates a new one. The new DIB
+ // is also assigned HANDLE=1.
+ // 4) Process A sends the Handle to B, but B incorrectly believes that it
+ // already has it cached.
+ struct HandleAndSequenceNum {
+ HandleAndSequenceNum()
+ : handle(NULL),
+ sequence_num(0) {
+ }
+
+ HandleAndSequenceNum(HANDLE h, uint32 seq_num)
+ : handle(h),
+ sequence_num(seq_num) {
+ }
+
+ bool operator< (const HandleAndSequenceNum& other) const {
+ if (other.handle < handle)
+ return true;
+ if (other.sequence_num < sequence_num)
+ return true;
+ return false;
+ }
+
+ HANDLE handle;
+ uint32 sequence_num;
+ };
+ typedef HandleAndSequenceNum Id;
+#elif defined(OS_MACOSX)
+ typedef base::SharedMemoryHandle Handle;
+ // On Mac, the inode number of the backing file is used as an id.
+ typedef base::SharedMemoryId Id;
+#elif defined(OS_LINUX)
+ typedef int Handle; // These two ints are SysV IPC shared memory keys
+ typedef int Id;
+#endif
+
+ // Create a new TransportDIB
+ // size: the minimum size, in bytes
+ // epoch: Windows only: a global counter. See comment above.
+ // returns: NULL on failure
+ static TransportDIB* Create(size_t size, uint32 sequence_num);
+
+ // Map the referenced transport DIB. Returns NULL on failure.
+ static TransportDIB* Map(Handle transport_dib);
+
+ // Return a pointer to the shared memory
+ void* memory() const;
+
+ // Return the maximum size of the shared memory. This is not the amount of
+ // data which is valid, you have to know that via other means, this is simply
+ // the maximum amount that /could/ be valid.
+ size_t size() const { return size_; }
+
+ // Return the identifier which can be used to refer to this shared memory
+ // on the wire.
+ Id id() const;
+
+ // Return a handle to the underlying shared memory. This can be sent over the
+ // wire to give this transport DIB to another process.
+ Handle handle() const;
+
+ private:
+ TransportDIB();
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ explicit TransportDIB(base::SharedMemoryHandle dib);
+ base::SharedMemory shared_memory_;
+ uint32 sequence_num_;
+#elif defined(OS_LINUX)
+ int key_; // SysV shared memory id
+ void* address_; // mapped address
+#endif
+ size_t size_; // length, in bytes
+};
+
+class MessageLoop;
+
+#endif // CHROME_COMMON_TRANSPORT_DIB_H_
diff --git a/chrome/common/transport_dib_linux.cc b/chrome/common/transport_dib_linux.cc
new file mode 100644
index 0000000..adecf1d
--- /dev/null
+++ b/chrome/common/transport_dib_linux.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2009 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 <errno.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "base/logging.h"
+#include "chrome/common/transport_dib.h"
+
+// The shmat system call uses this as it's invalid return address
+static void *const kInvalidAddress = (void*) -1;
+
+TransportDIB::TransportDIB()
+ : key_(-1),
+ address_(kInvalidAddress),
+ size_(0) {
+}
+
+TransportDIB::~TransportDIB() {
+ if (address_ != kInvalidAddress) {
+ shmdt(address_);
+ address_ = kInvalidAddress;
+ }
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
+ // We use a mode of 0666 since the X server won't attach to memory which is
+ // 0600 since it can't know if it (as a root process) is being asked to map
+ // someone else's private shared memory region.
+ const int shmkey = shmget(IPC_PRIVATE, size, 0666);
+ if (shmkey == -1) {
+ DLOG(ERROR) << "Failed to create SysV shared memory region"
+ << " errno:" << errno;
+ return false;
+ }
+
+ void* address = shmat(shmkey, NULL /* desired address */, 0 /* flags */);
+ // Here we mark the shared memory for deletion. Since we attached it in the
+ // line above, it doesn't actually get deleted but, if we crash, this means
+ // that the kernel will automatically clean it up for us.
+ shmctl(shmkey, IPC_RMID, 0);
+ if (address == kInvalidAddress)
+ return false;
+
+ TransportDIB* dib = new TransportDIB;
+
+ dib->key_ = shmkey;
+ dib->address_ = address;
+ dib->size_ = size;
+ return dib;
+}
+
+TransportDIB* TransportDIB::Map(Handle shmkey) {
+ struct shmid_ds shmst;
+ if (shmctl(shmkey, IPC_STAT, &shmst) == -1)
+ return NULL;
+
+ void* address = shmat(shmkey, NULL /* desired address */, 0 /* flags */);
+ if (address == kInvalidAddress)
+ return NULL;
+
+ TransportDIB* dib = new TransportDIB;
+
+ dib->address_ = address;
+ dib->size_ = shmst.shm_segsz;
+ dib->key_ = shmkey;
+ return dib;
+}
+
+void* TransportDIB::memory() const {
+ DCHECK_NE(address_, kInvalidAddress);
+ return address_;
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return key_;
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return key_;
+}
diff --git a/chrome/common/transport_dib_mac.cc b/chrome/common/transport_dib_mac.cc
new file mode 100644
index 0000000..4fb67a7
--- /dev/null
+++ b/chrome/common/transport_dib_mac.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2009 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 "chrome/common/transport_dib.h"
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include "base/shared_memory.h"
+
+TransportDIB::TransportDIB()
+ : size_(0) {
+}
+
+TransportDIB::TransportDIB(TransportDIB::Handle dib)
+ : shared_memory_(dib, false /* read write */),
+ size_(0) {
+}
+
+TransportDIB::~TransportDIB() {
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
+ TransportDIB* dib = new TransportDIB;
+ if (!dib->shared_memory_.Create(L"", false /* read write */,
+ false /* do not open existing */, size)) {
+ delete dib;
+ return NULL;
+ }
+
+ dib->size_ = size;
+ return dib;
+}
+
+// static
+TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) {
+ TransportDIB* dib = new TransportDIB(handle);
+ struct stat st;
+ fstat(handle.fd, &st);
+
+ if (!dib->shared_memory_.Map(st.st_size)) {
+ delete dib;
+ close(handle.fd);
+ return false;
+ }
+
+ dib->size_ = st.st_size;
+
+ return dib;
+}
+
+void* TransportDIB::memory() const {
+ return shared_memory_.memory();
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return false;
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return shared_memory_.handle();
+}
diff --git a/chrome/common/transport_dib_win.cc b/chrome/common/transport_dib_win.cc
new file mode 100644
index 0000000..e9ab424
--- /dev/null
+++ b/chrome/common/transport_dib_win.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2009 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 <limits>
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/sys_info.h"
+#include "chrome/common/transport_dib.h"
+
+TransportDIB::TransportDIB() {
+}
+
+TransportDIB::~TransportDIB() {
+}
+
+TransportDIB::TransportDIB(HANDLE handle)
+ : shared_memory_(handle, false /* read write */) {
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
+ size_t allocation_granularity = base::SysInfo::VMAllocationGranularity();
+ size = size / allocation_granularity + 1;
+ size = size * allocation_granularity;
+
+ TransportDIB* dib = new TransportDIB;
+
+ if (!dib->shared_memory_.Create(L"", false /* read write */,
+ true /* open existing */, size)) {
+ delete dib;
+ return NULL;
+ }
+
+ dib->size_ = size;
+ dib->sequence_num_ = sequence_num;
+
+ return dib;
+}
+
+// static
+TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) {
+ TransportDIB* dib = new TransportDIB(handle);
+ if (!dib->shared_memory_.Map(0 /* map whole shared memory segment */)) {
+ DLOG(ERROR) << "Failed to map transport DIB"
+ << " handle:" << handle
+ << " error:" << GetLastError();
+ delete dib;
+ return NULL;
+ }
+
+ // There doesn't seem to be any way to find the size of the shared memory
+ // region! GetFileSize indicates that the handle is invalid. Thus, we
+ // conservatively set the size to the maximum and hope that the renderer
+ // isn't about to ask us to read off the end of the array.
+ dib->size_ = std::numeric_limits<size_t>::max();
+
+ return dib;
+}
+
+void* TransportDIB::memory() const {
+ return shared_memory_.memory();
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return shared_memory_.handle();
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return Id(shared_memory_.handle(), sequence_num_);
+}
diff --git a/chrome/renderer/render_process.cc b/chrome/renderer/render_process.cc
index 853693b..198f854f 100644
--- a/chrome/renderer/render_process.cc
+++ b/chrome/renderer/render_process.cc
@@ -25,6 +25,7 @@
#include "chrome/common/ipc_channel.h"
#include "chrome/common/ipc_message_utils.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/transport_dib.h"
#include "chrome/renderer/render_view.h"
#include "webkit/glue/webkit_glue.h"
@@ -36,7 +37,10 @@ bool RenderProcess::load_plugins_in_process_ = false;
RenderProcess::RenderProcess(const std::wstring& channel_name)
: render_thread_(channel_name),
- ALLOW_THIS_IN_INITIALIZER_LIST(clearer_factory_(this)) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_(
+ base::TimeDelta::FromSeconds(5),
+ this, &RenderProcess::ClearTransportDIBCache)),
+ sequence_number_(0) {
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i)
shared_mem_cache_[i] = NULL;
}
@@ -48,7 +52,7 @@ RenderProcess::~RenderProcess() {
// This race condition causes a crash when the renderer process is shutting
// down.
render_thread_.Stop();
- ClearSharedMemCache();
+ ClearTransportDIBCache();
}
// static
@@ -124,97 +128,144 @@ bool RenderProcess::ShouldLoadPluginsInProcess() {
return load_plugins_in_process_;
}
-// static
-base::SharedMemory* RenderProcess::AllocSharedMemory(size_t size) {
- self()->clearer_factory_.RevokeAll();
-
- base::SharedMemory* mem = self()->GetSharedMemFromCache(size);
- if (mem)
- return mem;
+// -----------------------------------------------------------------------------
+// Platform specific code for dealing with bitmap transport...
- // Round-up size to allocation granularity
- size_t allocation_granularity = base::SysInfo::VMAllocationGranularity();
- size = size / allocation_granularity + 1;
- size = size * allocation_granularity;
+// -----------------------------------------------------------------------------
+// Create a platform canvas object which renders into the given transport
+// memory.
+// -----------------------------------------------------------------------------
+static skia::PlatformCanvas* CanvasFromTransportDIB(
+ TransportDIB* dib, const gfx::Rect& rect) {
+#if defined(OS_WIN)
+ return new skia::PlatformCanvas(rect.width(), rect.height(), true,
+ dib->handle());
+#elif defined(OS_LINUX) || defined(OS_MACOSX)
+ return new skia::PlatformCanvas(rect.width(), rect.height(), true,
+ reinterpret_cast<uint8_t*>(dib->memory()));
+#endif
+}
- mem = new base::SharedMemory();
- if (!mem)
+TransportDIB* RenderProcess::CreateTransportDIB(size_t size) {
+#if defined(OS_WIN) || defined(OS_LINUX)
+ // Windows and Linux create transport DIBs inside the renderer
+ return TransportDIB::Create(size, sequence_number_++);
+#elif defined(OS_MACOSX) // defined(OS_WIN) || defined(OS_LINUX)
+ // Mac creates transport DIBs in the browser, so we need to do a sync IPC to
+ // get one.
+ IPC::Maybe<TransportDIB::Handle> mhandle;
+ IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, &mhandle);
+ if (!render_thread_.Send(msg))
return NULL;
- if (!mem->Create(L"", false, true, size)) {
- delete mem;
+ if (!mhandle.valid)
return NULL;
+ return TransportDIB::Map(mhandle.value);
+#endif // defined(OS_MACOSX)
+}
+
+void RenderProcess::FreeTransportDIB(TransportDIB* dib) {
+ if (!dib)
+ return;
+
+#if defined(OS_MACOSX)
+ // On Mac we need to tell the browser that it can drop a reference to the
+ // shared memory.
+ IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id());
+ render_thread_.Send(msg);
+#endif
+
+ delete dib;
+}
+
+// -----------------------------------------------------------------------------
+
+
+// static
+skia::PlatformCanvas* RenderProcess::GetDrawingCanvas(
+ TransportDIB** memory, const gfx::Rect& rect) {
+ const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width());
+ const size_t size = stride * rect.height();
+
+ if (!self()->GetTransportDIBFromCache(memory, size)) {
+ *memory = self()->CreateTransportDIB(size);
+ if (!*memory)
+ return false;
}
- return mem;
+ return CanvasFromTransportDIB(*memory, rect);
}
// static
-void RenderProcess::FreeSharedMemory(base::SharedMemory* mem) {
+void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) {
if (self()->PutSharedMemInCache(mem)) {
- self()->ScheduleCacheClearer();
+ self()->shared_mem_cache_cleaner_.Reset();
return;
}
- DeleteSharedMem(mem);
-}
-// static
-void RenderProcess::DeleteSharedMem(base::SharedMemory* mem) {
- delete mem;
+ self()->FreeTransportDIB(mem);
}
-base::SharedMemory* RenderProcess::GetSharedMemFromCache(size_t size) {
+bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem,
+ size_t size) {
// look for a cached object that is suitable for the requested size.
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
- base::SharedMemory* mem = shared_mem_cache_[i];
- if (mem && mem->max_size() >= size) {
+ if (shared_mem_cache_[i] &&
+ size <= shared_mem_cache_[i]->size()) {
+ *mem = shared_mem_cache_[i];
shared_mem_cache_[i] = NULL;
- return mem;
+ return true;
}
}
- return NULL;
+
+ return false;
}
-bool RenderProcess::PutSharedMemInCache(base::SharedMemory* mem) {
+int RenderProcess::FindFreeCacheSlot(size_t size) {
// simple algorithm:
// - look for an empty slot to store mem, or
- // - if full, then replace any existing cache entry that is smaller than the
- // given shared memory object.
+ // - if full, then replace smallest entry which is smaller than |size|
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
- if (!shared_mem_cache_[i]) {
- shared_mem_cache_[i] = mem;
- return true;
- }
+ if (shared_mem_cache_[i] == NULL)
+ return i;
}
- for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
- base::SharedMemory* cached_mem = shared_mem_cache_[i];
- if (cached_mem->max_size() < mem->max_size()) {
- shared_mem_cache_[i] = mem;
- DeleteSharedMem(cached_mem);
- return true;
+
+ size_t smallest_size = size;
+ int smallest_index = -1;
+
+ for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) {
+ const size_t entry_size = shared_mem_cache_[i]->size();
+ if (entry_size < smallest_size) {
+ smallest_size = entry_size;
+ smallest_index = i;
}
}
- return false;
+
+ if (smallest_index != -1) {
+ FreeTransportDIB(shared_mem_cache_[smallest_index]);
+ shared_mem_cache_[smallest_index] = NULL;
+ }
+
+ return smallest_index;
}
-void RenderProcess::ClearSharedMemCache() {
+bool RenderProcess::PutSharedMemInCache(TransportDIB* mem) {
+ const int slot = FindFreeCacheSlot(mem->size());
+ if (slot == -1)
+ return false;
+
+ shared_mem_cache_[slot] = mem;
+ return true;
+}
+
+void RenderProcess::ClearTransportDIBCache() {
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
if (shared_mem_cache_[i]) {
- DeleteSharedMem(shared_mem_cache_[i]);
+ FreeTransportDIB(shared_mem_cache_[i]);
shared_mem_cache_[i] = NULL;
}
}
}
-void RenderProcess::ScheduleCacheClearer() {
- // If we already have a deferred clearer, then revoke it so we effectively
- // delay cache clearing until idle for our desired interval.
- clearer_factory_.RevokeAll();
-
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- clearer_factory_.NewRunnableMethod(&RenderProcess::ClearSharedMemCache),
- 5000 /* 5 seconds */);
-}
-
void RenderProcess::Cleanup() {
// TODO(port)
// Try and limit what we pull in for our non-Win unit test bundle
diff --git a/chrome/renderer/render_process.h b/chrome/renderer/render_process.h
index 6ba0905..9c4cabe 100644
--- a/chrome/renderer/render_process.h
+++ b/chrome/renderer/render_process.h
@@ -5,13 +5,17 @@
#ifndef CHROME_RENDERER_RENDER_PROCESS_H__
#define CHROME_RENDERER_RENDER_PROCESS_H__
+#include "base/timer.h"
#include "chrome/common/child_process.h"
#include "chrome/renderer/render_thread.h"
+#include "skia/ext/platform_canvas.h"
-namespace base {
- class SharedMemory;
+namespace gfx {
+class Rect;
}
+class TransportDIB;
+
// Represents the renderer end of the browser<->renderer connection. The
// opposite end is the RenderProcessHost. This is a singleton object for
// each renderer.
@@ -23,19 +27,19 @@ class RenderProcess : public ChildProcess {
// Returns true if plugins should be loaded in-process.
static bool ShouldLoadPluginsInProcess();
- // Allocates shared memory. When no longer needed, you should pass the
- // SharedMemory pointer to FreeSharedMemory so it can be recycled. The size
- // reported in the resulting SharedMemory object will be greater than or
- // equal to the requested size. This method returns NULL if unable to
- // allocate memory for some reason.
- static base::SharedMemory* AllocSharedMemory(size_t size);
+ // Get a canvas suitable for drawing and transporting to the browser
+ // memory: (output) the transport DIB memory
+ // rect: the rectangle which will be painted, use for sizing the canvas
+ // returns: NULL on error
+ //
+ // When no longer needed, you should pass the TransportDIB to
+ // ReleaseTransportDIB so that it can be recycled.
+ static skia::PlatformCanvas* GetDrawingCanvas(
+ TransportDIB** memory, const gfx::Rect& rect);
// Frees shared memory allocated by AllocSharedMemory. You should only use
// this function to free the SharedMemory object.
- static void FreeSharedMemory(base::SharedMemory* mem);
-
- // Deletes the shared memory allocated by AllocSharedMemory.
- static void DeleteSharedMem(base::SharedMemory* mem);
+ static void ReleaseTransportDIB(TransportDIB* memory);
private:
friend class ChildProcessFactory<RenderProcess>;
@@ -50,21 +54,28 @@ class RenderProcess : public ChildProcess {
static ChildProcess* ClassFactory(const std::wstring& channel_name);
- // Look in the shared memory cache for a suitable object to reuse. Returns
- // NULL if there is none.
- base::SharedMemory* GetSharedMemFromCache(size_t size);
+ // Look in the shared memory cache for a suitable object to reuse.
+ // result: (output) the memory found
+ // size: the resulting memory will be >= this size, in bytes
+ // returns: false if a suitable DIB memory could not be found
+ bool GetTransportDIBFromCache(TransportDIB** result, size_t size);
- // Maybe put the given shared memory into the shared memory cache. Returns
+ // Maybe put the given shared memory into the shared memory cache. Returns
// true if the SharedMemory object was stored in the cache; otherwise, false
// is returned.
- bool PutSharedMemInCache(base::SharedMemory* mem);
+ bool PutSharedMemInCache(TransportDIB* memory);
- void ClearSharedMemCache();
+ void ClearTransportDIBCache();
- // We want to lazily clear the shared memory cache if no one has requested
- // memory. This methods are used to schedule a deferred call to
- // RenderProcess::ClearSharedMemCache.
- void ScheduleCacheClearer();
+ // Return the index of a free cache slot in which to install a transport DIB
+ // of the given size. If all entries in the cache are larger than the given
+ // size, this doesn't free any slots and returns -1.
+ int FindFreeCacheSlot(size_t size);
+
+ // Create a new transport DIB of, at least, the given size. Return NULL on
+ // error.
+ TransportDIB* CreateTransportDIB(size_t size);
+ void FreeTransportDIB(TransportDIB*);
// ChildProcess implementation
virtual void Cleanup();
@@ -74,10 +85,13 @@ class RenderProcess : public ChildProcess {
// A very simplistic and small cache. If an entry in this array is non-null,
// then it points to a SharedMemory object that is available for reuse.
- base::SharedMemory* shared_mem_cache_[2];
+ TransportDIB* shared_mem_cache_[2];
+
+ // This DelayTimer cleans up our cache 5 seconds after the last use.
+ base::DelayTimer<RenderProcess> shared_mem_cache_cleaner_;
- // This factory is used to lazily invoke ClearSharedMemCache.
- ScopedRunnableMethodFactory<RenderProcess> clearer_factory_;
+ // TransportDIB sequence number
+ uint32 sequence_number_;
static bool load_plugins_in_process_;
diff --git a/chrome/renderer/render_process_unittest.cc b/chrome/renderer/render_process_unittest.cc
index 0303d40..7b7b7c6 100644
--- a/chrome/renderer/render_process_unittest.cc
+++ b/chrome/renderer/render_process_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/gfx/rect.h"
#include "base/sys_info.h"
#include "base/string_util.h"
#include "chrome/renderer/render_process.h"
@@ -24,11 +25,14 @@ class RenderProcessTest : public testing::Test {
};
-TEST_F(RenderProcessTest, TestSharedMemoryAllocOne) {
- size_t size = base::SysInfo::VMAllocationGranularity();
- base::SharedMemory* mem = RenderProcess::AllocSharedMemory(size);
- ASSERT_TRUE(mem);
- RenderProcess::FreeSharedMemory(mem);
+TEST_F(RenderProcessTest, TestTransportDIBAllocation) {
+ const gfx::Rect rect(0, 0, 100, 100);
+ TransportDIB* dib;
+ skia::PlatformCanvas* canvas = RenderProcess::GetDrawingCanvas(&dib, rect);
+ ASSERT_TRUE(dib);
+ ASSERT_TRUE(canvas);
+ RenderProcess::ReleaseTransportDIB(dib);
+ delete canvas;
}
} // namespace
diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc
index 04f16f1..7782fd5 100644
--- a/chrome/renderer/render_widget.cc
+++ b/chrome/renderer/render_widget.cc
@@ -11,6 +11,7 @@
#include "base/scoped_ptr.h"
#include "build/build_config.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/transport_dib.h"
#include "chrome/renderer/render_process.h"
#include "skia/ext/platform_canvas.h"
@@ -104,11 +105,11 @@ RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable)
RenderWidget::~RenderWidget() {
DCHECK(!webwidget_) << "Leaking our WebWidget!";
if (current_paint_buf_) {
- RenderProcess::FreeSharedMemory(current_paint_buf_);
+ RenderProcess::ReleaseTransportDIB(current_paint_buf_);
current_paint_buf_ = NULL;
}
if (current_scroll_buf_) {
- RenderProcess::FreeSharedMemory(current_scroll_buf_);
+ RenderProcess::ReleaseTransportDIB(current_scroll_buf_);
current_scroll_buf_ = NULL;
}
RenderProcess::ReleaseProcess();
@@ -297,20 +298,21 @@ void RenderWidget::OnPaintRectAck() {
// If we sent a PaintRect message with a zero-sized bitmap, then
// we should have no current paint buf.
if (current_paint_buf_) {
- RenderProcess::FreeSharedMemory(current_paint_buf_);
+ RenderProcess::ReleaseTransportDIB(current_paint_buf_);
current_paint_buf_ = NULL;
}
+
// Continue painting if necessary...
DoDeferredPaint();
}
void RenderWidget::OnScrollRectAck() {
-#if defined(OS_WIN)
DCHECK(scroll_reply_pending());
- RenderProcess::FreeSharedMemory(current_scroll_buf_);
- current_scroll_buf_ = NULL;
-#endif
+ if (current_scroll_buf_) {
+ RenderProcess::ReleaseTransportDIB(current_scroll_buf_);
+ current_scroll_buf_ = NULL;
+ }
// Continue scrolling if necessary...
DoDeferredScroll();
@@ -379,13 +381,6 @@ void RenderWidget::PaintRect(const gfx::Rect& rect,
DidPaint();
}
-// static
-size_t RenderWidget::GetPaintBufSize(const gfx::Rect& rect) {
- // TODO(darin): protect against overflow
- const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width());
- return stride * rect.height();
-}
-
void RenderWidget::DoDeferredPaint() {
if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
return;
@@ -407,37 +402,23 @@ void RenderWidget::DoDeferredPaint() {
paint_rect_ = gfx::Rect();
// Compute a buffer for painting and cache it.
-#if defined(OS_WIN)
- current_paint_buf_ =
- RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
- if (!current_paint_buf_) {
+ skia::PlatformCanvas* canvas =
+ RenderProcess::GetDrawingCanvas(&current_paint_buf_, damaged_rect);
+ if (!canvas) {
NOTREACHED();
return;
}
- skia::PlatformCanvasWin canvas(damaged_rect.width(), damaged_rect.height(),
- true, current_paint_buf_->handle());
-#elif defined(OS_POSIX)
- // Currently, on POSIX, we are serialising the bitmap data over the IPC
- // channel.
- skia::PlatformCanvas canvas(damaged_rect.width(), damaged_rect.height(),
- true);
-#endif // defined(OS_POSIX)
- PaintRect(damaged_rect, &canvas);
+ PaintRect(damaged_rect, canvas);
ViewHostMsg_PaintRect_Params params;
params.bitmap_rect = damaged_rect;
params.view_size = size_;
params.plugin_window_moves = plugin_window_moves_;
params.flags = next_paint_flags_;
+ params.bitmap = current_paint_buf_->id();
-#if defined(OS_WIN)
- // Windows passes a HANDLE to the shared memory over IPC
- params.bitmap = current_paint_buf_->handle();
-#elif defined(OS_POSIX)
- // POSIX currently passes the data itself.
- params.bitmap = canvas.getDevice()->accessBitmap(false);
-#endif // defined(OS_WIN)
+ delete canvas;
plugin_window_moves_.clear();
@@ -498,21 +479,12 @@ void RenderWidget::DoDeferredScroll() {
// In case the scroll offset exceeds the width/height of the scroll rect
damaged_rect = scroll_rect_.Intersect(damaged_rect);
-#if defined(OS_WIN)
- current_scroll_buf_ =
- RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
- if (!current_scroll_buf_) {
+ skia::PlatformCanvas* canvas =
+ RenderProcess::GetDrawingCanvas(&current_scroll_buf_, damaged_rect);
+ if (!canvas) {
NOTREACHED();
return;
}
- skia::PlatformCanvasWin canvas(damaged_rect.width(), damaged_rect.height(),
- true, current_scroll_buf_->handle());
-#elif defined(OS_POSIX)
- // Currently, on POSIX, we are serialising the bitmap data over the IPC
- // channel.
- skia::PlatformCanvas canvas(damaged_rect.width(), damaged_rect.height(),
- true);
-#endif // defined(OS_POSIX)
// Set these parameters before calling Paint, since that could result in
// further invalidates (uncommon).
@@ -523,22 +495,16 @@ void RenderWidget::DoDeferredScroll() {
params.clip_rect = scroll_rect_;
params.view_size = size_;
params.plugin_window_moves = plugin_window_moves_;
-
-#if defined(OS_WIN)
- // Windows passes a HANDLE to the shared memory over IPC
- params.bitmap = current_scroll_buf_->handle();
-#elif defined(OS_POSIX)
- // POSIX currently passes the data itself.
- params.bitmap = canvas.getDevice()->accessBitmap(false);
-#endif // defined(OS_WIN)
+ params.bitmap = current_scroll_buf_->id();
plugin_window_moves_.clear();
// Mark the scroll operation as no longer pending.
scroll_rect_ = gfx::Rect();
- PaintRect(damaged_rect, &canvas);
+ PaintRect(damaged_rect, canvas);
Send(new ViewHostMsg_ScrollRect(routing_id_, params));
+ delete canvas;
UpdateIME();
}
diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h
index 4153ce0..b0c4b11 100644
--- a/chrome/renderer/render_widget.h
+++ b/chrome/renderer/render_widget.h
@@ -14,6 +14,7 @@
#include "base/ref_counted.h"
#include "base/shared_memory.h"
#include "chrome/common/ipc_channel.h"
+#include "chrome/renderer/render_process.h"
#include "skia/ext/platform_canvas.h"
#include "webkit/glue/webwidget_delegate.h"
@@ -86,10 +87,6 @@ class RenderWidget : public IPC::Channel::Listener,
// Close the underlying WebWidget.
void Close();
- // Get the size of the paint buffer for the given rectangle, rounding up to
- // the allocation granularity of the system.
- static size_t GetPaintBufSize(const gfx::Rect& rect);
-
protected:
// Friend RefCounted so that the dtor can be non-public. Using this class
// without ref-counting is an error.
@@ -192,10 +189,10 @@ class RenderWidget : public IPC::Channel::Listener,
// The size of the RenderWidget.
gfx::Size size_;
- // Shared memory handles that are currently in use to transfer an image to
- // the browser.
- base::SharedMemory* current_paint_buf_;
- base::SharedMemory* current_scroll_buf_;
+ // Transport DIBs that are currently in use to transfer an image to the
+ // browser.
+ TransportDIB* current_paint_buf_;
+ TransportDIB* current_scroll_buf_;
// The smallest bounding rectangle that needs to be re-painted. This is non-
// empty if a paint event is pending.
diff --git a/chrome/renderer/renderer_glue.cc b/chrome/renderer/renderer_glue.cc
index a8a9486..a65f326 100644
--- a/chrome/renderer/renderer_glue.cc
+++ b/chrome/renderer/renderer_glue.cc
@@ -95,7 +95,9 @@ void ScopedClipboardWriterGlue::WriteBitmap(const SkBitmap& bitmap) {
gfx::Size size(bitmap.width(), bitmap.height());
// Allocate a shared memory buffer to hold the bitmap bits
- shared_buf_ = RenderProcess::AllocSharedMemory(buf_size);
+ shared_buf_ = new base::SharedMemory;
+ shared_buf_->Create(L"", false /* read write */, true /* open existing */,
+ buf_size);
if (!shared_buf_ || !shared_buf_->Map(buf_size)) {
NOTREACHED();
return;
@@ -134,7 +136,7 @@ ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() {
if (shared_buf_) {
g_render_thread->Send(
new ViewHostMsg_ClipboardWriteObjectsSync(objects_));
- RenderProcess::FreeSharedMemory(shared_buf_);
+ delete shared_buf_;
return;
}
#endif
diff --git a/skia/ext/bitmap_platform_device_linux.h b/skia/ext/bitmap_platform_device_linux.h
index cfc72e2..d26c50d 100644
--- a/skia/ext/bitmap_platform_device_linux.h
+++ b/skia/ext/bitmap_platform_device_linux.h
@@ -59,9 +59,9 @@ class BitmapPlatformDeviceLinux : public PlatformDeviceLinux {
class BitmapPlatformDeviceLinuxData;
public:
- /// Static constructor. I don't understand this, it's just a copy of the mac
static BitmapPlatformDeviceLinux* Create(int width, int height,
bool is_opaque);
+ // This doesn't take ownership of |data|
static BitmapPlatformDeviceLinux* Create(int width, int height,
bool is_opaque, uint8_t* data);
static BitmapPlatformDeviceLinux* Create(int width, int height,
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc
index 9b4beb0..a0f0bf1 100755
--- a/skia/ext/bitmap_platform_device_mac.cc
+++ b/skia/ext/bitmap_platform_device_mac.cc
@@ -168,24 +168,26 @@ BitmapPlatformDeviceMac* BitmapPlatformDeviceMac::Create(CGContextRef context,
#endif
}
- CGColorSpaceRef color_space =
- CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
- // allocate a bitmap context with 4 components per pixel (BGRA). Apple
- // recommends these flags for improved CG performance.
- CGContextRef bitmap_context =
- CGBitmapContextCreate(data, width, height, 8, width*4,
- color_space,
- kCGImageAlphaPremultipliedFirst |
- kCGBitmapByteOrder32Host);
-
- // Change the coordinate system to match WebCore's
- CGContextTranslateCTM(bitmap_context, 0, height);
- CGContextScaleCTM(bitmap_context, 1.0, -1.0);
- CGColorSpaceRelease(color_space);
+ if (!context) {
+ CGColorSpaceRef color_space =
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ // allocate a bitmap context with 4 components per pixel (BGRA). Apple
+ // recommends these flags for improved CG performance.
+ context =
+ CGBitmapContextCreate(data, width, height, 8, width*4,
+ color_space,
+ kCGImageAlphaPremultipliedFirst |
+ kCGBitmapByteOrder32Host);
+
+ // Change the coordinate system to match WebCore's
+ CGContextTranslateCTM(context, 0, height);
+ CGContextScaleCTM(context, 1.0, -1.0);
+ CGColorSpaceRelease(color_space);
+ }
// The device object will take ownership of the graphics context.
return new BitmapPlatformDeviceMac(
- new BitmapPlatformDeviceMacData(bitmap_context), bitmap);
+ new BitmapPlatformDeviceMacData(context), bitmap);
}
// The device will own the bitmap, which corresponds to also owning the pixel
diff --git a/skia/ext/platform_canvas_linux.cc b/skia/ext/platform_canvas_linux.cc
index d436fd7..422693c 100644
--- a/skia/ext/platform_canvas_linux.cc
+++ b/skia/ext/platform_canvas_linux.cc
@@ -21,6 +21,13 @@ PlatformCanvasLinux::PlatformCanvasLinux(int width, int height, bool is_opaque)
SK_CRASH();
}
+PlatformCanvasLinux::PlatformCanvasLinux(int width, int height, bool is_opaque,
+ uint8_t* data)
+ : SkCanvas() {
+ if (!initialize(width, height, is_opaque, data))
+ SK_CRASH();
+}
+
PlatformCanvasLinux::~PlatformCanvasLinux() {
}
@@ -34,6 +41,18 @@ bool PlatformCanvasLinux::initialize(int width, int height, bool is_opaque) {
return true;
}
+bool PlatformCanvasLinux::initialize(int width, int height, bool is_opaque,
+ uint8_t* data) {
+ SkDevice* device =
+ BitmapPlatformDeviceLinux::Create(width, height, is_opaque, data);
+ if (!device)
+ return false;
+
+ setDevice(device);
+ device->unref(); // was created with refcount 1, and setDevice also refs
+ return true;
+}
+
PlatformDeviceLinux& PlatformCanvasLinux::getTopPlatformDevice() const {
// All of our devices should be our special PlatformDevice.
SkCanvas::LayerIter iter(const_cast<PlatformCanvasLinux*>(this), false);
diff --git a/skia/ext/platform_canvas_linux.h b/skia/ext/platform_canvas_linux.h
index 5782284..1cf87a8 100644
--- a/skia/ext/platform_canvas_linux.h
+++ b/skia/ext/platform_canvas_linux.h
@@ -30,6 +30,7 @@ class PlatformCanvasLinux : public SkCanvas {
// For two-part init, call if you use the no-argument constructor above
bool initialize(int width, int height, bool is_opaque);
+ bool initialize(int width, int height, bool is_opaque, uint8_t* data);
// Returns the platform device pointer of the topmost rect with a non-empty
// clip. Both the windows and mac versions have an equivalent of this method;
diff --git a/skia/ext/platform_canvas_mac.cc b/skia/ext/platform_canvas_mac.cc
index 380a78b..9ada02d 100755
--- a/skia/ext/platform_canvas_mac.cc
+++ b/skia/ext/platform_canvas_mac.cc
@@ -25,6 +25,14 @@ PlatformCanvasMac::PlatformCanvasMac(int width,
initialize(width, height, is_opaque);
}
+PlatformCanvasMac::PlatformCanvasMac(int width,
+ int height,
+ bool is_opaque,
+ uint8_t* data)
+ : SkCanvas() {
+ initialize(width, height, is_opaque, data);
+}
+
PlatformCanvasMac::~PlatformCanvasMac() {
}
@@ -40,6 +48,33 @@ bool PlatformCanvasMac::initialize(int width,
return true;
}
+bool PlatformCanvasMac::initialize(int width,
+ int height,
+ bool is_opaque,
+ uint8_t* data) {
+ CGContextRef context = NULL;
+ CGColorSpaceRef colorSpace;
+
+ colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ context = CGBitmapContextCreate(
+ data, width, height, 8 /* bits per plane */, 4 * width /* stride */,
+ colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
+ CGColorSpaceRelease(colorSpace);
+ if (!context)
+ return false;
+ // Change the coordinate system to match WebCore's
+ CGContextTranslateCTM(context, 0, height);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ SkDevice* device = createPlatformDevice(width, height, is_opaque, context);
+ if (!device)
+ return false;
+
+ setDevice(device);
+ device->unref(); // was created with refcount 1, and setDevice also refs
+ return true;
+}
+
CGContextRef PlatformCanvasMac::beginPlatformPaint() {
return getTopPlatformDevice().GetBitmapContext();
}
diff --git a/skia/ext/platform_canvas_mac.h b/skia/ext/platform_canvas_mac.h
index da745f8..935bdc6 100755
--- a/skia/ext/platform_canvas_mac.h
+++ b/skia/ext/platform_canvas_mac.h
@@ -25,10 +25,13 @@ class PlatformCanvasMac : public SkCanvas {
PlatformCanvasMac(int width, int height, bool is_opaque);
PlatformCanvasMac(int width, int height, bool is_opaque,
CGContextRef context);
+ PlatformCanvasMac(int width, int height, bool is_opaque,
+ uint8_t* context);
virtual ~PlatformCanvasMac();
// For two-part init, call if you use the no-argument constructor above
bool initialize(int width, int height, bool is_opaque);
+ bool initialize(int width, int height, bool is_opaque, uint8_t* data);
// These calls should surround calls to platform drawing routines. The CG
// context returned by beginPlatformPaint is the one that can be used to