Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6440)

Unified Diff: chrome/renderer/render_widget.cc

Issue 403005: Refactors RenderWidget to extract a PaintAggregator class.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/renderer/render_widget.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/renderer/render_widget.cc
===================================================================
--- chrome/renderer/render_widget.cc (revision 32494)
+++ chrome/renderer/render_widget.cc (working copy)
@@ -215,18 +215,16 @@
// We should not be sent a Resize message if we have not ACK'd the previous
DCHECK(!next_paint_is_resize_ack());
+ paint_aggregator_.ClearPendingUpdate();
+
// When resizing, we want to wait to paint before ACK'ing the resize. This
// ensures that we only resize as fast as we can paint. We only need to send
// an ACK if we are resized to a non-empty rect.
webwidget_->resize(new_size);
if (!new_size.IsEmpty()) {
- DCHECK(!paint_rect_.IsEmpty());
+ // Resize should have caused an invalidation of the entire view.
+ DCHECK(paint_aggregator_.HasPendingUpdate());
- // This should have caused an invalidation of the entire view. The damaged
- // rect could be larger than new_size if we are being made smaller.
- DCHECK_GE(paint_rect_.width(), new_size.width());
- DCHECK_GE(paint_rect_.height(), new_size.height());
-
// We will send the Resize_ACK flag once we paint again.
set_next_paint_is_resize_ack();
}
@@ -271,7 +269,7 @@
DidPaint();
// Continue painting if necessary...
- CallDoDeferredPaint();
+ CallDoDeferredUpdate();
}
void RenderWidget::OnRequestMoveAck() {
@@ -288,18 +286,9 @@
}
// Continue scrolling if necessary...
- CallDoDeferredScroll();
+ CallDoDeferredUpdate();
}
-void RenderWidget::CallDoDeferredScroll() {
- DoDeferredScroll();
-
- if (pending_input_event_ack_.get()) {
- Send(pending_input_event_ack_.get());
- pending_input_event_ack_.release();
- }
-}
-
void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
void* iter = NULL;
@@ -322,7 +311,7 @@
response->WriteBool(processed);
if (input_event->type == WebInputEvent::MouseMove &&
- (!paint_rect_.IsEmpty() || !scroll_rect_.IsEmpty())) {
+ paint_aggregator_.HasPendingUpdate()) {
// We want to rate limit the input events in this case, so we'll wait for
// painting to finish before ACKing this message.
pending_input_event_ack_.reset(response);
@@ -387,8 +376,8 @@
canvas->getTopPlatformDevice().accessBitmap(false);
}
-void RenderWidget::CallDoDeferredPaint() {
- DoDeferredPaint();
+void RenderWidget::CallDoDeferredUpdate() {
+ DoDeferredUpdate();
if (pending_input_event_ack_.get()) {
Send(pending_input_event_ack_.get());
@@ -396,140 +385,96 @@
}
}
-void RenderWidget::DoDeferredPaint() {
- if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
+void RenderWidget::DoDeferredUpdate() {
+ if (!webwidget_ || !paint_aggregator_.HasPendingUpdate() ||
+ paint_reply_pending() || scroll_reply_pending())
return;
- // When we are hidden, we want to suppress painting, but we still need to
- // mark this DoDeferredPaint as complete.
+ // Suppress updating when we are hidden.
if (is_hidden_ || size_.IsEmpty()) {
- paint_rect_ = gfx::Rect();
+ paint_aggregator_.ClearPendingUpdate();
needs_repainting_on_restore_ = true;
return;
}
- // Layout may generate more invalidation...
+ // Layout may generate more invalidation.
webwidget_->layout();
- // OK, save the current paint_rect to a local since painting may cause more
+ // OK, save the pending update to a local since painting may cause more
// invalidation. Some WebCore rendering objects only layout when painted.
- gfx::Rect damaged_rect = paint_rect_;
- paint_rect_ = gfx::Rect();
+ PaintAggregator::PendingUpdate update = paint_aggregator_.GetPendingUpdate();
+ paint_aggregator_.ClearPendingUpdate();
- // Compute a buffer for painting and cache it.
- skia::PlatformCanvas* canvas =
- RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
- damaged_rect);
- if (!canvas) {
- NOTREACHED();
- return;
- }
+ if (!update.scroll_rect.IsEmpty()) {
+ // Optmized scrolling
- // 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());
+ // Compute the region we will expose by scrolling, and paint that into a
+ // shared memory section.
+ gfx::Rect damaged_rect = update.GetScrollDamage();
- PaintRect(damaged_rect, canvas);
+ scoped_ptr<skia::PlatformCanvas> canvas(
+ RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_,
+ damaged_rect));
+ if (!canvas.get()) {
+ NOTREACHED();
+ return;
+ }
- ViewHostMsg_PaintRect_Params params;
- params.bitmap_rect = damaged_rect;
- params.view_size = size_;
- params.plugin_window_moves = plugin_window_moves_;
- params.flags = next_paint_flags_;
- params.bitmap = current_paint_buf_->id();
+ // 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());
- delete canvas;
+ // 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();
+ plugin_window_moves_.clear();
- paint_reply_pending_ = true;
- Send(new ViewHostMsg_PaintRect(routing_id_, params));
- next_paint_flags_ = 0;
-
- UpdateIME();
-}
-
-void RenderWidget::DoDeferredScroll() {
- if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
- return;
-
- // When we are hidden, we want to suppress scrolling, but we still need to
- // mark this DoDeferredScroll as complete.
- if (is_hidden_ || size_.IsEmpty()) {
- scroll_rect_ = gfx::Rect();
- needs_repainting_on_restore_ = true;
- return;
+ PaintRect(damaged_rect, canvas.get());
+ Send(new ViewHostMsg_ScrollRect(routing_id_, params));
}
- // Layout may generate more invalidation, so we might have to bail on
- // optimized scrolling...
- webwidget_->layout();
+ if (!update.paint_rect.IsEmpty()) {
+ // Normal painting
- if (scroll_rect_.IsEmpty())
- return;
+ gfx::Rect damaged_rect = update.paint_rect;
- gfx::Rect damaged_rect;
-
- // Compute the region we will expose by scrolling, and paint that into a
- // shared memory section.
- if (scroll_delta_.x()) {
- int dx = scroll_delta_.x();
- damaged_rect.set_y(scroll_rect_.y());
- damaged_rect.set_height(scroll_rect_.height());
- if (dx > 0) {
- damaged_rect.set_x(scroll_rect_.x());
- damaged_rect.set_width(dx);
- } else {
- damaged_rect.set_x(scroll_rect_.right() + dx);
- damaged_rect.set_width(-dx);
+ // Compute a buffer for painting and cache it.
+ scoped_ptr<skia::PlatformCanvas> canvas(
+ RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
+ damaged_rect));
+ if (!canvas.get()) {
+ NOTREACHED();
+ return;
}
- } else {
- int dy = scroll_delta_.y();
- damaged_rect.set_x(scroll_rect_.x());
- damaged_rect.set_width(scroll_rect_.width());
- if (dy > 0) {
- damaged_rect.set_y(scroll_rect_.y());
- damaged_rect.set_height(dy);
- } else {
- damaged_rect.set_y(scroll_rect_.bottom() + dy);
- damaged_rect.set_height(-dy);
- }
- }
- // In case the scroll offset exceeds the width/height of the scroll rect
- damaged_rect = scroll_rect_.Intersect(damaged_rect);
+ // 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());
- skia::PlatformCanvas* canvas =
- RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_,
- damaged_rect);
- if (!canvas) {
- NOTREACHED();
- return;
- }
+ PaintRect(damaged_rect, canvas.get());
- // 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());
+ ViewHostMsg_PaintRect_Params params;
+ params.bitmap_rect = damaged_rect;
+ params.view_size = size_;
+ params.plugin_window_moves = plugin_window_moves_;
+ params.flags = next_paint_flags_;
+ params.bitmap = current_paint_buf_->id();
- // 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 = scroll_delta_.x();
- params.dy = scroll_delta_.y();
- params.clip_rect = scroll_rect_;
- params.view_size = size_;
- params.plugin_window_moves = plugin_window_moves_;
- params.bitmap = current_scroll_buf_->id();
+ plugin_window_moves_.clear();
- plugin_window_moves_.clear();
+ paint_reply_pending_ = true;
+ Send(new ViewHostMsg_PaintRect(routing_id_, params));
+ next_paint_flags_ = 0;
+ }
- // Mark the scroll operation as no longer pending.
- scroll_rect_ = gfx::Rect();
-
- PaintRect(damaged_rect, canvas);
- Send(new ViewHostMsg_ScrollRect(routing_id_, params));
- delete canvas;
UpdateIME();
}
@@ -537,77 +482,61 @@
// WebWidgetDelegate
void RenderWidget::didInvalidateRect(const WebRect& rect) {
- // We only want one pending DoDeferredPaint call at any time...
- bool paint_pending = !paint_rect_.IsEmpty();
+ // We only want one pending DoDeferredUpdate call at any time...
+ bool update_pending = paint_aggregator_.HasPendingUpdate();
- // If this invalidate overlaps with a pending scroll, then we have to
- // downgrade to invalidating the scroll rect.
- if (gfx::Rect(rect).Intersects(scroll_rect_)) {
- paint_rect_ = paint_rect_.Union(scroll_rect_);
- scroll_rect_ = gfx::Rect();
- }
-
+ // The invalidated rect might be outside the bounds of the view.
gfx::Rect view_rect(0, 0, size_.width(), size_.height());
- // TODO(iyengar) Investigate why we have painting issues when
- // we ignore invalid regions outside the view.
- // Ignore invalidates that occur outside the bounds of the view
- // TODO(darin): maybe this should move into the paint code?
- // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
- paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
+ gfx::Rect damaged_rect = view_rect.Intersect(rect);
+ if (damaged_rect.IsEmpty())
+ return;
- if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
+ paint_aggregator_.InvalidateRect(damaged_rect);
+
+ // We may not need to schedule another call to DoDeferredUpdate.
+ if (update_pending)
return;
+ if (!paint_aggregator_.HasPendingUpdate())
+ return;
+ if (paint_reply_pending() || scroll_reply_pending())
+ return;
- // Perform painting asynchronously. This serves two purposes:
+ // Perform updating asynchronously. This serves two purposes:
// 1) Ensures that we call WebView::Paint without a bunch of other junk
// on the call stack.
// 2) Allows us to collect more damage rects before painting to help coalesce
// the work that we will need to do.
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &RenderWidget::CallDoDeferredPaint));
+ this, &RenderWidget::CallDoDeferredUpdate));
}
void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) {
- if (dx != 0 && dy != 0) {
- // We only support scrolling along one axis at a time.
- didScrollRect(0, dy, clip_rect);
- dy = 0;
- }
+ // We only want one pending DoDeferredUpdate call at any time...
+ bool update_pending = paint_aggregator_.HasPendingUpdate();
- bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
-
- // If we already have a pending scroll operation or if this scroll operation
- // intersects the existing paint region, then just failover to invalidating.
- if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
- if (!intersects_with_painting && scroll_rect_ == gfx::Rect(clip_rect)) {
- // OK, we can just update the scroll delta (requires same scrolling axis)
- if (!dx && !scroll_delta_.x()) {
- scroll_delta_.set_y(scroll_delta_.y() + dy);
- return;
- }
- if (!dy && !scroll_delta_.y()) {
- scroll_delta_.set_x(scroll_delta_.x() + dx);
- return;
- }
- }
- didInvalidateRect(scroll_rect_);
- DCHECK(scroll_rect_.IsEmpty());
- didInvalidateRect(clip_rect);
+ // The scrolled rect might be outside the bounds of the view.
+ gfx::Rect view_rect(0, 0, size_.width(), size_.height());
+ gfx::Rect damaged_rect = view_rect.Intersect(clip_rect);
+ if (damaged_rect.IsEmpty())
return;
- }
- // We only want one pending DoDeferredScroll call at any time...
- bool scroll_pending = !scroll_rect_.IsEmpty();
+ paint_aggregator_.ScrollRect(dx, dy, damaged_rect);
- scroll_rect_ = clip_rect;
- scroll_delta_.SetPoint(dx, dy);
-
- if (scroll_pending)
+ // We may not need to schedule another call to DoDeferredUpdate.
+ if (update_pending)
return;
+ if (!paint_aggregator_.HasPendingUpdate())
+ return;
+ if (paint_reply_pending() || scroll_reply_pending())
+ return;
- // Perform scrolling asynchronously since we need to call WebView::Paint
+ // Perform updating asynchronously. This serves two purposes:
+ // 1) Ensures that we call WebView::Paint without a bunch of other junk
+ // on the call stack.
+ // 2) Allows us to collect more damage rects before painting to help coalesce
+ // the work that we will need to do.
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &RenderWidget::CallDoDeferredScroll));
+ this, &RenderWidget::CallDoDeferredUpdate));
}
void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) {
« no previous file with comments | « chrome/renderer/render_widget.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698