summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/paint_aggregator.cc
diff options
context:
space:
mode:
authordarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-19 05:24:57 +0000
committerdarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-19 05:24:57 +0000
commit552e600db9f51ac1efb0438bd749227226dffa64 (patch)
tree121e6a11a6f637e9b5cfd2d04244c94b1961420f /chrome/renderer/paint_aggregator.cc
parent0dea18f231b425216aae0c956129bc80b7086770 (diff)
downloadchromium_src-552e600db9f51ac1efb0438bd749227226dffa64.zip
chromium_src-552e600db9f51ac1efb0438bd749227226dffa64.tar.gz
chromium_src-552e600db9f51ac1efb0438bd749227226dffa64.tar.bz2
Refactors RenderWidget to extract a PaintAggregator class.
After this change, I plan on changing the PaintAggregator algorithm. Some things to note: 1- Previously, it was possible to send overlapping ViewHostMsg_PaintRect and ViewHostMsg_ScrollRect messages. This happened when scrolling a page since the scrollbar would need to be repainted while the contents of the page are being scrolled. With this CL, this overlapping behavior is a bit more explicit. 2- There was a TODO about view_size clipping that I've eliminated. I was able to eliminate it because I realized that it is correct to clip the rects passed by didInvalidateRect and didScrollRect to the size of the RenderWidget. Apparently WebKit can sometimes invalidate regions outside the view. R=brettw BUG=25905 TEST=none Review URL: http://codereview.chromium.org/403005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32496 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/paint_aggregator.cc')
-rw-r--r--chrome/renderer/paint_aggregator.cc105
1 files changed, 105 insertions, 0 deletions
diff --git a/chrome/renderer/paint_aggregator.cc b/chrome/renderer/paint_aggregator.cc
new file mode 100644
index 0000000..ca4841b
--- /dev/null
+++ b/chrome/renderer/paint_aggregator.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/paint_aggregator.h"
+
+#include "base/logging.h"
+
+// We implement a very simple algorithm:
+//
+// - Multiple repaints are unioned to form the smallest bounding box.
+// - If a scroll intersects a repaint, then the scroll is downgraded
+// to a repaint and then unioned with the existing repaint.
+//
+// This allows for a scroll to exist in parallel to a repaint provided the two
+// do not intersect.
+
+gfx::Rect PaintAggregator::PendingUpdate::GetScrollDamage() const {
+ // Should only be scrolling in one direction at a time.
+ DCHECK(!(scroll_delta.x() && scroll_delta.y()));
+
+ 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);
+ }
+ } 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
+ return scroll_rect.Intersect(damaged_rect);
+}
+
+bool PaintAggregator::HasPendingUpdate() const {
+ return !update_.scroll_rect.IsEmpty() || !update_.paint_rect.IsEmpty();
+}
+
+void PaintAggregator::ClearPendingUpdate() {
+ update_ = PendingUpdate();
+}
+
+void PaintAggregator::InvalidateRect(const gfx::Rect& rect) {
+ // If this invalidate overlaps with a pending scroll, then we have to
+ // downgrade to invalidating the scroll rect.
+ if (rect.Intersects(update_.scroll_rect)) {
+ update_.paint_rect = update_.paint_rect.Union(update_.scroll_rect);
+ update_.scroll_rect = gfx::Rect();
+ update_.scroll_delta = gfx::Point();
+ }
+
+ update_.paint_rect = update_.paint_rect.Union(rect);
+}
+
+void PaintAggregator::ScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
+ if (dx != 0 && dy != 0) {
+ // We only support scrolling along one axis at a time.
+ ScrollRect(0, dy, clip_rect);
+ dy = 0;
+ }
+
+ bool intersects_with_painting = update_.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 (!update_.scroll_rect.IsEmpty() || intersects_with_painting) {
+ if (!intersects_with_painting && update_.scroll_rect == clip_rect) {
+ // OK, we can just update the scroll delta (requires same scrolling axis)
+ if (!dx && !update_.scroll_delta.x()) {
+ update_.scroll_delta.set_y(update_.scroll_delta.y() + dy);
+ return;
+ }
+ if (!dy && !update_.scroll_delta.y()) {
+ update_.scroll_delta.set_x(update_.scroll_delta.x() + dx);
+ return;
+ }
+ }
+ InvalidateRect(update_.scroll_rect);
+ DCHECK(update_.scroll_rect.IsEmpty());
+ InvalidateRect(clip_rect);
+ return;
+ }
+
+ update_.scroll_rect = clip_rect;
+ update_.scroll_delta = gfx::Point(dx, dy);
+}