diff options
author | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-19 05:24:57 +0000 |
---|---|---|
committer | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-19 05:24:57 +0000 |
commit | 552e600db9f51ac1efb0438bd749227226dffa64 (patch) | |
tree | 121e6a11a6f637e9b5cfd2d04244c94b1961420f /chrome/renderer/paint_aggregator.cc | |
parent | 0dea18f231b425216aae0c956129bc80b7086770 (diff) | |
download | chromium_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.cc | 105 |
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); +} |