diff options
27 files changed, 510 insertions, 380 deletions
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h index 68514e4..387a564 100644 --- a/chrome/browser/renderer_host/backing_store.h +++ b/chrome/browser/renderer_host/backing_store.h @@ -98,9 +98,12 @@ class BackingStore { const gfx::Rect& bitmap_rect, const gfx::Rect& copy_rect); - // Scrolls the contents of clip_rect in the backing store by dx or dy (but dx - // and dy cannot both be non-zero). - void ScrollRect(int dx, int dy, + // 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, + TransportDIB* bitmap, const gfx::Rect& bitmap_rect, + int dx, int dy, const gfx::Rect& clip_rect, const gfx::Size& view_size); diff --git a/chrome/browser/renderer_host/backing_store_mac.mm b/chrome/browser/renderer_host/backing_store_mac.mm index 0b8fa6e..1de83b2 100644 --- a/chrome/browser/renderer_host/backing_store_mac.mm +++ b/chrome/browser/renderer_host/backing_store_mac.mm @@ -99,7 +99,10 @@ void BackingStore::PaintRect(base::ProcessHandle process, } // Scroll the contents of our CGLayer -void BackingStore::ScrollRect(int dx, int dy, +void BackingStore::ScrollRect(base::ProcessHandle process, + TransportDIB* bitmap, + const gfx::Rect& bitmap_rect, + int dx, int dy, const gfx::Rect& clip_rect, const gfx::Size& view_size) { DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap())); @@ -155,6 +158,9 @@ void BackingStore::ScrollRect(int dx, int dy, cg_bitmap_.swap(new_bitmap); } } + // Now paint the new bitmap data + PaintRect(process, bitmap, bitmap_rect, bitmap_rect); + return; } CGLayerRef BackingStore::CreateCGLayer() { diff --git a/chrome/browser/renderer_host/backing_store_win.cc b/chrome/browser/renderer_host/backing_store_win.cc index ae772dc..6cbaa34 100644 --- a/chrome/browser/renderer_host/backing_store_win.cc +++ b/chrome/browser/renderer_host/backing_store_win.cc @@ -146,7 +146,10 @@ void BackingStore::PaintRect(base::ProcessHandle process, reinterpret_cast<BITMAPINFO*>(&hdr)); } -void BackingStore::ScrollRect(int dx, int dy, +void BackingStore::ScrollRect(base::ProcessHandle process, + TransportDIB* bitmap, + const gfx::Rect& bitmap_rect, + int dx, int dy, const gfx::Rect& clip_rect, const gfx::Size& view_size) { RECT damaged_rect, r = clip_rect.ToRECT(); @@ -154,4 +157,9 @@ void BackingStore::ScrollRect(int dx, int dy, // 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); + + PaintRect(process, bitmap, bitmap_rect, bitmap_rect); } diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc index a1173b8..74ea8ac 100644 --- a/chrome/browser/renderer_host/backing_store_x.cc +++ b/chrome/browser/renderer_host/backing_store_x.cc @@ -311,7 +311,10 @@ void BackingStore::PaintRect(base::ProcessHandle process, XFreePixmap(display_, pixmap); } -void BackingStore::ScrollRect(int dx, int dy, +void BackingStore::ScrollRect(base::ProcessHandle process, + TransportDIB* bitmap, + const gfx::Rect& bitmap_rect, + int dx, int dy, const gfx::Rect& clip_rect, const gfx::Size& view_size) { if (!display_) @@ -343,6 +346,8 @@ void BackingStore::ScrollRect(int dx, int dy, clip_rect.y() /* dest x */); } } + + PaintRect(process, bitmap, bitmap_rect, bitmap_rect); } void BackingStore::ShowRect(const gfx::Rect& rect, XID target) { diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 2d7d2f8..a6f02a3 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -347,16 +347,15 @@ void BrowserRenderProcessHost::CrossSiteClosePageACK( widget_helper_->CrossSiteClosePageACK(params); } -bool BrowserRenderProcessHost::WaitForUpdateMsg( - int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg) { +bool BrowserRenderProcessHost::WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg) { // The post task to this thread with the process id could be in queue, and we // don't want to dispatch a message before then since it will need the handle. if (child_process_.get() && child_process_->IsStarting()) return false; - return widget_helper_->WaitForUpdateMsg(render_widget_id, max_delay, msg); + return widget_helper_->WaitForPaintMsg(render_widget_id, max_delay, msg); } void BrowserRenderProcessHost::ReceivedBadMessage(uint32 msg_type) { diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h index 3a6e83b..cd94bf5 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.h +++ b/chrome/browser/renderer_host/browser_render_process_host.h @@ -63,9 +63,9 @@ class BrowserRenderProcessHost : public RenderProcessHost, virtual int GetNextRoutingID(); virtual void CancelResourceRequests(int render_widget_id); virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params); - virtual bool WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg); + virtual bool WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg); virtual void ReceivedBadMessage(uint32 msg_type); virtual void WidgetRestored(); virtual void WidgetHidden(); diff --git a/chrome/browser/renderer_host/mock_render_process_host.cc b/chrome/browser/renderer_host/mock_render_process_host.cc index b18cc50..8be0416 100644 --- a/chrome/browser/renderer_host/mock_render_process_host.cc +++ b/chrome/browser/renderer_host/mock_render_process_host.cc @@ -31,9 +31,9 @@ void MockRenderProcessHost::CrossSiteClosePageACK( const ViewMsg_ClosePage_Params& params) { } -bool MockRenderProcessHost::WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg) { +bool MockRenderProcessHost::WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg) { return false; } diff --git a/chrome/browser/renderer_host/mock_render_process_host.h b/chrome/browser/renderer_host/mock_render_process_host.h index 70ed985..aa04651 100644 --- a/chrome/browser/renderer_host/mock_render_process_host.h +++ b/chrome/browser/renderer_host/mock_render_process_host.h @@ -35,9 +35,9 @@ class MockRenderProcessHost : public RenderProcessHost { virtual int GetNextRoutingID(); virtual void CancelResourceRequests(int render_widget_id); virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params); - virtual bool WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg); + virtual bool WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg); virtual void ReceivedBadMessage(uint32 msg_type); virtual void WidgetRestored(); virtual void WidgetHidden(); diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h index 7979d24..aad1f83 100644 --- a/chrome/browser/renderer_host/render_process_host.h +++ b/chrome/browser/renderer_host/render_process_host.h @@ -165,12 +165,12 @@ class RenderProcessHost : public IPC::Channel::Sender, virtual void CrossSiteClosePageACK( const ViewMsg_ClosePage_Params& params) = 0; - // Called on the UI thread to wait for the next UpdateRect message for the + // Called on the UI thread to wait for the next PaintRect message for the // specified render widget. Returns true if successful, and the msg out- - // param will contain a copy of the received UpdateRect message. - virtual bool WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg) = 0; + // param will contain a copy of the received PaintRect message. + virtual bool WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg) = 0; // Called when a received message cannot be decoded. virtual void ReceivedBadMessage(uint32 msg_type) = 0; diff --git a/chrome/browser/renderer_host/render_widget_helper.cc b/chrome/browser/renderer_host/render_widget_helper.cc index dffc9c5..8916c70 100644 --- a/chrome/browser/renderer_host/render_widget_helper.cc +++ b/chrome/browser/renderer_host/render_widget_helper.cc @@ -14,24 +14,24 @@ // A Task used with InvokeLater that we hold a pointer to in pending_paints_. // Instances are deleted by MessageLoop after it calls their Run method. -class RenderWidgetHelper::UpdateMsgProxy : public Task { +class RenderWidgetHelper::PaintMsgProxy : public Task { public: - UpdateMsgProxy(RenderWidgetHelper* h, const IPC::Message& m) + PaintMsgProxy(RenderWidgetHelper* h, const IPC::Message& m) : helper(h), message(m), cancelled(false) { } - ~UpdateMsgProxy() { + ~PaintMsgProxy() { // If the paint message was never dispatched, then we need to let the // helper know that we are going away. if (!cancelled && helper) - helper->OnDiscardUpdateMsg(this); + helper->OnDiscardPaintMsg(this); } virtual void Run() { if (!cancelled) { - helper->OnDispatchUpdateMsg(this); + helper->OnDispatchPaintMsg(this); helper = NULL; } } @@ -40,7 +40,7 @@ class RenderWidgetHelper::UpdateMsgProxy : public Task { IPC::Message message; bool cancelled; // If true, then the message will not be dispatched. - DISALLOW_COPY_AND_ASSIGN(UpdateMsgProxy); + DISALLOW_COPY_AND_ASSIGN(PaintMsgProxy); }; RenderWidgetHelper::RenderWidgetHelper() @@ -94,17 +94,17 @@ void RenderWidgetHelper::CrossSiteClosePageACK( params)); } -bool RenderWidgetHelper::WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg) { +bool RenderWidgetHelper::WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg) { base::TimeTicks time_start = base::TimeTicks::Now(); for (;;) { - UpdateMsgProxy* proxy = NULL; + PaintMsgProxy* proxy = NULL; { AutoLock lock(pending_paints_lock_); - UpdateMsgProxyMap::iterator it = pending_paints_.find(render_widget_id); + PaintMsgProxyMap::iterator it = pending_paints_.find(render_widget_id); if (it != pending_paints_.end()) { proxy = it->second; @@ -134,25 +134,25 @@ bool RenderWidgetHelper::WaitForUpdateMsg(int render_widget_id, return false; } -void RenderWidgetHelper::DidReceiveUpdateMsg(const IPC::Message& msg) { +void RenderWidgetHelper::DidReceivePaintMsg(const IPC::Message& msg) { int render_widget_id = msg.routing_id(); - UpdateMsgProxy* proxy = NULL; + PaintMsgProxy* proxy = NULL; { AutoLock lock(pending_paints_lock_); - UpdateMsgProxyMap::value_type new_value(render_widget_id, NULL); + PaintMsgProxyMap::value_type new_value(render_widget_id, NULL); // We expect only a single PaintRect message at a time. Optimize for the // case that we don't already have an entry by using the 'insert' method. - std::pair<UpdateMsgProxyMap::iterator, bool> result = + std::pair<PaintMsgProxyMap::iterator, bool> result = pending_paints_.insert(new_value); if (!result.second) { NOTREACHED() << "Unexpected PaintRect message!"; return; } - result.first->second = (proxy = new UpdateMsgProxy(this, msg)); + result.first->second = (proxy = new PaintMsgProxy(this, msg)); } // Notify anyone waiting on the UI thread that there is a new entry in the @@ -164,14 +164,14 @@ void RenderWidgetHelper::DidReceiveUpdateMsg(const IPC::Message& msg) { ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, proxy); } -void RenderWidgetHelper::OnDiscardUpdateMsg(UpdateMsgProxy* proxy) { +void RenderWidgetHelper::OnDiscardPaintMsg(PaintMsgProxy* proxy) { const IPC::Message& msg = proxy->message; // Remove the proxy from the map now that we are going to handle it normally. { AutoLock lock(pending_paints_lock_); - UpdateMsgProxyMap::iterator it = pending_paints_.find(msg.routing_id()); + PaintMsgProxyMap::iterator it = pending_paints_.find(msg.routing_id()); DCHECK(it != pending_paints_.end()); DCHECK(it->second == proxy); @@ -179,8 +179,8 @@ void RenderWidgetHelper::OnDiscardUpdateMsg(UpdateMsgProxy* proxy) { } } -void RenderWidgetHelper::OnDispatchUpdateMsg(UpdateMsgProxy* proxy) { - OnDiscardUpdateMsg(proxy); +void RenderWidgetHelper::OnDispatchPaintMsg(PaintMsgProxy* proxy) { + OnDiscardPaintMsg(proxy); // It is reasonable for the host to no longer exist. RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_); diff --git a/chrome/browser/renderer_host/render_widget_helper.h b/chrome/browser/renderer_host/render_widget_helper.h index d7e863e..1220970 100644 --- a/chrome/browser/renderer_host/render_widget_helper.h +++ b/chrome/browser/renderer_host/render_widget_helper.h @@ -37,20 +37,20 @@ struct ViewMsg_ClosePage_Params; // RenderWidgetHelper is used to implement optimized resize. When the // RenderWidgetHost is resized, it sends a Resize message to its RenderWidget // counterpart in the renderer process. The RenderWidget generates a -// UpdateRect message in response to the Resize message, and it sets the -// IS_RESIZE_ACK flag in the UpdateRect message to true. +// PaintRect message in response to the Resize message, and it sets the +// IS_RESIZE_ACK flag in the PaintRect message to true. // // Back in the browser process, when the RenderProcessHost's MessageFilter -// sees a UpdateRect message, it directs it to the RenderWidgetHelper by -// calling the DidReceiveUpdateMsg method. That method stores the data for -// the UpdateRect message in a map, where it can be directly accessed by the +// sees a PaintRect message, it directs it to the RenderWidgetHelper by +// calling the DidReceivePaintMsg method. That method stores the data for +// the PaintRect message in a map, where it can be directly accessed by the // RenderWidgetHost on the UI thread during a call to RenderWidgetHost's // GetBackingStore method. // // When the RenderWidgetHost's GetBackingStore method is called, it first // checks to see if it is waiting for a resize ack. If it is, then it calls -// the RenderWidgetHelper's WaitForUpdateMsg to check if there is already a -// resulting UpdateRect message (or to wait a short amount of time for one to +// the RenderWidgetHelper's WaitForPaintMsg to check if there is already a +// resulting PaintRect message (or to wait a short amount of time for one to // arrive). The main goal of this mechanism is to short-cut the usual way in // which IPC messages are proxied over to the UI thread via InvokeLater. // This approach is necessary since window resize is followed up immediately @@ -60,19 +60,19 @@ struct ViewMsg_ClosePage_Params; // OPTIMIZED TAB SWITCHING // // When a RenderWidgetHost is in a background tab, it is flagged as hidden. -// This causes the corresponding RenderWidget to stop sending UpdateRect +// This causes the corresponding RenderWidget to stop sending PaintRect // messages. The RenderWidgetHost also discards its backingstore when it is // hidden, which helps free up memory. As a result, when a RenderWidgetHost // is restored, it can be momentarily without a backingstore. (Restoring a // RenderWidgetHost results in a WasRestored message being sent to the -// RenderWidget, which triggers a full UpdateRect message.) This can lead to +// RenderWidget, which triggers a full PaintRect message.) This can lead to // an observed rendering glitch as the TabContents will just have to fill // white overtop the RenderWidgetHost until the RenderWidgetHost receives a -// UpdateRect message to refresh its backingstore. +// PaintRect message to refresh its backingstore. // // To avoid this 'white flash', the RenderWidgetHost again makes use of the -// RenderWidgetHelper's WaitForUpdateMsg method. When the RenderWidgetHost's -// GetBackingStore method is called, it will call WaitForUpdateMsg if it has +// RenderWidgetHelper's WaitForPaintMsg method. When the RenderWidgetHost's +// GetBackingStore method is called, it will call WaitForPaintMsg if it has // no backingstore. // // TRANSPORT DIB CREATION @@ -103,9 +103,9 @@ class RenderWidgetHelper // for documentation. void CancelResourceRequests(int render_widget_id); void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params); - bool WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg); + bool WaitForPaintMsg(int render_widget_id, + 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. @@ -115,8 +115,8 @@ class RenderWidgetHelper // IO THREAD ONLY ----------------------------------------------------------- - // Called on the IO thread when a UpdateRect message is received. - void DidReceiveUpdateMsg(const IPC::Message& msg); + // Called on the IO thread when a PaintRect message is received. + void DidReceivePaintMsg(const IPC::Message& msg); void CreateNewWindow(int opener_id, bool user_gesture, @@ -135,20 +135,20 @@ class RenderWidgetHelper private: // A class used to proxy a paint message. PaintMsgProxy objects are created // on the IO thread and destroyed on the UI thread. - class UpdateMsgProxy; - friend class UpdateMsgProxy; + class PaintMsgProxy; + friend class PaintMsgProxy; friend class base::RefCountedThreadSafe<RenderWidgetHelper>; // Map from render_widget_id to live PaintMsgProxy instance. - typedef base::hash_map<int, UpdateMsgProxy*> UpdateMsgProxyMap; + typedef base::hash_map<int, PaintMsgProxy*> PaintMsgProxyMap; ~RenderWidgetHelper(); // Called on the UI thread to discard a paint message. - void OnDiscardUpdateMsg(UpdateMsgProxy* proxy); + void OnDiscardPaintMsg(PaintMsgProxy* proxy); // Called on the UI thread to dispatch a paint message if necessary. - void OnDispatchUpdateMsg(UpdateMsgProxy* proxy); + void OnDispatchPaintMsg(PaintMsgProxy* proxy); // Called on the UI thread to finish creating a window. void OnCreateWindowOnUI(int opener_id, @@ -179,12 +179,12 @@ class RenderWidgetHelper // 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.) - UpdateMsgProxyMap pending_paints_; + PaintMsgProxyMap pending_paints_; Lock pending_paints_lock_; int render_process_id_; - // Event used to implement WaitForUpdateMsg. + // Event used to implement WaitForPaintMsg. base::WaitableEvent event_; // The next routing id to use. diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index ad94aa6..c40bbf8 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -124,7 +124,8 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewGone, OnMsgRenderViewGone) IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnMsgClose) IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove) - IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnMsgUpdateRect) + IPC_MESSAGE_HANDLER(ViewHostMsg_PaintRect, OnMsgPaintRect) + IPC_MESSAGE_HANDLER(ViewHostMsg_ScrollRect, OnMsgScrollRect) IPC_MESSAGE_HANDLER(ViewHostMsg_HandleInputEvent_ACK, OnMsgInputEventAck) IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnMsgFocus) IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur) @@ -298,9 +299,9 @@ BackingStore* RenderWidgetHost::GetBackingStore(bool force_create) { if (resize_ack_pending_ || !backing_store) { IPC::Message msg; TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); - if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) { - ViewHostMsg_UpdateRect::Dispatch( - &msg, this, &RenderWidgetHost::OnMsgUpdateRect); + if (process_->WaitForPaintMsg(routing_id_, max_delay, &msg)) { + ViewHostMsg_PaintRect::Dispatch( + &msg, this, &RenderWidgetHost::OnMsgPaintRect); backing_store = BackingStoreManager::GetBackingStore(this, current_size_); } } @@ -617,15 +618,15 @@ void RenderWidgetHost::OnMsgRequestMove(const gfx::Rect& pos) { } } -void RenderWidgetHost::OnMsgUpdateRect( - const ViewHostMsg_UpdateRect_Params& params) { +void RenderWidgetHost::OnMsgPaintRect( + const ViewHostMsg_PaintRect_Params& params) { TimeTicks paint_start = TimeTicks::Now(); // Update our knowledge of the RenderWidget's size. current_size_ = params.view_size; bool is_resize_ack = - ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags); + ViewHostMsg_PaintRect_Flags::is_resize_ack(params.flags); // resize_ack_pending_ needs to be cleared before we call DidPaintRect, since // that will end up reaching GetBackingStore. @@ -636,7 +637,7 @@ void RenderWidgetHost::OnMsgUpdateRect( } bool is_repaint_ack = - ViewHostMsg_UpdateRect_Flags::is_repaint_ack(params.flags); + ViewHostMsg_PaintRect_Flags::is_repaint_ack(params.flags); if (is_repaint_ack) { repaint_ack_pending_ = false; TimeDelta delta = TimeTicks::Now() - repaint_start_time_; @@ -652,19 +653,12 @@ void RenderWidgetHost::OnMsgUpdateRect( if (dib) { if (dib->size() < size) { DLOG(WARNING) << "Transport DIB too small for given rectangle"; - process()->ReceivedBadMessage(ViewHostMsg_UpdateRect__ID); + process()->ReceivedBadMessage(ViewHostMsg_PaintRect__ID); } else { - // Scroll the backing store. - if (!params.scroll_rect.IsEmpty()) { - ScrollBackingStoreRect(params.dx, params.dy, - params.scroll_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(dib, params.bitmap_rect, params.copy_rects, + PaintBackingStoreRect(dib, params.bitmap_rect, params.update_rects, params.view_size); } } @@ -673,7 +667,7 @@ void RenderWidgetHost::OnMsgUpdateRect( // 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_UpdateRect_ACK(routing_id_)); + Send(new ViewMsg_PaintRect_ACK(routing_id_)); // 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 @@ -685,12 +679,7 @@ void RenderWidgetHost::OnMsgUpdateRect( if (view_) { view_->MovePluginWindows(params.plugin_window_moves); view_being_painted_ = true; - if (!params.scroll_rect.IsEmpty()) { - view_->DidScrollBackingStoreRect(params.scroll_rect, - params.dx, - params.dy); - } - view_->DidPaintBackingStoreRects(params.copy_rects); + view_->DidPaintRect(params.bitmap_rect); view_being_painted_ = false; } @@ -711,7 +700,56 @@ void RenderWidgetHost::OnMsgUpdateRect( // Log the time delta for processing a paint message. TimeDelta delta = TimeTicks::Now() - paint_start; - UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgUpdateRect", delta); + UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgPaintRect", delta); +} + +void RenderWidgetHost::OnMsgScrollRect( + const ViewHostMsg_ScrollRect_Params& params) { + TimeTicks scroll_start = TimeTicks::Now(); + + DCHECK(!params.view_size.IsEmpty()); + + 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 + // 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_)); + + // 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; + + // 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; + } + + if (painting_observer_) + painting_observer_->WidgetDidUpdateBackingStore(this); + + // Log the time delta for processing a scroll message. + TimeDelta delta = TimeTicks::Now() - scroll_start; + UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgScrollRect", delta); } void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { @@ -853,7 +891,9 @@ void RenderWidgetHost::PaintBackingStoreRect( } } -void RenderWidgetHost::ScrollBackingStoreRect(int dx, int dy, +void RenderWidgetHost::ScrollBackingStoreRect(TransportDIB* bitmap, + const gfx::Rect& bitmap_rect, + int dx, int dy, const gfx::Rect& clip_rect, const gfx::Size& view_size) { if (is_hidden_) { @@ -870,7 +910,8 @@ void RenderWidgetHost::ScrollBackingStoreRect(int dx, int dy, BackingStore* backing_store = BackingStoreManager::Lookup(this); if (!backing_store || (backing_store->size() != view_size)) return; - backing_store->ScrollRect(dx, dy, clip_rect, view_size); + backing_store->ScrollRect(process_->GetHandle(), bitmap, bitmap_rect, + dx, dy, clip_rect, view_size); } void RenderWidgetHost::ToggleSpellPanel(bool is_currently_visible) { diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index d59fc4e..dc425b0 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -38,8 +38,9 @@ class RenderWidgetHostView; class RenderWidgetHostPaintingObserver; class TransportDIB; class WebCursor; +struct ViewHostMsg_PaintRect_Params; +struct ViewHostMsg_ScrollRect_Params; struct ViewHostMsg_ShowPopup_Params; -struct ViewHostMsg_UpdateRect_Params; // This class manages the browser side of a browser<->renderer HWND connection. // The HWND lives in the browser process, and windows events are sent over @@ -412,7 +413,8 @@ class RenderWidgetHost : public IPC::Channel::Listener, void OnMsgRenderViewGone(); void OnMsgClose(); void OnMsgRequestMove(const gfx::Rect& pos); - void OnMsgUpdateRect(const ViewHostMsg_UpdateRect_Params& params); + void OnMsgPaintRect(const ViewHostMsg_PaintRect_Params& params); + void OnMsgScrollRect(const ViewHostMsg_ScrollRect_Params& params); void OnMsgInputEventAck(const IPC::Message& message); void OnMsgFocus(); void OnMsgBlur(); @@ -442,7 +444,10 @@ class RenderWidgetHost : public IPC::Channel::Listener, // Scrolls the given |clip_rect| in the backing by the given dx/dy amount. The // |dib| and its corresponding location |bitmap_rect| in the backing store // is the newly painted pixels by the renderer. - void ScrollBackingStoreRect(int dx, int dy, const gfx::Rect& clip_rect, + void ScrollBackingStoreRect(TransportDIB* dib, + const gfx::Rect& bitmap_rect, + int dx, int dy, + const gfx::Rect& clip_rect, const gfx::Size& view_size); // Called by OnMsgInputEventAck() to process a keyboard event ack message. diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc index ba191fc..e3f4517 100644 --- a/chrome/browser/renderer_host/render_widget_host_unittest.cc +++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc @@ -21,9 +21,9 @@ class RenderWidgetHostProcess : public MockRenderProcessHost { public: explicit RenderWidgetHostProcess(Profile* profile) : MockRenderProcessHost(profile), - current_update_buf_(NULL), - update_msg_should_reply_(false), - update_msg_reply_flags_(0) { + current_paint_buf_(NULL), + paint_msg_should_reply_(false), + paint_msg_reply_flags_(0) { // DANGER! This is a hack. The RenderWidgetHost checks the channel to see // if the process is still alive, but it doesn't actually dereference it. // An IPC::SyncChannel is nontrivial, so we just fake it here. If you end up @@ -34,65 +34,64 @@ class RenderWidgetHostProcess : public MockRenderProcessHost { // We don't want to actually delete the channel, since it's not a real // pointer. channel_.release(); - delete current_update_buf_; + if (current_paint_buf_) + delete current_paint_buf_; } - void set_update_msg_should_reply(bool reply) { - update_msg_should_reply_ = reply; + void set_paint_msg_should_reply(bool reply) { + paint_msg_should_reply_ = reply; } - void set_update_msg_reply_flags(int flags) { - update_msg_reply_flags_ = flags; + void set_paint_msg_reply_flags(int flags) { + paint_msg_reply_flags_ = flags; } // Fills the given paint parameters with resonable default values. - void InitUpdateRectParams(ViewHostMsg_UpdateRect_Params* params); + void InitPaintRectParams(ViewHostMsg_PaintRect_Params* params); protected: - virtual bool WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg); + virtual bool WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg); - TransportDIB* current_update_buf_; + TransportDIB* current_paint_buf_; // Set to true when WaitForPaintMsg should return a successful paint messaage // reply. False implies timeout. - bool update_msg_should_reply_; + bool paint_msg_should_reply_; // Indicates the flags that should be sent with a the repaint request. This // only has an effect when paint_msg_should_reply_ is true. - int update_msg_reply_flags_; + int paint_msg_reply_flags_; DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostProcess); }; -void RenderWidgetHostProcess::InitUpdateRectParams( - ViewHostMsg_UpdateRect_Params* params) { +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 (!current_update_buf_) - current_update_buf_ = TransportDIB::Create(pixel_size, 0); - params->bitmap = current_update_buf_->id(); + if (!current_paint_buf_) + current_paint_buf_ = TransportDIB::Create(pixel_size, 0); + params->bitmap = current_paint_buf_->id(); params->bitmap_rect = gfx::Rect(0, 0, w, h); - params->dx = 0; - params->dy = 0; - params->copy_rects.push_back(params->bitmap_rect); + params->update_rects.push_back(params->bitmap_rect); params->view_size = gfx::Size(w, h); - params->flags = update_msg_reply_flags_; + params->flags = paint_msg_reply_flags_; } -bool RenderWidgetHostProcess::WaitForUpdateMsg(int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg) { - if (!update_msg_should_reply_) +bool RenderWidgetHostProcess::WaitForPaintMsg(int render_widget_id, + const base::TimeDelta& max_delay, + IPC::Message* msg) { + if (!paint_msg_should_reply_) return false; // Construct a fake paint reply. - ViewHostMsg_UpdateRect_Params params; - InitUpdateRectParams(¶ms); + ViewHostMsg_PaintRect_Params params; + InitPaintRectParams(¶ms); - ViewHostMsg_UpdateRect message(render_widget_id, params); + ViewHostMsg_PaintRect message(render_widget_id, params); *msg = message; return true; } @@ -252,9 +251,9 @@ TEST_F(RenderWidgetHostTest, Resize) { // Send out a paint that's not a resize ack. This should not clean the // resize ack pending flag. - ViewHostMsg_UpdateRect_Params params; - process_->InitUpdateRectParams(¶ms); - host_->OnMsgUpdateRect(params); + ViewHostMsg_PaintRect_Params params; + process_->InitPaintRectParams(¶ms); + host_->OnMsgPaintRect(params); EXPECT_TRUE(host_->resize_ack_pending_); EXPECT_EQ(original_size.size(), host_->in_flight_size_); @@ -272,9 +271,9 @@ TEST_F(RenderWidgetHostTest, Resize) { // this isn't the second_size, the message handler should immediately send // a new resize message for the new size to the renderer. process_->sink().ClearMessages(); - params.flags = ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; + params.flags = ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK; params.view_size = original_size.size(); - host_->OnMsgUpdateRect(params); + host_->OnMsgPaintRect(params); EXPECT_TRUE(host_->resize_ack_pending_); EXPECT_EQ(second_size.size(), host_->in_flight_size_); ASSERT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID)); @@ -282,7 +281,7 @@ TEST_F(RenderWidgetHostTest, Resize) { // Send the resize ack for the latest size. process_->sink().ClearMessages(); params.view_size = second_size.size(); - host_->OnMsgUpdateRect(params); + host_->OnMsgPaintRect(params); EXPECT_FALSE(host_->resize_ack_pending_); EXPECT_EQ(gfx::Size(), host_->in_flight_size_); ASSERT_FALSE(process_->sink().GetFirstMessageMatching(ViewMsg_Resize::ID)); @@ -399,42 +398,42 @@ TEST_F(RenderWidgetHostTest, Background) { TEST_F(RenderWidgetHostTest, GetBackingStore_NoRepaintAck) { // We don't currently have a backing store, and if the renderer doesn't send // one in time, we should get nothing. - process_->set_update_msg_should_reply(false); + process_->set_paint_msg_should_reply(false); BackingStore* backing = host_->GetBackingStore(true); EXPECT_FALSE(backing); // The widget host should have sent a request for a repaint, and there should // be no paint ACK. EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Repaint::ID)); EXPECT_FALSE(process_->sink().GetUniqueMessageMatching( - ViewMsg_UpdateRect_ACK::ID)); + ViewMsg_PaintRect_ACK::ID)); // Allowing the renderer to reply in time should give is a backing store. process_->sink().ClearMessages(); - process_->set_update_msg_should_reply(true); - process_->set_update_msg_reply_flags(0); + process_->set_paint_msg_should_reply(true); + process_->set_paint_msg_reply_flags(0); backing = host_->GetBackingStore(true); EXPECT_TRUE(backing); // The widget host should NOT have sent a request for a repaint, since there // was an ACK already pending. EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Repaint::ID)); EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( - ViewMsg_UpdateRect_ACK::ID)); + ViewMsg_PaintRect_ACK::ID)); } // Tests getting the backing store with the renderer sending a repaint ack. TEST_F(RenderWidgetHostTest, GetBackingStore_RepaintAck) { // Doing a request request with the paint message allowed should work and // the repaint ack should work. - process_->set_update_msg_should_reply(true); - process_->set_update_msg_reply_flags( - ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK); + process_->set_paint_msg_should_reply(true); + process_->set_paint_msg_reply_flags( + ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK); BackingStore* backing = host_->GetBackingStore(true); EXPECT_TRUE(backing); // We still should not have sent out a repaint request since the last flags // didn't have the repaint ack set, and the pending flag will still be set. EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Repaint::ID)); EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( - ViewMsg_UpdateRect_ACK::ID)); + ViewMsg_PaintRect_ACK::ID)); // Asking again for the backing store should just re-use the existing one // and not send any messagse. @@ -443,7 +442,7 @@ TEST_F(RenderWidgetHostTest, GetBackingStore_RepaintAck) { EXPECT_TRUE(backing); EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Repaint::ID)); EXPECT_FALSE(process_->sink().GetUniqueMessageMatching( - ViewMsg_UpdateRect_ACK::ID)); + ViewMsg_PaintRect_ACK::ID)); } // Test that we don't paint when we're hidden, but we still send the ACK. Most @@ -457,13 +456,13 @@ TEST_F(RenderWidgetHostTest, HiddenPaint) { // Send it a paint as from the renderer. process_->sink().ClearMessages(); - ViewHostMsg_UpdateRect_Params params; - process_->InitUpdateRectParams(¶ms); - host_->OnMsgUpdateRect(params); + ViewHostMsg_PaintRect_Params params; + process_->InitPaintRectParams(¶ms); + host_->OnMsgPaintRect(params); // It should have sent out the ACK. EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( - ViewMsg_UpdateRect_ACK::ID)); + ViewMsg_PaintRect_ACK::ID)); // Now unhide. process_->sink().ClearMessages(); diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index 2a87291..3a71011 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -110,14 +110,13 @@ class RenderWidgetHostView { // (Worse, we might recursively call RenderWidgetHost::GetBackingStore().) // Thus implementers should generally paint as much of |rect| as possible // synchronously with as little overpainting as possible. - virtual void DidPaintBackingStoreRects( - const std::vector<gfx::Rect>& rects) = 0; + virtual void DidPaintRect(const gfx::Rect& rect) = 0; // Informs the view that a portion of the widget's backing store was scrolled // by dx pixels horizontally and dy pixels vertically. The view should copy // the exposed pixels from the backing store of the render widget (which has // already been scrolled) onto the screen. - virtual void DidScrollBackingStoreRect( + virtual void DidScrollRect( const gfx::Rect& rect, int dx, int dy) = 0; // Notifies the View that the renderer has ceased to exist. diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index 8ce8747..cd38ec8 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -505,27 +505,21 @@ void RenderWidgetHostViewGtk::IMEUpdateStatus(int control, key_bindings_handler_->set_enabled(control != IME_DISABLE); } -void RenderWidgetHostViewGtk::DidPaintBackingStoreRects( - const std::vector<gfx::Rect>& rects) { +void RenderWidgetHostViewGtk::DidPaintRect(const gfx::Rect& rect) { if (is_hidden_) return; - for (size_t i = 0; i < rects.size(); ++i) { - if (about_to_validate_and_paint_) { - invalid_rect_ = invalid_rect_.Union(rects[i]); - } else { - Paint(rects[i]); - } - } + if (about_to_validate_and_paint_) + invalid_rect_ = invalid_rect_.Union(rect); + else + Paint(rect); } -void RenderWidgetHostViewGtk::DidScrollBackingStoreRect(const gfx::Rect& rect, - int dx, int dy) { +void RenderWidgetHostViewGtk::DidScrollRect(const gfx::Rect& rect, int dx, + int dy) { if (is_hidden_) return; - // TODO(darin): Implement the equivalent of Win32's ScrollWindowEX. Can that - // be done using XCopyArea? Perhaps similar to BackingStore::ScrollRect? Paint(rect); } diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h index 5c05094..94f4f1a 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h @@ -60,8 +60,8 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView { virtual void UpdateCursor(const WebCursor& cursor); virtual void SetIsLoading(bool is_loading); virtual void IMEUpdateStatus(int control, const gfx::Rect& caret_rect); - virtual void DidPaintBackingStoreRects(const std::vector<gfx::Rect>& rects); - virtual void DidScrollBackingStoreRect(const gfx::Rect& rect, int dx, int dy); + virtual void DidPaintRect(const gfx::Rect& rect); + virtual void DidScrollRect(const gfx::Rect& rect, int dx, int dy); virtual void RenderViewGone(); virtual void Destroy(); virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {} diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index 3dc07b2..c661578 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -95,8 +95,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void UpdateCursor(const WebCursor& cursor); virtual void SetIsLoading(bool is_loading); virtual void IMEUpdateStatus(int control, const gfx::Rect& caret_rect); - virtual void DidPaintBackingStoreRects(const std::vector<gfx::Rect>& rects); - virtual void DidScrollBackingStoreRect(const gfx::Rect& rect, int dx, int dy); + virtual void DidPaintRect(const gfx::Rect& rect); + virtual void DidScrollRect(const gfx::Rect& rect, int dx, int dy); virtual void RenderViewGone(); virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {}; virtual void Destroy(); diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index 55cfaef..78d2736 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -275,31 +275,26 @@ void RenderWidgetHostViewMac::IMEUpdateStatus(int control, caret_rect.width(), caret_rect.height()); } -void RenderWidgetHostViewMac::DidPaintBackingStoreRects( - const std::vector<gfx::Rect>& rects) { +void RenderWidgetHostViewMac::DidPaintRect(const gfx::Rect& rect) { if (is_hidden_) return; - for (size_t i = 0; i < rects.size(); ++i) { - NSRect ns_rect = [cocoa_view_ RectToNSRect:rects[i]]; - - if (about_to_validate_and_paint_) { - // As much as we'd like to use -setNeedsDisplayInRect: here, we can't. - // We're in the middle of executing a -drawRect:, and as soon as it - // returns Cocoa will clear its record of what needs display. If we want - // to handle the recursive drawing, we need to do it ourselves. - invalid_rect_ = NSUnionRect(invalid_rect_, ns_rect); - } else { - [cocoa_view_ setNeedsDisplayInRect:ns_rect]; - } - } + NSRect ns_rect = [cocoa_view_ RectToNSRect:rect]; - if (!about_to_validate_and_paint_) + if (about_to_validate_and_paint_) { + // As much as we'd like to use -setNeedsDisplayInRect: here, we can't. We're + // in the middle of executing a -drawRect:, and as soon as it returns Cocoa + // will clear its record of what needs display. If we want to handle the + // recursive drawing, we need to do it ourselves. + invalid_rect_ = NSUnionRect(invalid_rect_, ns_rect); + } else { + [cocoa_view_ setNeedsDisplayInRect:ns_rect]; [cocoa_view_ displayIfNeeded]; + } } -void RenderWidgetHostViewMac::DidScrollBackingStoreRect(const gfx::Rect& rect, - int dx, int dy) { +void RenderWidgetHostViewMac::DidScrollRect( + const gfx::Rect& rect, int dx, int dy) { if (is_hidden_) return; @@ -310,7 +305,7 @@ void RenderWidgetHostViewMac::DidScrollBackingStoreRect(const gfx::Rect& rect, // TODO(rohitrao): Evaluate how slow this full redraw is. If it // turns out to be a problem, consider scrolling only a portion of // the view, based on where the findbar and blocked popups are. - DidPaintBackingStoreRects(std::vector<gfx::Rect>(1, rect)); + DidPaintRect(rect); } void RenderWidgetHostViewMac::RenderViewGone() { diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc index 8be4df5..e0b3832 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc @@ -568,13 +568,7 @@ BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam) { return TRUE; } -void RenderWidgetHostViewWin::Redraw() { - RECT damage_bounds; - GetUpdateRect(&damage_bounds, FALSE); - - ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0)); - GetUpdateRgn(damage_region, FALSE); - +void RenderWidgetHostViewWin::Redraw(const gfx::Rect& rect) { // Paint the invalid region synchronously. Our caller will not paint again // until we return, so by painting to the screen here, we ensure effective // rate-limiting of backing store updates. This helps a lot on pages that @@ -585,11 +579,12 @@ void RenderWidgetHostViewWin::Redraw() { // message dispatching we allow scrolling to be smooth, and also avoid the // browser process locking up if the plugin process is hung. // - RedrawWindow(NULL, damage_region, RDW_UPDATENOW | RDW_NOCHILDREN); + RedrawWindow( + &rect.ToRECT(), NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN); // Send the invalid rect in screen coordinates. gfx::Rect screen_rect = GetViewBounds(); - gfx::Rect invalid_screen_rect(damage_bounds); + gfx::Rect invalid_screen_rect = rect; invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y()); LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect); @@ -624,29 +619,31 @@ void RenderWidgetHostViewWin::DrawResizeCorner(const gfx::Rect& paint_rect, } } -void RenderWidgetHostViewWin::DidPaintBackingStoreRects( - const std::vector<gfx::Rect>& rects) { +void RenderWidgetHostViewWin::DidPaintRect(const gfx::Rect& rect) { if (is_hidden_) return; - for (size_t i = 0; i < rects.size(); ++i) - InvalidateRect(&rects[i].ToRECT(), false); - - if (!about_to_validate_and_paint_) - Redraw(); + if (about_to_validate_and_paint_) + InvalidateRect(&rect.ToRECT(), false); + else + Redraw(rect); } -void RenderWidgetHostViewWin::DidScrollBackingStoreRect( +void RenderWidgetHostViewWin::DidScrollRect( const gfx::Rect& rect, int dx, int dy) { if (is_hidden_) return; - // We need to pass in SW_INVALIDATE to ScrollWindowEx. The documentation on - // MSDN states that it only applies to the HRGN argument, which is wrong. - // Not passing in this flag does not invalidate the region which was scrolled - // from, thus causing painting issues. + // We need to pass in SW_INVALIDATE to ScrollWindowEx. The MSDN + // documentation states that it only applies to the HRGN argument, which is + // wrong. Not passing in this flag does not invalidate the region which was + // scrolled from, thus causing painting issues. RECT clip_rect = rect.ToRECT(); ScrollWindowEx(dx, dy, NULL, &clip_rect, NULL, NULL, SW_INVALIDATE); + + RECT invalid_rect = {0}; + GetUpdateRect(&invalid_rect); + Redraw(gfx::Rect(invalid_rect)); } void RenderWidgetHostViewWin::RenderViewGone() { @@ -768,12 +765,6 @@ void RenderWidgetHostViewWin::OnPaint(HDC dc) { // GetBackingStore(), so that if it updates the invalid rect we'll catch the // changes and repaint them. about_to_validate_and_paint_ = false; - - // Grab the region to paint before creation of paint_dc since it clears the - // damage region. - ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0)); - GetUpdateRgn(damage_region, FALSE); - CPaintDC paint_dc(m_hWnd); gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint); @@ -781,38 +772,28 @@ void RenderWidgetHostViewWin::OnPaint(HDC dc) { return; if (backing_store) { - gfx::Rect bitmap_rect(gfx::Point(), backing_store->size()); - - bool manage_colors = BackingStore::ColorManagementEnabled(); - if (manage_colors) - SetICMMode(paint_dc.m_hDC, ICM_ON); - - // Blit only the damaged regions from the backing store. - DWORD data_size = GetRegionData(damage_region, 0, NULL); - scoped_array<char> region_data_buf(new char[data_size]); - RGNDATA* region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get()); - GetRegionData(damage_region, data_size, region_data); - - RECT* region_rects = reinterpret_cast<RECT*>(region_data->Buffer); - for (DWORD i = 0; i < region_data->rdh.nCount; ++i) { - gfx::Rect paint_rect = bitmap_rect.Intersect(gfx::Rect(region_rects[i])); - if (!paint_rect.IsEmpty()) { - DrawResizeCorner(paint_rect, backing_store->hdc()); - BitBlt(paint_dc.m_hDC, - paint_rect.x(), - paint_rect.y(), - paint_rect.width(), - paint_rect.height(), - backing_store->hdc(), - paint_rect.x(), - paint_rect.y(), - SRCCOPY); - } + gfx::Rect bitmap_rect( + 0, 0, backing_store->size().width(), backing_store->size().height()); + + gfx::Rect paint_rect = bitmap_rect.Intersect(damaged_rect); + if (!paint_rect.IsEmpty()) { + DrawResizeCorner(paint_rect, backing_store->hdc()); + bool manage_colors = BackingStore::ColorManagementEnabled(); + if (manage_colors) + SetICMMode(paint_dc.m_hDC, ICM_ON); + BitBlt(paint_dc.m_hDC, + paint_rect.x(), + paint_rect.y(), + paint_rect.width(), + paint_rect.height(), + backing_store->hdc(), + paint_rect.x(), + paint_rect.y(), + SRCCOPY); + if (manage_colors) + SetICMMode(paint_dc.m_hDC, ICM_OFF); } - if (manage_colors) - SetICMMode(paint_dc.m_hDC, ICM_OFF); - // Fill the remaining portion of the damaged_rect with the background if (damaged_rect.right() > bitmap_rect.right()) { RECT r; diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h index 3b54064..57b220b 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.h +++ b/chrome/browser/renderer_host/render_widget_host_view_win.h @@ -125,8 +125,8 @@ class RenderWidgetHostViewWin virtual void UpdateCursor(const WebCursor& cursor); virtual void SetIsLoading(bool is_loading); virtual void IMEUpdateStatus(int control, const gfx::Rect& caret_rect); - virtual void DidPaintBackingStoreRects(const std::vector<gfx::Rect>& rects); - virtual void DidScrollBackingStoreRect(const gfx::Rect& rect, int dx, int dy); + virtual void DidPaintRect(const gfx::Rect& rect); + virtual void DidScrollRect(const gfx::Rect& rect, int dx, int dy); virtual void RenderViewGone(); virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh); virtual void Destroy(); @@ -207,7 +207,7 @@ class RenderWidgetHostViewWin // Redraws the window synchronously, and any child windows (i.e. plugins) // asynchronously. - void Redraw(); + void Redraw(const gfx::Rect& invalid_rect); // Draw the resize corner bitmap on top of the given HDC, if it intersects the // given paint rect. diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index c0cc742..2bcccb2 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -326,8 +326,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_DnsPrefetch, OnDnsPrefetch) IPC_MESSAGE_HANDLER(ViewHostMsg_RendererHistograms, OnRendererHistograms) - IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect, - render_widget_helper_->DidReceiveUpdateMsg(msg)) + IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_PaintRect, + render_widget_helper_->DidReceivePaintMsg(msg)) IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsAsync, OnClipboardWriteObjects) IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsSync, diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index 9990fab..b1458a1 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -64,10 +64,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void UpdateCursor(const WebCursor& cursor) {} virtual void UpdateCursorIfOverSelf() {} virtual void IMEUpdateStatus(int control, const gfx::Rect& caret_rect) {} - virtual void DidPaintBackingStoreRects( - const std::vector<gfx::Rect>& rects) {} - virtual void DidScrollBackingStoreRect( - const gfx::Rect& rect, int dx, int dy) {} + virtual void DidPaintRect(const gfx::Rect& rect) {} + virtual void DidScrollRect(const gfx::Rect& rect, int dx, int dy) {} virtual void RenderViewGone() { delete this; } virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) { } virtual void Destroy() {} diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index c886522..9e2e6fc 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -176,8 +176,8 @@ struct ViewHostMsg_FrameNavigate_Params { }; // Values that may be OR'd together to form the 'flags' parameter of a -// ViewHostMsg_UpdateRect_Params structure. -struct ViewHostMsg_UpdateRect_Flags { +// ViewHostMsg_PaintRect message. +struct ViewHostMsg_PaintRect_Flags { enum { IS_RESIZE_ACK = 1 << 0, IS_RESTORE_ACK = 1 << 1, @@ -189,12 +189,13 @@ struct ViewHostMsg_UpdateRect_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_UpdateRect_Params { +struct ViewHostMsg_PaintRect_Params { // The bitmap to be painted into the view at the locations specified by // update_rects. TransportDIB::Id bitmap; @@ -202,18 +203,8 @@ struct ViewHostMsg_UpdateRect_Params { // The position and size of the bitmap. gfx::Rect bitmap_rect; - // The scroll offset. Only one of these can be non-zero, and if they are - // both zero, then it means there is no scrolling and the scroll_rect is - // ignored. - int dx; - int dy; - - // The rectangular region to scroll. - gfx::Rect scroll_rect; - // The regions of the bitmap (in view coords) that contain updated pixels. - // In the case of scrolling, this includes the scroll damage rect. - std::vector<gfx::Rect> copy_rects; + std::vector<gfx::Rect> update_rects; // The size of the RenderView when this message was generated. This is // included so the host knows how large the view is from the perspective of @@ -226,22 +217,42 @@ struct ViewHostMsg_UpdateRect_Params { // The following describes the various bits that may be set in flags: // - // ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK + // ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK // Indicates that this is a response to a ViewMsg_Resize message. // - // ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK + // ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK // Indicates that this is a response to a ViewMsg_WasRestored message. // - // ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK - // Indicates that this is a response to a ViewMsg_Repaint message. - // // If flags is zero, then this message corresponds to an unsoliticed paint - // request by the render view. Any of the above bits may be set in flags, + // request by the render view. Both of the above bits may be set in flags, // which would indicate that this paint message is an ACK for multiple // request messages. int flags; }; +// Parameters structure for ViewHostMsg_ScrollRect, which has too many data +// 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. + TransportDIB::Id bitmap; + + // The position and size of the bitmap. + gfx::Rect bitmap_rect; + + // The scroll offset. Only one of these can be non-zero. + int dx; + int dy; + + // The rectangular region to scroll. + gfx::Rect clip_rect; + + // The size of the RenderView when this message was generated. + gfx::Size view_size; + + // New window locations for plugin child windows. + std::vector<webkit_glue::WebPluginGeometry> plugin_window_moves; +}; + // Information on closing a tab. This is used both for ViewMsg_ClosePage, and // the corresponding ViewHostMsg_ClosePage_ACK. struct ViewMsg_ClosePage_Params { @@ -967,20 +978,56 @@ struct ParamTraits<ContextMenuParams> { } }; -// Traits for ViewHostMsg_UpdateRect_Params structure to pack/unpack. +// Traits for ViewHostMsg_PaintRect_Params structure to pack/unpack. template <> -struct ParamTraits<ViewHostMsg_UpdateRect_Params> { - typedef ViewHostMsg_UpdateRect_Params param_type; +struct ParamTraits<ViewHostMsg_PaintRect_Params> { + typedef ViewHostMsg_PaintRect_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.bitmap); + WriteParam(m, p.bitmap_rect); + WriteParam(m, p.update_rects); + WriteParam(m, p.view_size); + WriteParam(m, p.plugin_window_moves); + WriteParam(m, p.flags); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->bitmap) && + ReadParam(m, iter, &p->bitmap_rect) && + ReadParam(m, iter, &p->update_rects) && + ReadParam(m, iter, &p->view_size) && + ReadParam(m, iter, &p->plugin_window_moves) && + ReadParam(m, iter, &p->flags); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.bitmap, l); + l->append(L", "); + LogParam(p.bitmap_rect, l); + l->append(L", "); + LogParam(p.update_rects, l); + l->append(L", "); + LogParam(p.view_size, l); + l->append(L", "); + LogParam(p.plugin_window_moves, l); + l->append(L", "); + LogParam(p.flags, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_ScrollRect_Params structure to pack/unpack. +template <> +struct ParamTraits<ViewHostMsg_ScrollRect_Params> { + typedef ViewHostMsg_ScrollRect_Params param_type; static void Write(Message* m, const param_type& p) { WriteParam(m, p.bitmap); WriteParam(m, p.bitmap_rect); WriteParam(m, p.dx); WriteParam(m, p.dy); - WriteParam(m, p.scroll_rect); - WriteParam(m, p.copy_rects); + WriteParam(m, p.clip_rect); WriteParam(m, p.view_size); WriteParam(m, p.plugin_window_moves); - WriteParam(m, p.flags); } static bool Read(const Message* m, void** iter, param_type* p) { return @@ -988,11 +1035,9 @@ struct ParamTraits<ViewHostMsg_UpdateRect_Params> { ReadParam(m, iter, &p->bitmap_rect) && ReadParam(m, iter, &p->dx) && ReadParam(m, iter, &p->dy) && - ReadParam(m, iter, &p->scroll_rect) && - ReadParam(m, iter, &p->copy_rects) && + ReadParam(m, iter, &p->clip_rect) && ReadParam(m, iter, &p->view_size) && - ReadParam(m, iter, &p->plugin_window_moves) && - ReadParam(m, iter, &p->flags); + ReadParam(m, iter, &p->plugin_window_moves); } static void Log(const param_type& p, std::wstring* l) { l->append(L"("); @@ -1004,15 +1049,11 @@ struct ParamTraits<ViewHostMsg_UpdateRect_Params> { l->append(L", "); LogParam(p.dy, l); l->append(L", "); - LogParam(p.scroll_rect, l); - l->append(L", "); - LogParam(p.copy_rects, l); + LogParam(p.clip_rect, l); l->append(L", "); LogParam(p.view_size, l); l->append(L", "); LogParam(p.plugin_window_moves, l); - l->append(L", "); - LogParam(p.flags, l); l->append(L")"); } }; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index ca3e80b..3f9a1f1 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -128,6 +128,10 @@ IPC_BEGIN_MESSAGES(View) // render view responds with a ViewHostMsg_Thumbnail. IPC_MESSAGE_ROUTED0(ViewMsg_CaptureThumbnail) + // 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) + // Tells the render view to switch the CSS to print media type, renders every // requested pages and switch back the CSS to display media type. IPC_MESSAGE_ROUTED0(ViewMsg_PrintPages) @@ -143,9 +147,9 @@ IPC_BEGIN_MESSAGES(View) // JS garbage, not in purging irreplaceable objects. IPC_MESSAGE_CONTROL0(ViewMsg_PurgeMemory) - // Tells the render view that a ViewHostMsg_UpdateRect message was processed. - // This signals the render view that it can send another UpdateRect message. - IPC_MESSAGE_ROUTED0(ViewMsg_UpdateRect_ACK) + // Tells the render view that a ViewHostMsg_ScrollRect message was processed. + // This signals the render view that it can send another ScrollRect message. + IPC_MESSAGE_ROUTED0(ViewMsg_ScrollRect_ACK) // Message payload includes: // 1. A blob that should be cast to WebInputEvent @@ -989,10 +993,15 @@ IPC_BEGIN_MESSAGES(ViewHost) navigating to a POST again and we're going to show the POST interstitial */ ) - // Sent to update part of the view. In response to this message, the host - // generates a ViewMsg_UpdateRect_ACK message. - IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateRect, - ViewHostMsg_UpdateRect_Params) + // Sent to paint part of the view. In response to this message, the host + // generates a ViewMsg_PaintRect_ACK message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_PaintRect, + ViewHostMsg_PaintRect_Params) + + // Sent to scroll part of the view. In response to this message, the host + // generates a ViewMsg_ScrollRect_ACK message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ScrollRect, + ViewHostMsg_ScrollRect_Params) // Acknowledges receipt of a ViewMsg_HandleInputEvent message. // Payload is a WebInputEvent::Type which is the type of the event, followed diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc index 8a3513c..27955bb 100644 --- a/chrome/renderer/render_widget.cc +++ b/chrome/renderer/render_widget.cc @@ -50,8 +50,9 @@ RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable) render_thread_(render_thread), host_window_(0), current_paint_buf_(NULL), + current_scroll_buf_(NULL), next_paint_flags_(0), - update_reply_pending_(false), + paint_reply_pending_(false), did_show_(false), is_hidden_(false), needs_repainting_on_restore_(false), @@ -78,6 +79,10 @@ RenderWidget::~RenderWidget() { RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); current_paint_buf_ = NULL; } + if (current_scroll_buf_) { + RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_); + current_scroll_buf_ = NULL; + } RenderProcess::current()->ReleaseProcess(); } @@ -137,7 +142,8 @@ IPC_DEFINE_MESSAGE_MAP(RenderWidget) IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize) IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored) - IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck) + IPC_MESSAGE_HANDLER(ViewMsg_PaintRect_ACK, OnPaintRectAck) + IPC_MESSAGE_HANDLER(ViewMsg_ScrollRect_ACK, OnScrollRectAck) IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent) IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost) IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus) @@ -252,17 +258,11 @@ void RenderWidget::OnWasRestored(bool needs_repainting) { didInvalidateRect(gfx::Rect(size_.width(), size_.height())); } -void RenderWidget::OnRequestMoveAck() { - DCHECK(pending_window_rect_count_); - pending_window_rect_count_--; -} - -void RenderWidget::OnUpdateRectAck() { - DCHECK(update_reply_pending()); - update_reply_pending_ = false; - - // If we sent an UpdateRect message with a zero-sized bitmap, then we should - // have no current update buf. +void RenderWidget::OnPaintRectAck() { + 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::current()->ReleaseTransportDIB(current_paint_buf_); current_paint_buf_ = NULL; @@ -275,6 +275,23 @@ void RenderWidget::OnUpdateRectAck() { CallDoDeferredUpdate(); } +void RenderWidget::OnRequestMoveAck() { + DCHECK(pending_window_rect_count_); + pending_window_rect_count_--; +} + +void RenderWidget::OnScrollRectAck() { + DCHECK(scroll_reply_pending()); + + if (current_scroll_buf_) { + RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_); + current_scroll_buf_ = NULL; + } + + // Continue scrolling if necessary... + CallDoDeferredUpdate(); +} + void RenderWidget::OnHandleInputEvent(const IPC::Message& message) { void* iter = NULL; @@ -388,17 +405,9 @@ void RenderWidget::PaintDebugBorder(const gfx::Rect& rect, if (!kPaintBorder) return; - // Cycle through these colors to help distinguish new paint rects. - const SkColor colors[] = { - SkColorSetARGB(0x3F, 0xFF, 0, 0), - SkColorSetARGB(0x3F, 0xFF, 0, 0xFF), - SkColorSetARGB(0x3F, 0, 0, 0xFF), - }; - static int color_selector = 0; - SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); - paint.setColor(colors[color_selector++ % arraysize(colors)]); + paint.setColor(SkColorSetARGB(0x3F, 0xFF, 0, 0)); paint.setStrokeWidth(1); SkIRect irect; @@ -417,7 +426,7 @@ void RenderWidget::CallDoDeferredUpdate() { void RenderWidget::DoDeferredUpdate() { if (!webwidget_ || !paint_aggregator_.HasPendingUpdate() || - update_reply_pending()) + paint_reply_pending() || scroll_reply_pending()) return; // Suppress updating when we are hidden. @@ -435,56 +444,86 @@ void RenderWidget::DoDeferredUpdate() { PaintAggregator::PendingUpdate update = paint_aggregator_.GetPendingUpdate(); paint_aggregator_.ClearPendingUpdate(); - gfx::Rect scroll_damage = update.GetScrollDamage(); - gfx::Rect bounds = update.GetPaintBounds().Union(scroll_damage); + if (!update.scroll_rect.IsEmpty()) { + // Optmized scrolling - // Compute a buffer for painting and cache it. - scoped_ptr<skia::PlatformCanvas> canvas( - RenderProcess::current()->GetDrawingCanvas(¤t_paint_buf_, bounds)); - if (!canvas.get()) { - NOTREACHED(); - return; - } + // Compute the region we will expose by scrolling, and paint that into a + // shared memory section. + gfx::Rect damaged_rect = update.GetScrollDamage(); - // We may get back a smaller canvas than we asked for. - // TODO(darin): This seems like it could cause painting problems! - DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); - DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); - bounds.set_width(canvas->getDevice()->width()); - bounds.set_height(canvas->getDevice()->height()); - - HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size()); - - // The scroll damage is just another rectangle to paint and copy. - std::vector<gfx::Rect> copy_rects; - copy_rects.swap(update.paint_rects); - if (!scroll_damage.IsEmpty()) - copy_rects.push_back(scroll_damage); - - // TODO(darin): Re-enable painting multiple damage rects once the - // page-cycler regressions are resolved. See bug 29589. - if (update.scroll_rect.IsEmpty()) { - update.paint_rects.clear(); - update.paint_rects.push_back(bounds); + scoped_ptr<skia::PlatformCanvas> canvas( + RenderProcess::current()->GetDrawingCanvas(¤t_scroll_buf_, + damaged_rect)); + if (!canvas.get()) { + NOTREACHED(); + return; + } + + // We may get back a smaller canvas than we asked for. + damaged_rect.set_width(canvas->getDevice()->width()); + damaged_rect.set_height(canvas->getDevice()->height()); + + // Set these parameters before calling Paint, since that could result in + // further invalidates (uncommon). + ViewHostMsg_ScrollRect_Params params; + params.bitmap_rect = damaged_rect; + params.dx = update.scroll_delta.x(); + params.dy = update.scroll_delta.y(); + params.clip_rect = update.scroll_rect; + params.view_size = size_; + params.plugin_window_moves = plugin_window_moves_; + params.bitmap = current_scroll_buf_->id(); + + plugin_window_moves_.clear(); + + PaintRect(damaged_rect, damaged_rect.origin(), canvas.get()); + Send(new ViewHostMsg_ScrollRect(routing_id_, params)); } - for (size_t i = 0; i < copy_rects.size(); ++i) - PaintRect(copy_rects[i], bounds.origin(), canvas.get()); + if (!update.paint_rects.empty()) { + // Normal painting + + gfx::Rect bounds = update.GetPaintBounds(); + + // Compute a buffer for painting and cache it. + scoped_ptr<skia::PlatformCanvas> canvas( + RenderProcess::current()->GetDrawingCanvas(¤t_paint_buf_, + bounds)); + if (!canvas.get()) { + NOTREACHED(); + return; + } + + // We may get back a smaller canvas than we asked for. + bounds.set_width(canvas->getDevice()->width()); + bounds.set_height(canvas->getDevice()->height()); + + HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size()); + + // TODO(darin): Re-enable painting multiple damage rects once the + // page-cycler regressions are resolved. See bug 29589. + if (update.scroll_rect.IsEmpty()) { + update.paint_rects.clear(); + update.paint_rects.push_back(bounds); + } + + for (size_t i = 0; i < update.paint_rects.size(); ++i) + PaintRect(update.paint_rects[i], bounds.origin(), canvas.get()); - ViewHostMsg_UpdateRect_Params params; - params.bitmap = current_paint_buf_->id(); - params.bitmap_rect = bounds; - params.dx = update.scroll_delta.x(); - params.dy = update.scroll_delta.y(); - params.scroll_rect = update.scroll_rect; - params.copy_rects.swap(copy_rects); // TODO(darin): clip to bounds? - params.view_size = size_; - params.plugin_window_moves.swap(plugin_window_moves_); - params.flags = next_paint_flags_; + ViewHostMsg_PaintRect_Params params; + params.bitmap_rect = bounds; + params.update_rects = update.paint_rects; // TODO(darin): clip to bounds? + params.view_size = size_; + params.plugin_window_moves = plugin_window_moves_; + params.flags = next_paint_flags_; + params.bitmap = current_paint_buf_->id(); - update_reply_pending_ = true; - Send(new ViewHostMsg_UpdateRect(routing_id_, params)); - next_paint_flags_ = 0; + plugin_window_moves_.clear(); + + paint_reply_pending_ = true; + Send(new ViewHostMsg_PaintRect(routing_id_, params)); + next_paint_flags_ = 0; + } UpdateIME(); } @@ -509,7 +548,7 @@ void RenderWidget::didInvalidateRect(const WebRect& rect) { return; if (!paint_aggregator_.HasPendingUpdate()) return; - if (update_reply_pending()) + if (paint_reply_pending() || scroll_reply_pending()) return; // Perform updating asynchronously. This serves two purposes: @@ -538,7 +577,7 @@ void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) { return; if (!paint_aggregator_.HasPendingUpdate()) return; - if (update_reply_pending()) + if (paint_reply_pending() || scroll_reply_pending()) return; // Perform updating asynchronously. This serves two purposes: @@ -734,23 +773,23 @@ void RenderWidget::SetBackground(const SkBitmap& background) { } bool RenderWidget::next_paint_is_resize_ack() const { - return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_); + return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_); } bool RenderWidget::next_paint_is_restore_ack() const { - return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_); + return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_); } void RenderWidget::set_next_paint_is_resize_ack() { - next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; + next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK; } void RenderWidget::set_next_paint_is_restore_ack() { - next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK; + next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK; } void RenderWidget::set_next_paint_is_repaint_ack() { - next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK; + next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK; } void RenderWidget::UpdateIME() { diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h index 4cf033e..c25c99a 100644 --- a/chrome/renderer/render_widget.h +++ b/chrome/renderer/render_widget.h @@ -142,7 +142,8 @@ class RenderWidget : public IPC::Channel::Listener, const gfx::Rect& resizer_rect); void OnWasHidden(); void OnWasRestored(bool needs_repainting); - void OnUpdateRectAck(); + void OnPaintRectAck(); + void OnScrollRectAck(); void OnRequestMoveAck(); void OnHandleInputEvent(const IPC::Message& message); void OnMouseCaptureLost(); @@ -166,9 +167,14 @@ class RenderWidget : public IPC::Channel::Listener, bool is_hidden() const { return is_hidden_; } - // True if an UpdateRect_ACK message is pending. - bool update_reply_pending() const { - return update_reply_pending_; + // True if a PaintRect_ACK message is pending. + bool paint_reply_pending() const { + return paint_reply_pending_; + } + + // True if a ScrollRect_ACK message is pending. + bool scroll_reply_pending() const { + return current_scroll_buf_ != NULL; } bool next_paint_is_resize_ack() const; @@ -232,20 +238,22 @@ class RenderWidget : public IPC::Channel::Listener, // The size of the RenderWidget. gfx::Size size_; - // The TransportDIB that is being used to transfer an image to the browser. + // Transport DIBs that are currently in use to transfer an image to the + // browser. TransportDIB* current_paint_buf_; + TransportDIB* current_scroll_buf_; PaintAggregator paint_aggregator_; // The area that must be reserved for drawing the resize corner. gfx::Rect resizer_rect_; - // Flags for the next ViewHostMsg_UpdateRect message. + // Flags for the next ViewHostMsg_PaintRect message. int next_paint_flags_; - // True if we are expecting an UpdateRect_ACK message (i.e., that a - // UpdateRect message has been sent). - bool update_reply_pending_; + // True if we are expecting a PaintRect_ACK message (i.e., that a PaintRect + // message has been sent). + bool paint_reply_pending_; // Set to true if we should ignore RenderWidget::Show calls. bool did_show_; |