diff options
author | iyengar@google.com <iyengar@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-06 05:30:12 +0000 |
---|---|---|
committer | iyengar@google.com <iyengar@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-06 05:30:12 +0000 |
commit | ec7dc1160836695462ee7311d4c02f2c2f61350e (patch) | |
tree | 9fb3d234403ee1b52ca24f603dbedede952a4948 | |
parent | e5d478012a5ee0765d35fd62e5090d07f5ae7dde (diff) | |
download | chromium_src-ec7dc1160836695462ee7311d4c02f2c2f61350e.zip chromium_src-ec7dc1160836695462ee7311d4c02f2c2f61350e.tar.gz chromium_src-ec7dc1160836695462ee7311d4c02f2c2f61350e.tar.bz2 |
This fixes http://b/issue?id=1257424, which is a need to implement a global backing store cache. The current backing store cache is only used for invisible tabs and every other RenderWidgetHost holds a reference to its backing store.
This CB proposes a change where in we have a global backing store cache, whose size can be controlled based on strategies like available resources etc. At this point the strategy is not implemented and the size is left at 5.
We no longer maintain a reference to the backing store in the RenderWidgetHost. Every host queries the global cache for its backing store. The cache provides methods to create the backing store and populate it with the required dib.
The other change is to use the renderer dib when the size of the bitmap being painted is the same as the backing store size. This is an attempt to improve performance in operations like scrolling.
Bug=1257424
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@422 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/render_view_host.cc | 2 | ||||
-rw-r--r-- | chrome/browser/render_widget_host.cc | 429 | ||||
-rw-r--r-- | chrome/browser/render_widget_host.h | 62 | ||||
-rw-r--r-- | chrome/common/mru_cache.h | 2 | ||||
-rw-r--r-- | chrome/common/render_messages.h | 5 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 9 | ||||
-rw-r--r-- | chrome/renderer/render_process.h | 7 | ||||
-rw-r--r-- | chrome/renderer/render_widget.cc | 30 | ||||
-rw-r--r-- | chrome/renderer/render_widget.h | 7 |
9 files changed, 393 insertions, 160 deletions
diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc index bb98a9e..ba466a8 100644 --- a/chrome/browser/render_view_host.cc +++ b/chrome/browser/render_view_host.cc @@ -775,7 +775,7 @@ void RenderViewHost::OnMsgRendererGone() { current_size_ = gfx::Size(); is_hidden_ = false; - backing_store_.reset(); + RendererExited(); if (view_) { view_->RendererGone(); diff --git a/chrome/browser/render_widget_host.cc b/chrome/browser/render_widget_host.cc index 23cf9e1..8f48a51 100644 --- a/chrome/browser/render_widget_host.cc +++ b/chrome/browser/render_widget_host.cc @@ -54,85 +54,269 @@ static const int kHungRendererDelayMs = 10000; // RenderWidget::BackingStore RenderWidgetHost::BackingStore::BackingStore(const gfx::Size& size) - : size_(size) { + : size_(size), + backing_store_dib_(NULL), + renderer_bitmap_section_(NULL), + original_bitmap_(NULL) { HDC screen_dc = ::GetDC(NULL); hdc_ = CreateCompatibleDC(screen_dc); - int color_depth = GetDeviceCaps(screen_dc, BITSPIXEL); - - // Color depths less than 16 bpp require a palette to be specified in the - // BITMAPINFO structure passed to CreateDIBSection. Instead of creating - // the palette, we specify the desired color depth as 16 which allows the - // OS to come up with an approximation. Tested this with 8bpp. - if (color_depth < 16) - color_depth = 16; - - BITMAPINFOHEADER hdr = {0}; - gfx::CreateBitmapHeaderWithColorDepth(size.width(), size.height(), - color_depth, &hdr); - void* data = NULL; - HANDLE bitmap = CreateDIBSection(hdc_, reinterpret_cast<BITMAPINFO*>(&hdr), - 0, &data, NULL, 0); - SelectObject(hdc_, bitmap); - ::ReleaseDC(NULL, screen_dc); + ReleaseDC(NULL, screen_dc); } RenderWidgetHost::BackingStore::~BackingStore() { DCHECK(hdc_); - HBITMAP bitmap = - reinterpret_cast<HBITMAP>(GetCurrentObject(hdc_, OBJ_BITMAP)); DeleteDC(hdc_); - DeleteObject(bitmap); + + if (backing_store_dib_) { + DeleteObject(backing_store_dib_); + backing_store_dib_ = NULL; + } + + if (renderer_bitmap_section_) { + CloseHandle(renderer_bitmap_section_); + renderer_bitmap_section_ = NULL; + } } -/////////////////////////////////////////////////////////////////////////////// -// RenderWidget::BackingStoreCache +bool RenderWidgetHost::BackingStore::Refresh(HANDLE process, + HANDLE bitmap_section, + 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 (bitmap_rect.size() == size()) { + CreateDIBSectionBackedByRendererBitmap(bitmap_rect, valid_bitmap); + return true; + } + + if (!backing_store_dib_) { + backing_store_dib_ = CreateDIB(hdc_, size_.width(), size_.height(), true, + NULL); + DCHECK(backing_store_dib_ != NULL); + original_bitmap_ = SelectObject(hdc_, backing_store_dib_); + } + + // 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); + // Account for a bitmap_rect that exceeds the bounds of our view + gfx::Rect view_rect(0, 0, size_.width(), size_.height()); + gfx::Rect paint_rect = view_rect.Intersect(bitmap_rect); -class RenderWidgetHost::BackingStoreCache { + StretchDIBits(hdc_, + paint_rect.x(), + paint_rect.y(), + paint_rect.width(), + paint_rect.height(), + 0, 0, // source x,y + paint_rect.width(), + paint_rect.height(), + backing_store_data, + reinterpret_cast<BITMAPINFO*>(&hdr), + DIB_RGB_COLORS, + SRCCOPY); + + UnmapViewOfFile(backing_store_data); + CloseHandle(valid_bitmap); + return true; +} + +void RenderWidgetHost::BackingStore::CreateDIBSectionBackedByRendererBitmap( + const gfx::Rect& bitmap_rect, HANDLE bitmap_section_from_renderer) { + if (backing_store_dib_ != NULL) { + SelectObject(hdc_, original_bitmap_); + DeleteObject(backing_store_dib_); + backing_store_dib_ = NULL; + } + + if (renderer_bitmap_section_ != NULL) { + CloseHandle(renderer_bitmap_section_); + renderer_bitmap_section_ = NULL; + } + + backing_store_dib_ = CreateDIB(hdc_, bitmap_rect.width(), + bitmap_rect.height(), false, + bitmap_section_from_renderer); + DCHECK(backing_store_dib_ != NULL); + + renderer_bitmap_section_ = bitmap_section_from_renderer; + original_bitmap_ = SelectObject(hdc_, backing_store_dib_); +} + +HANDLE RenderWidgetHost::BackingStore::CreateDIB(HDC dc, int width, int height, + bool use_system_color_depth, + HANDLE section) { + BITMAPINFOHEADER hdr; + + if (use_system_color_depth) { + HDC screen_dc = ::GetDC(NULL); + int color_depth = GetDeviceCaps(screen_dc, BITSPIXEL); + ::ReleaseDC(NULL, screen_dc); + + // Color depths less than 16 bpp require a palette to be specified in the + // BITMAPINFO structure passed to CreateDIBSection. Instead of creating + // the palette, we specify the desired color depth as 16 which allows the + // OS to come up with an approximation. Tested this with 8bpp. + if (color_depth < 16) + color_depth = 16; + + gfx::CreateBitmapHeaderWithColorDepth(width, height, color_depth, &hdr); + } else { + gfx::CreateBitmapHeader(width, height, &hdr); + } + void* data = NULL; + HANDLE dib = + CreateDIBSection(hdc_, reinterpret_cast<BITMAPINFO*>(&hdr), + 0, &data, section, 0); + return dib; +} + + +/////////////////////////////////////////////////////////////////////////////// +// RenderWidgetHost::BackingStoreManager + +// This class manages backing stores in the browsr. Every RenderWidgetHost +// is associated with a backing store which it requests from this class. +// The hosts don't maintain any references to the backing stores. +// These backing stores are maintained in a cache which can be trimmed as +// needed. +class RenderWidgetHost::BackingStoreManager { public: - // The number of backing stores to cache. - enum { kMaxSize = 5 }; + // Returns a backing store which matches the desired dimensions. + // Parameters: + // host + // A pointer to the RenderWidgetHost. + // backing_store_rect + // The desired backing store dimensions. + // Returns a pointer to the backing store on success, NULL on failure. + static BackingStore* GetBackingStore(RenderWidgetHost* host, + const gfx::Size& desired_size) { + BackingStore* backing_store = Lookup(host); + if (backing_store) { + // If we already have a backing store, then make sure it is the correct + // size. + if (backing_store->size() == desired_size) + return backing_store; + backing_store = NULL; + } - static void Add(RenderWidgetHost* host, BackingStore* backing_store) { - // TODO(darin): Re-enable once we have a fix for bug 1143208. - if (!cache_) - cache_ = new Cache(kMaxSize); - cache_->Put(host, backing_store); + return backing_store; } - static BackingStore* Remove(RenderWidgetHost* host) { - // TODO(darin): Re-enable once we have a fix for bug 1143208. + // Returns a backing store which is fully ready for consumption, + // i.e. the bitmap from the renderer has been copied into the + // backing store dc, or the bitmap in the backing store dc references + // the renderer bitmap. + // Parameters: + // host + // A pointer to the RenderWidgetHost. + // backing_store_rect + // The desired backing store dimensions. + // process_handle + // The renderer process handle. + // bitmap_section + // The bitmap section from the renderer. + // bitmap_rect + // The rect to be painted into the backing store + // needs_full_paint + // Set if we need to send out a request to paint the view + // to the renderer. + static BackingStore* PrepareBackingStore(RenderWidgetHost* host, + const gfx::Rect& backing_store_rect, + HANDLE process_handle, + HANDLE bitmap_section, + const gfx::Rect& bitmap_rect, + bool* needs_full_paint) { + BackingStore* backing_store = GetBackingStore(host, + backing_store_rect.size()); + if (!backing_store) { + // We need to get Webkit to generate a new paint here, as we + // don't have a previous snapshot. + if (bitmap_rect != backing_store_rect) { + DCHECK(needs_full_paint != NULL); + *needs_full_paint = true; + } + backing_store = CreateBackingStore(host, backing_store_rect); + } + + DCHECK(backing_store != NULL); + backing_store->Refresh(process_handle, bitmap_section, bitmap_rect); + return backing_store; + } + + // Returns a matching backing store for the host. + // Returns NULL if we fail to find one. + static BackingStore* Lookup(RenderWidgetHost* host) { + if (cache_) { + BackingStoreCache::iterator it = cache_->Peek(host); + if (it != cache_->end()) + return it->second; + } + return NULL; + } + + // Removes the backing store for the host. + static void RemoveBackingStore(RenderWidgetHost* host) { if (!cache_) - return NULL; + return; - Cache::iterator it = cache_->Peek(host); + BackingStoreCache::iterator it = cache_->Peek(host); if (it == cache_->end()) - return NULL; - - BackingStore* result = it->second; + return; - // Remove from the cache without deleting the backing store object. - it->second = NULL; cache_->Erase(it); - if (cache_->size() == 0) { + if (cache_->empty()) { delete cache_; cache_ = NULL; } - - return result; } private: - ~BackingStoreCache(); // not intended to be instantiated + // Not intended for instantiation. + ~BackingStoreManager(); + + typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> BackingStoreCache; + static BackingStoreCache* cache_; + + // Returns the size of the backing store cache. + // TODO(iyengar) Make this dynamic, i.e. based on the available resources + // on the machine. + static int GetBackingStoreCacheSize() { + const int kMaxSize = 5; + return kMaxSize; + } - typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> Cache; - static Cache* cache_; + // Creates the backing store for the host based on the dimensions passed in. + // Removes the existing backing store if there is one. + static BackingStore* CreateBackingStore( + RenderWidgetHost* host, const gfx::Rect& backing_store_rect) { + RemoveBackingStore(host); + + BackingStore* backing_store = new BackingStore(backing_store_rect.size()); + int backing_store_cache_size = GetBackingStoreCacheSize(); + if (backing_store_cache_size > 0) { + if (!cache_) + cache_ = new BackingStoreCache(backing_store_cache_size); + cache_->Put(host, backing_store); + } + return backing_store; + } + + DISALLOW_EVIL_CONSTRUCTORS(BackingStoreManager); }; -// static -RenderWidgetHost::BackingStoreCache::Cache* - RenderWidgetHost::BackingStoreCache::cache_ = NULL; +RenderWidgetHost::BackingStoreManager::BackingStoreCache* + RenderWidgetHost::BackingStoreManager::cache_ = NULL; + /////////////////////////////////////////////////////////////////////////////// // RenderWidgetHost @@ -148,7 +332,9 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, int routing_id) suppress_view_updating_(false), needs_repainting_on_restore_(false), hung_renderer_factory_(this), - is_unresponsive_(false) { + is_unresponsive_(false), + view_being_painted_(false), + repaint_ack_pending_(false) { if (routing_id_ == MSG_ROUTING_NONE) routing_id_ = process_->widget_helper()->GetNextRoutingID(); @@ -160,7 +346,7 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, int routing_id) RenderWidgetHost::~RenderWidgetHost() { // Clear our current or cached backing store if either remains. - backing_store_.reset(BackingStoreCache::Remove(this)); + BackingStoreManager::RemoveBackingStore(this); process_->Release(routing_id_); } @@ -230,21 +416,39 @@ void RenderWidgetHost::OnMsgPaintRect( resize_ack_pending_ = false; } + bool is_repaint_ack = + ViewHostMsg_PaintRect_Flags::is_repaint_ack(params.flags); + if (is_repaint_ack) { + repaint_ack_pending_ = false; + TimeDelta delta = TimeTicks::Now() - repaint_start_time_; + UMA_HISTOGRAM_TIMES(L"MPArch.RWH_RepaintDelta", delta); + } + DCHECK(params.bitmap); DCHECK(!params.bitmap_rect.IsEmpty()); DCHECK(!params.view_size.IsEmpty()); PaintRect(params.bitmap, params.bitmap_rect, params.view_size); + bool using_renderer_bitmap_section = false; + BackingStore* backing_store = BackingStoreManager::Lookup(this); + if (backing_store) { + using_renderer_bitmap_section = + backing_store->using_renderer_bitmap_section(); + } + // ACK early so we can prefetch the next PaintRect if there is a next one. - Send(new ViewMsg_PaintRect_ACK(routing_id_)); + Send(new ViewMsg_PaintRect_ACK(routing_id_, using_renderer_bitmap_section)); // TODO(darin): This should really be done by the view_! MovePluginWindows(params.plugin_window_moves); // The view might be destroyed already. Check for this case. - if (view_ && !suppress_view_updating_) + if (view_ && !suppress_view_updating_) { + view_being_painted_ = true; view_->DidPaintRect(params.bitmap_rect); + view_being_painted_ = false; + } if (paint_observer_.get()) paint_observer_->RenderWidgetHostDidPaint(this); @@ -279,8 +483,11 @@ void RenderWidgetHost::OnMsgScrollRect( MovePluginWindows(params.plugin_window_moves); // The view might be destroyed already. Check for this case - if (view_) + if (view_) { + view_being_painted_ = true; view_->DidScrollRect(params.clip_rect, params.dx, params.dy); + view_being_painted_ = false; + } // Log the time delta for processing a scroll message. TimeDelta delta = TimeTicks::Now() - scroll_start; @@ -398,10 +605,6 @@ void RenderWidgetHost::WasHidden() { // reduce its resource utilization. Send(new ViewMsg_WasHidden(routing_id_)); - // Yield the backing store (allows this memory to be freed). - if (backing_store_.get()) - BackingStoreCache::Add(this, backing_store_.release()); - // TODO(darin): what about constrained windows? it doesn't look like they // see a message when their parent is hidden. maybe there is something more // generic we can do at the TabContents API level instead of relying on @@ -417,13 +620,11 @@ void RenderWidgetHost::WasRestored() { return; is_hidden_ = false; - DCHECK(!backing_store_.get()); - backing_store_.reset(BackingStoreCache::Remove(this)); - + BackingStore* backing_store = BackingStoreManager::Lookup(this); // If we already have a backing store for this widget, then we don't need to // repaint on restore _unless_ we know that our backing store is invalid. bool needs_repainting; - if (needs_repainting_on_restore_ || !backing_store_.get()) { + if (needs_repainting_on_restore_ || !backing_store) { needs_repainting = true; needs_repainting_on_restore_ = false; } else { @@ -569,13 +770,21 @@ RenderWidgetHost::BackingStore* RenderWidgetHost::GetBackingStore() { DCHECK(!is_hidden_) << "GetBackingStore called while hidden!"; // We might have a cached backing store that we can reuse! - if (!backing_store_.get()) - backing_store_.reset(BackingStoreCache::Remove(this)); + BackingStore* backing_store = + BackingStoreManager::GetBackingStore(this, current_size_); + // If we fail to find a backing store in the cache, send out a request + // to the renderer to paint the view if required. + if (!backing_store && !repaint_ack_pending_ && !resize_ack_pending_ && + !view_being_painted_) { + repaint_start_time_ = TimeTicks::Now(); + repaint_ack_pending_ = true; + Send(new ViewMsg_Repaint(routing_id_, current_size_)); + } // When we have asked the RenderWidget to resize, and we are still waiting on // a response, block for a little while to see if we can't get a response // before returning the old (incorrectly sized) backing store. - if (resize_ack_pending_ || !backing_store_.get()) { + if (resize_ack_pending_ || !backing_store) { IPC::Message msg; TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); if (process_->widget_helper()->WaitForPaintMsg(routing_id_, max_delay, @@ -584,53 +793,11 @@ RenderWidgetHost::BackingStore* RenderWidgetHost::GetBackingStore() { ViewHostMsg_PaintRect::Dispatch( &msg, this, &RenderWidgetHost::OnMsgPaintRect); suppress_view_updating_ = false; + backing_store = BackingStoreManager::GetBackingStore(this, current_size_); } } - return backing_store_.get(); -} - -void RenderWidgetHost::EnsureBackingStore(const gfx::Rect& view_rect) { - // We might have a cached backing store that we can reuse! - if (!backing_store_.get()) - backing_store_.reset(BackingStoreCache::Remove(this)); - - // If we already have a backing store, then make sure it is the correct size. - if (backing_store_.get() && backing_store_->size() == view_rect.size()) - return; - - backing_store_.reset(new BackingStore(view_rect.size())); -} - -void RenderWidgetHost::PaintBackingStore(HANDLE bitmap, - const gfx::Rect& bitmap_rect) { - // TODO(darin): protect against integer overflow - DWORD size = 4 * bitmap_rect.width() * bitmap_rect.height(); - void* data = MapViewOfFile(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); - - // Account for a bitmap_rect that exceeds the bounds of our view - gfx::Rect view_rect( - 0, 0, backing_store_->size().width(), backing_store_->size().height()); - gfx::Rect paint_rect = view_rect.Intersect(bitmap_rect); - - StretchDIBits(backing_store_->dc(), - paint_rect.x(), - paint_rect.y(), - paint_rect.width(), - paint_rect.height(), - 0, 0, // source x,y - paint_rect.width(), - paint_rect.height(), - data, - reinterpret_cast<BITMAPINFO*>(&hdr), - DIB_RGB_COLORS, - SRCCOPY); - - UnmapViewOfFile(data); + return backing_store; } void RenderWidgetHost::PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, @@ -640,18 +807,21 @@ void RenderWidgetHost::PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, return; } - // The bitmap received is valid only in the renderer process. - HANDLE valid_bitmap = - win_util::GetSectionFromProcess(bitmap, process_->process(), true); - if (valid_bitmap) { - // We use the view size according to the render view, which may not be - // quite the same as the size of our window. - gfx::Rect view_rect(0, 0, view_size.width(), view_size.height()); - - EnsureBackingStore(view_rect); - - PaintBackingStore(valid_bitmap, bitmap_rect); - CloseHandle(valid_bitmap); + // We use the view size according to the render view, which may not be + // quite the same as the size of our window. + gfx::Rect view_rect(0, 0, view_size.width(), view_size.height()); + + bool needs_full_paint = false; + BackingStore* backing_store = + BackingStoreManager::PrepareBackingStore(this, view_rect, + process_->process(), + bitmap, bitmap_rect, + &needs_full_paint); + DCHECK(backing_store != NULL); + if (needs_full_paint) { + repaint_start_time_ = TimeTicks::Now(); + repaint_ack_pending_ = true; + Send(new ViewMsg_Repaint(routing_id_, view_size)); } } @@ -666,11 +836,12 @@ void RenderWidgetHost::ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, // TODO(darin): do we need to do something else if our backing store is not // the same size as the advertised view? maybe we just assume there is a // full paint on its way? - if (backing_store_->size() != view_size) + BackingStore* backing_store = BackingStoreManager::Lookup(this); + if (backing_store && backing_store->size() != view_size) return; RECT damaged_rect, r = clip_rect.ToRECT(); - ScrollDC(backing_store_->dc(), dx, dy, NULL, &r, NULL, &damaged_rect); + ScrollDC(backing_store->dc(), dx, dy, NULL, &r, NULL, &damaged_rect); // TODO(darin): this doesn't work if dx and dy are both non-zero! DCHECK(dx == 0 || dy == 0); @@ -678,13 +849,7 @@ void RenderWidgetHost::ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, // We expect that damaged_rect should equal bitmap_rect. DCHECK(gfx::Rect(damaged_rect) == bitmap_rect); - // The bitmap handle is valid only in the renderer process - HANDLE valid_bitmap = - win_util::GetSectionFromProcess(bitmap, process_->process(), true); - if (valid_bitmap) { - PaintBackingStore(valid_bitmap, bitmap_rect); - CloseHandle(valid_bitmap); - } + backing_store->Refresh(process_->process(), bitmap, bitmap_rect); } void RenderWidgetHost::RestartHangMonitorTimeout() { @@ -702,3 +867,7 @@ void RenderWidgetHost::StartHangMonitorTimeout(int delay) { hung_renderer_factory_.NewRunnableMethod( &RenderWidgetHost::RendererIsUnresponsive), delay); } + +void RenderWidgetHost::RendererExited() { + BackingStoreManager::RemoveBackingStore(this); +} diff --git a/chrome/browser/render_widget_host.h b/chrome/browser/render_widget_host.h index bb71df8..054959d 100644 --- a/chrome/browser/render_widget_host.h +++ b/chrome/browser/render_widget_host.h @@ -184,6 +184,9 @@ class RenderWidgetHost : public IPC::Channel::Listener { // of a RenderWidgetHost. class BackingStore; + // Manages a set of backing stores. + class BackingStoreManager; + // Get access to the widget's backing store. If a resize is in progress, // then the current size of the backing store may be less than the size of // the widget's view. This method returns NULL if the backing store could @@ -218,11 +221,11 @@ class RenderWidgetHost : public IPC::Channel::Listener { // left on the existing timeouts. void StartHangMonitorTimeout(int delay); + // Called when we receive a notification indicating that the renderer + // process has gone. + void RendererExited(); protected: - // Represents a cache of BackingStore objects indexed by RenderWidgetHost. - class BackingStoreCache; - // Called when we an InputEvent was not processed by the renderer. virtual void UnhandledInputEvent(const WebInputEvent& event) { } @@ -253,17 +256,6 @@ class RenderWidgetHost : public IPC::Channel::Listener { void ForwardWheelEvent(const WebMouseWheelEvent& wheel_event); void ForwardInputEvent(const WebInputEvent& input_event, int event_size); - // Paints the bitmap referenced by the specified handle to the backing store, - // at the specified bounds. - void PaintBackingStore(HANDLE bitmap, const gfx::Rect& bitmap_rect); - - // Retrieves a handle to the backing store bitmap. - HBITMAP GetBackingStoreBitmap() const; - - // Creates the backing store bitmap for the specified ViewPort bounds, if - // one does not presently exist. - void EnsureBackingStore(const gfx::Rect& view_rect); - // Called to paint a region of the backing store void PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, const gfx::Size& view_size); @@ -312,9 +304,6 @@ class RenderWidgetHost : public IPC::Channel::Listener { // The time when an input event was sent to the RenderWidget. TimeTicks input_event_start_time_; - // The backing store, used as a target for rendering. - scoped_ptr<BackingStore> backing_store_; - // Indicates whether a page is loading or not. bool is_loading_; // Indicates whether a page is hidden or not. @@ -338,6 +327,16 @@ class RenderWidgetHost : public IPC::Channel::Listener { // Optional observer that listens for notifications of painting. scoped_ptr<PaintObserver> paint_observer_; + // Set when we call DidPaintRect/DidScrollRect on the view. + bool view_being_painted_; + + // Set if we are waiting for a repaint ack for the view. + bool repaint_ack_pending_; + + // Used for UMA histogram logging to measure the time for a repaint view + // operation to finish. + TimeTicks repaint_start_time_; + DISALLOW_EVIL_CONSTRUCTORS(RenderWidgetHost); }; @@ -349,9 +348,38 @@ class RenderWidgetHost::BackingStore { HDC dc() { return hdc_; } const gfx::Size& size() { return size_; } + // Paints the bitmap from the renderer onto the backing store. + bool Refresh(HANDLE process, HANDLE bitmap_section, + const gfx::Rect& bitmap_rect); + + bool using_renderer_bitmap_section() const { + return renderer_bitmap_section_ != NULL; + } + private: + // Creates the backing store DIB backed by the renderer bitmap + // shared section. + void CreateDIBSectionBackedByRendererBitmap( + const gfx::Rect& bitmap_rect, HANDLE bitmap_section_from_renderer); + + // Creates a dib conforming to the height/width/section parameters passed + // in. The use_os_color_depth parameter controls whether we use the color + // depth to create an appropriate dib or not. + HANDLE CreateDIB(HDC dc, int width, int height, bool use_os_color_depth, + HANDLE section); + + // The backing store dc. HDC hdc_; + // The size of the backing store. gfx::Size size_; + // Handle to the renderer bitmap section, valid in the browser address + // space. This is set if the backing store dib is backed by the renderer + // bitmap section. + HANDLE renderer_bitmap_section_; + // Handle to the backing store dib. + HANDLE backing_store_dib_; + // Handle to the original bitmap in the dc. + HANDLE original_bitmap_; DISALLOW_EVIL_CONSTRUCTORS(BackingStore); }; diff --git a/chrome/common/mru_cache.h b/chrome/common/mru_cache.h index 93f8059..cdad761 100644 --- a/chrome/common/mru_cache.h +++ b/chrome/common/mru_cache.h @@ -186,6 +186,8 @@ class MRUCacheBase { reverse_iterator rend() { return ordering_.rend(); } const_reverse_iterator rend() const { return ordering_.rend(); } + bool empty() const { return ordering_.empty(); } + private: PayloadList ordering_; KeyIndex index_; diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 32f7d7e..8beb013 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -183,6 +183,7 @@ struct ViewHostMsg_PaintRect_Flags { enum { IS_RESIZE_ACK = 1 << 0, IS_RESTORE_ACK = 1 << 1, + IS_REPAINT_ACK = 1 << 2, }; static bool is_resize_ack(int flags) { return (flags & IS_RESIZE_ACK) != 0; @@ -190,6 +191,10 @@ struct ViewHostMsg_PaintRect_Flags { static bool is_restore_ack(int flags) { return (flags & IS_RESTORE_ACK) != 0; } + + static bool is_repaint_ack(int flags) { + return (flags & IS_REPAINT_ACK) != 0; + } }; struct ViewHostMsg_PaintRect_Params { diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index a81499e..738aa16 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -105,7 +105,10 @@ IPC_BEGIN_MESSAGES(View, 1) // Tells the render view that a ViewHostMsg_PaintRect message was processed. // This signals the render view that it can send another PaintRect message. - IPC_MESSAGE_ROUTED0(ViewMsg_PaintRect_ACK) + // The drop bitmap argument indicates whether the renderer should drop its + // reference on the shared section used for the dib. + IPC_MESSAGE_ROUTED1(ViewMsg_PaintRect_ACK, + bool /* drop bitmap */) // Asks the renderer to calculate the number of printed pages according to the // supplied settings. The renderer will reply with @@ -431,6 +434,10 @@ IPC_BEGIN_MESSAGES(View, 1) // Notifies the renderer about ui theme changes IPC_MESSAGE_ROUTED0(ViewMsg_ThemeChanged) + // Notifies the renderer that a paint is to be generated for the rectangle + // passed in. + IPC_MESSAGE_ROUTED1(ViewMsg_Repaint, + gfx::Size /* The view size to be repainted */) IPC_END_MESSAGES(View) diff --git a/chrome/renderer/render_process.h b/chrome/renderer/render_process.h index 49f43e2..9ecbb13 100644 --- a/chrome/renderer/render_process.h +++ b/chrome/renderer/render_process.h @@ -63,6 +63,9 @@ class RenderProcess : public ChildProcess { // this function to free the SharedMemory object. static void FreeSharedMemory(SharedMemory* mem); + // Deletes the shared memory allocated by AllocSharedMemory. + static void DeleteSharedMem(SharedMemory* mem); + private: friend class ChildProcessFactory<RenderProcess>; RenderProcess(const std::wstring& channel_name); @@ -83,10 +86,6 @@ class RenderProcess : public ChildProcess { static ChildProcess* ClassFactory(const std::wstring& channel_name); - // This is here so consumers will use FreeSharedMemory instead. A destructor - // on SharedMemory would be too tempting. - static void DeleteSharedMem(SharedMemory* mem); - // Look in the shared memory cache for a suitable object to reuse. Returns // NULL if there is none. SharedMemory* GetSharedMemFromCache(size_t size); diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc index c5db805..2560438 100644 --- a/chrome/renderer/render_widget.cc +++ b/chrome/renderer/render_widget.cc @@ -182,6 +182,7 @@ IPC_DEFINE_MESSAGE_MAP(RenderWidget) IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus) IPC_MESSAGE_HANDLER(ViewMsg_ImeSetInputMode, OnImeSetInputMode) IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition) + IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint) IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() @@ -295,17 +296,24 @@ void RenderWidget::OnWasRestored(bool needs_repainting) { DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height())); } -void RenderWidget::OnPaintRectAck() { +void RenderWidget::OnPaintRectAck(bool drop_bitmap) { DCHECK(paint_reply_pending()); paint_reply_pending_ = false; - // 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_); - current_paint_buf_ = NULL; + if (drop_bitmap) { + if (current_paint_buf_) { + RenderProcess::DeleteSharedMem(current_paint_buf_); + } + } else { + // 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_); + } } + current_paint_buf_ = NULL; + // Continue painting if necessary... DoDeferredPaint(); } @@ -691,6 +699,16 @@ void RenderWidget::OnImeSetComposition(int string_type, } } +void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) { + // During shutdown we can just ignore this message. + if (!webwidget_) + return; + + set_next_paint_is_repaint_ack(); + gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height()); + DidInvalidateRect(webwidget_, repaint_rect); +} + void RenderWidget::UpdateIME() { // If a browser process does not have IMEs, its IMEs are not active, or there // are not any attached widgets. diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h index 720df07..48b40ee 100644 --- a/chrome/renderer/render_widget.h +++ b/chrome/renderer/render_widget.h @@ -133,7 +133,7 @@ class RenderWidget : public IPC::Channel::Listener, void OnResize(const gfx::Size& new_size); void OnWasHidden(); void OnWasRestored(bool needs_repainting); - void OnPaintRectAck(); + void OnPaintRectAck(bool drop_bitmap); void OnScrollRectAck(); void OnHandleInputEvent(const IPC::Message& message); void OnMouseCaptureLost(); @@ -142,6 +142,7 @@ class RenderWidget : public IPC::Channel::Listener, void OnImeSetComposition(int string_type, int cursor_position, int target_start, int target_end, const std::wstring& ime_string); + void OnMsgRepaint(const gfx::Size& size_to_paint); // True if a PaintRect_ACK message is pending. bool paint_reply_pending() const { @@ -169,6 +170,10 @@ class RenderWidget : public IPC::Channel::Listener, next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK; } + void set_next_paint_is_repaint_ack() { + next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK; + } + // Called when a renderer process moves an input focus or updates the // position of its caret. // This function compares them with the previous values, and send them to |