diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-20 02:00:04 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-20 02:00:04 +0000 |
commit | e68e62fa169c45bd779bfe890aa4fcdaa24d267d (patch) | |
tree | efdb18adec880e7f780d8cde4e12893d3a20234f /chrome/browser/renderer_host | |
parent | 7fe07d0726bad485fa40150aa9f7cecb1318217e (diff) | |
download | chromium_src-e68e62fa169c45bd779bfe890aa4fcdaa24d267d.zip chromium_src-e68e62fa169c45bd779bfe890aa4fcdaa24d267d.tar.gz chromium_src-e68e62fa169c45bd779bfe890aa4fcdaa24d267d.tar.bz2 |
Bitmap transport
This patch reworks bitmap transport on all platforms. Linux and Mac
are switched from serialising bitmaps over the IPC channel to using
shared memory. All platforms gain a shared memory mapping cache on the
host side.
The concept of a TransportDIB (device independent bitmap) is added to
encapsulate most of the platform specifics.
On Linux, we use SysV shared memory. This is because X shared pixmaps,
which predate POSIX SHM, can only use SysV. By using SysV between
renderer and browser, we open up the possibility to map the shared
memory directly from the renderer to the X server.
On Mac, we use POSIX shared memory. However, since this needs
filesystem access and the Mac renderer is sandboxed from the
filesystem, we add two new messages from renderer -> browser:
The first, AllocTransportDIB, synchronously creates a transport DIB in
the browser and passes a handle back to the renderer. The second,
FreeTransportDIB, asynchronously, notifies the browser that it may
close its handle to the shared memory region.
On Mac, the shared memory regions are identified by their inode
numbers on the wire. This means that the browser must keep handles
open to all the allocated shared memory regions (since an inode number
is insufficient to map the region). The alternative design is that the
renderer passes the file descriptor with each paint operation. Since
passing file descriptors is special case in the code, I felt that it
would be best to minimise their use. Creating and freeing transport
DIBs are relatively rare operations relative to paints and scrolls.
On Windows, most of the code remains the same, except that Windows now
uses the mapping cache added in this patch. This allows the browser to
maintain a shared memory mapping for a transport DIB over several
paints. Previously it mapped and unmapped for every operation, causing
lots of TLB and VM churn.
Review URL: http://codereview.chromium.org/21485
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10071 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/renderer_host')
17 files changed, 324 insertions, 76 deletions
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. |