diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-23 23:14:11 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-23 23:14:11 +0000 |
commit | bcfc90e8a909bbc199f4d80143f5eb24abda1544 (patch) | |
tree | 2ea9ba7885047e901fe55f2c4938c46633e0ee09 /chrome/browser/renderer_host/render_widget_host.cc | |
parent | 2a5af8a6e448b72044353b691ab7766e989db152 (diff) | |
download | chromium_src-bcfc90e8a909bbc199f4d80143f5eb24abda1544.zip chromium_src-bcfc90e8a909bbc199f4d80143f5eb24abda1544.tar.gz chromium_src-bcfc90e8a909bbc199f4d80143f5eb24abda1544.tar.bz2 |
Separate out the backing store from the RenderWidgetHost into its own file to
make porting easier.
I also did some cleanup in the scrolling and painting areas, collapsing the
confusing ScrollRect call inside OnMsgScrollRect to just be inside the function
and call a new function on the backing store to scroll it. Same for painting.
This also moves plugin window moving to the view.
Review URL: http://codereview.chromium.org/18702
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8594 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/renderer_host/render_widget_host.cc')
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 356 |
1 files changed, 47 insertions, 309 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 354f54b..63dd0f3 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -7,10 +7,10 @@ #include "base/gfx/gdi_util.h" #include "base/message_loop.h" #include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/renderer_host/backing_store.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_widget_helper.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" -#include "chrome/common/mru_cache.h" #include "chrome/common/notification_service.h" #include "chrome/common/win_util.h" #include "chrome/views/view.h" @@ -31,241 +31,6 @@ static const int kPaintMsgTimeoutMS = 40; static const int kHungRendererDelayMs = 20000; /////////////////////////////////////////////////////////////////////////////// -// RenderWidget::BackingStore - -RenderWidgetHost::BackingStore::BackingStore(const gfx::Size& size) - : size_(size), - backing_store_dib_(NULL), - original_bitmap_(NULL) { - HDC screen_dc = ::GetDC(NULL); - hdc_ = CreateCompatibleDC(screen_dc); - ReleaseDC(NULL, screen_dc); -} - -RenderWidgetHost::BackingStore::~BackingStore() { - DCHECK(hdc_); - - DeleteDC(hdc_); - - if (backing_store_dib_) { - DeleteObject(backing_store_dib_); - backing_store_dib_ = NULL; - } -} - -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 (!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); - - 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; -} - -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: - // 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; - } - - return backing_store; - } - - // 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; - - BackingStoreCache::iterator it = cache_->Peek(host); - if (it == cache_->end()) - return; - - cache_->Erase(it); - - if (cache_->empty()) { - delete cache_; - cache_ = NULL; - } - } - - private: - // 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; - } - - // 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); -}; - -RenderWidgetHost::BackingStoreManager::BackingStoreCache* - RenderWidgetHost::BackingStoreManager::cache_ = NULL; - - -/////////////////////////////////////////////////////////////////////////////// // RenderWidgetHost RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, @@ -375,17 +140,27 @@ void RenderWidgetHost::OnMsgPaintRect( DCHECK(!params.bitmap_rect.IsEmpty()); DCHECK(!params.view_size.IsEmpty()); - PaintRect(params.bitmap, params.bitmap_rect, params.view_size); + // 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); // 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 + // renderer. This ACK is a signal to the renderer that the backing store can + // be re-used, so the bitmap may be invalid after this call. Send(new ViewMsg_PaintRect_ACK(routing_id_)); - // TODO(darin): This should really be done by the view_! - MovePluginWindows(params.plugin_window_moves); + // We don't need to update the view if the view is hidden. We must do this + // early return after the ACK is sent, however, or the renderer will not send + // is more data. + if (is_hidden_) + return; - // The view might be destroyed already. Check for this case. + // Now paint the view. Watch out: it might be destroyed already. if (view_ && !suppress_view_updating_) { view_being_painted_ = true; + view_->MovePluginWindows(params.plugin_window_moves); view_->DidPaintRect(params.bitmap_rect); view_being_painted_ = false; } @@ -413,18 +188,27 @@ void RenderWidgetHost::OnMsgScrollRect( DCHECK(!params.view_size.IsEmpty()); - ScrollRect(params.bitmap, params.bitmap_rect, params.dx, params.dy, - params.clip_rect, params.view_size); + // Scroll the backing store. + ScrollBackingStoreRect(params.bitmap, 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 + // renderer. This ACK is a signal to the renderer that the backing store can + // be re-used, so the bitmap may be invalid after this call. Send(new ViewMsg_ScrollRect_ACK(routing_id_)); - // TODO(darin): This should really be done by the view_! - MovePluginWindows(params.plugin_window_moves); + // We don't need to update the view if the view is hidden. We must do this + // early return after the ACK is sent, however, or the renderer will not send + // is more data. + if (is_hidden_) + return; - // The view might be destroyed already. Check for this case + // Paint the view. Watch out: it might be destroyed already. if (view_) { view_being_painted_ = true; + view_->MovePluginWindows(params.plugin_window_moves); view_->DidScrollRect(params.clip_rect, params.dx, params.dy); view_being_painted_ = false; } @@ -434,53 +218,6 @@ void RenderWidgetHost::OnMsgScrollRect( UMA_HISTOGRAM_TIMES(L"MPArch.RWH_OnMsgScrollRect", delta); } -void RenderWidgetHost::MovePluginWindows( - const std::vector<WebPluginGeometry>& plugin_window_moves) { - if (plugin_window_moves.empty()) - return; - - HDWP defer_window_pos_info = - ::BeginDeferWindowPos(static_cast<int>(plugin_window_moves.size())); - - if (!defer_window_pos_info) { - NOTREACHED(); - return; - } - - for (size_t i = 0; i < plugin_window_moves.size(); ++i) { - unsigned long flags = 0; - const WebPluginGeometry& move = plugin_window_moves[i]; - - if (move.visible) - flags |= SWP_SHOWWINDOW; - else - flags |= SWP_HIDEWINDOW; - - HRGN hrgn = ::CreateRectRgn(move.clip_rect.x(), - move.clip_rect.y(), - move.clip_rect.right(), - move.clip_rect.bottom()); - gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects); - - // Note: System will own the hrgn after we call SetWindowRgn, - // so we don't need to call DeleteObject(hrgn) - ::SetWindowRgn(move.window, hrgn, !move.clip_rect.IsEmpty()); - - defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info, - move.window, NULL, - move.window_rect.x(), - move.window_rect.y(), - move.window_rect.width(), - move.window_rect.height(), flags); - if (!defer_window_pos_info) { - DCHECK(false) << "DeferWindowPos given invalid window, so rest ignored."; - return; - } - } - - ::EndDeferWindowPos(defer_window_pos_info); -} - void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { // Log the time delta for processing an input event. TimeDelta delta = TimeTicks::Now() - input_event_start_time_; @@ -726,7 +463,7 @@ void RenderWidgetHost::SetIsLoading(bool is_loading) { view_->SetIsLoading(is_loading); } -RenderWidgetHost::BackingStore* RenderWidgetHost::GetBackingStore() { +BackingStore* RenderWidgetHost::GetBackingStore() { // We should not be asked to paint while we are hidden. If we are hidden, // then it means that our consumer failed to call WasRestored. DCHECK(!is_hidden_) << "GetBackingStore called while hidden!"; @@ -761,9 +498,13 @@ RenderWidgetHost::BackingStore* RenderWidgetHost::GetBackingStore() { return backing_store; } -void RenderWidgetHost::PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, - const gfx::Size& view_size) { +void RenderWidgetHost::PaintBackingStoreRect(HANDLE bitmap, + const gfx::Rect& bitmap_rect, + const gfx::Size& view_size) { if (is_hidden_) { + // Don't bother updating the backing store when we're hidden. Just mark it + // as being totally invalid. This will cause a complete repaint when the + // view is restored. needs_repainting_on_restore_ = true; return; } @@ -786,10 +527,15 @@ void RenderWidgetHost::PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, } } -void RenderWidgetHost::ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, - int dx, int dy, const gfx::Rect& clip_rect, - const gfx::Size& view_size) { +void RenderWidgetHost::ScrollBackingStoreRect(HANDLE bitmap, + const gfx::Rect& bitmap_rect, + int dx, int dy, + const gfx::Rect& clip_rect, + const gfx::Size& view_size) { if (is_hidden_) { + // Don't bother updating the backing store when we're hidden. Just mark it + // as being totally invalid. This will cause a complete repaint when the + // view is restored. needs_repainting_on_restore_ = true; return; } @@ -800,19 +546,11 @@ void RenderWidgetHost::ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, 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); - - // TODO(darin): this doesn't work if dx and dy are both non-zero! - DCHECK(dx == 0 || dy == 0); - - // We expect that damaged_rect should equal bitmap_rect. - DCHECK(gfx::Rect(damaged_rect) == bitmap_rect); - - backing_store->Refresh(process_->process().handle(), bitmap, bitmap_rect); + backing_store->ScrollRect(process_->process().handle(), bitmap, bitmap_rect, + dx, dy, clip_rect, view_size); } + void RenderWidgetHost::RestartHangMonitorTimeout() { StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs)); } |