Commit 396ac1a8 authored by jbroman's avatar jbroman Committed by Commit bot

Remove PaintAggregator.

It has no uses (aside from its unit tests), and doesn't seem to have for
several years.

Review URL: https://codereview.chromium.org/1513833002

Cr-Commit-Position: refs/heads/master@{#364480}
parent 22eddc71
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "web/painting/PaintAggregator.h"
#include "public/platform/Platform.h"
using namespace blink;
namespace blink {
// ----------------------------------------------------------------------------
// ALGORITHM NOTES
//
// We attempt to maintain a scroll rect in the presence of invalidations that
// are contained within the scroll rect. If an invalidation crosses a scroll
// rect, then we just treat the scroll rect as an invalidation rect.
//
// For invalidations performed prior to scrolling and contained within the
// scroll rect, we offset the invalidation rects to account for the fact that
// the consumer will perform scrolling before painting.
//
// We only support scrolling along one axis at a time. A diagonal scroll will
// therefore be treated as an invalidation.
// ----------------------------------------------------------------------------
// If the combined area of paint rects contained within the scroll rect grows
// too large, then we might as well just treat the scroll rect as a paint rect.
// This constant sets the max ratio of paint rect area to scroll rect area that
// we will tolerate before dograding the scroll into a repaint.
static const float maxRedundantPaintToScrollArea = 0.8f;
// The maximum number of paint rects. If we exceed this limit, then we'll
// start combining paint rects (see CombinePaintRects). This limiting is
// important since the WebKit code associated with deciding what to paint given
// a paint rect can be significant.
static const size_t maxPaintRects = 5;
// If the combined area of paint rects divided by the area of the union of all
// paint rects exceeds this threshold, then we will combine the paint rects.
static const float maxPaintRectsAreaRatio = 0.7f;
static int calculateArea(const IntRect& rect)
{
return rect.size().width() * rect.size().height();
}
// Subtracts out the intersection of |a| and |b| from |a|, assuming |b| fully
// overlaps with |a| in either the x- or y-direction. If there is no full
// overlap, then |a| is returned.
static IntRect subtractIntersection(const IntRect& a, const IntRect& b)
{
// boundary cases:
if (!a.intersects(b))
return a;
if (b.contains(a))
return IntRect();
int rx = a.x();
int ry = a.y();
int rr = a.maxX();
int rb = a.maxY();
if (b.y() <= a.y() && b.maxY() >= a.maxY()) {
// complete intersection in the y-direction
if (b.x() <= a.x())
rx = b.maxX();
else
rr = b.x();
} else if (b.x() <= a.x() && b.maxX() >= a.maxX()) {
// complete intersection in the x-direction
if (b.y() <= a.y())
ry = b.maxY();
else
rb = b.y();
}
return IntRect(rx, ry, rr - rx, rb - ry);
}
// Returns true if |a| and |b| share an entire edge (i.e., same width or same
// height), and the rectangles do not overlap.
static bool sharesEdge(const IntRect& a, const IntRect& b)
{
return (a.y() == b.y() && a.height() == b.height() && (a.x() == b.maxX() || a.maxX() == b.x()))
|| (a.x() == b.x() && a.width() == b.width() && (a.y() == b.maxY() || a.maxY() == b.y()));
}
PaintAggregator::PendingUpdate::PendingUpdate()
{
}
PaintAggregator::PendingUpdate::~PendingUpdate()
{
}
IntRect PaintAggregator::PendingUpdate::calculateScrollDamage() const
{
// Should only be scrolling in one direction at a time.
ASSERT(!(scrollDelta.x() && scrollDelta.y()));
IntRect damagedRect;
// Compute the region we will expose by scrolling, and paint that into a
// shared memory section.
if (scrollDelta.x()) {
int dx = scrollDelta.x();
damagedRect.setY(scrollRect.y());
damagedRect.setHeight(scrollRect.height());
if (dx > 0) {
damagedRect.setX(scrollRect.x());
damagedRect.setWidth(dx);
} else {
damagedRect.setX(scrollRect.maxX() + dx);
damagedRect.setWidth(-dx);
}
} else {
int dy = scrollDelta.y();
damagedRect.setX(scrollRect.x());
damagedRect.setWidth(scrollRect.width());
if (dy > 0) {
damagedRect.setY(scrollRect.y());
damagedRect.setHeight(dy);
} else {
damagedRect.setY(scrollRect.maxY() + dy);
damagedRect.setHeight(-dy);
}
}
// In case the scroll offset exceeds the width/height of the scroll rect
return intersection(scrollRect, damagedRect);
}
IntRect PaintAggregator::PendingUpdate::calculatePaintBounds() const
{
IntRect bounds;
for (size_t i = 0; i < paintRects.size(); ++i)
bounds.unite(paintRects[i]);
return bounds;
}
bool PaintAggregator::hasPendingUpdate() const
{
return !m_update.scrollRect.isEmpty() || !m_update.paintRects.isEmpty();
}
void PaintAggregator::clearPendingUpdate()
{
m_update = PendingUpdate();
}
void PaintAggregator::popPendingUpdate(PendingUpdate* update)
{
// Combine paint rects if their combined area is not sufficiently less than
// the area of the union of all paint rects. We skip this if there is a
// scroll rect since scrolling benefits from smaller paint rects.
if (m_update.scrollRect.isEmpty() && m_update.paintRects.size() > 1) {
int paintArea = 0;
IntRect unionRect;
for (size_t i = 0; i < m_update.paintRects.size(); ++i) {
paintArea += calculateArea(m_update.paintRects[i]);
unionRect.unite(m_update.paintRects[i]);
}
int unionArea = calculateArea(unionRect);
if (float(paintArea) / float(unionArea) > maxPaintRectsAreaRatio)
combinePaintRects();
}
*update = m_update;
clearPendingUpdate();
}
void PaintAggregator::invalidateRect(const IntRect& rect)
{
// Combine overlapping paints using smallest bounding box.
for (size_t i = 0; i < m_update.paintRects.size(); ++i) {
const IntRect& existingRect = m_update.paintRects[i];
if (existingRect.contains(rect)) // Optimize out redundancy.
return;
if (rect.intersects(existingRect) || sharesEdge(rect, existingRect)) {
// Re-invalidate in case the union intersects other paint rects.
IntRect combinedRect = unionRect(existingRect, rect);
m_update.paintRects.remove(i);
invalidateRect(combinedRect);
return;
}
}
// Add a non-overlapping paint.
m_update.paintRects.append(rect);
// If the new paint overlaps with a scroll, then it forces an invalidation of
// the scroll. If the new paint is contained by a scroll, then trim off the
// scroll damage to avoid redundant painting.
if (!m_update.scrollRect.isEmpty()) {
if (shouldInvalidateScrollRect(rect))
invalidateScrollRect();
else if (m_update.scrollRect.contains(rect)) {
m_update.paintRects[m_update.paintRects.size() - 1] =
subtractIntersection(rect, m_update.calculateScrollDamage());
if (m_update.paintRects[m_update.paintRects.size() - 1].isEmpty())
m_update.paintRects.remove(m_update.paintRects.size() - 1);
}
}
if (m_update.paintRects.size() > maxPaintRects)
combinePaintRects();
// Track how large the paintRects vector grows during an invalidation
// sequence. Note: A subsequent invalidation may end up being combined
// with all existing paints, which means that tracking the size of
// paintRects at the time when popPendingUpdate() is called may mask
// certain performance problems.
Platform::current()->histogramCustomCounts("MPArch.RW_IntermediatePaintRectCount",
m_update.paintRects.size(), 1, 100, 50);
}
void PaintAggregator::scrollRect(int dx, int dy, const IntRect& clipRect)
{
// We only support scrolling along one axis at a time.
if (dx && dy) {
invalidateRect(clipRect);
return;
}
// We can only scroll one rect at a time.
if (!m_update.scrollRect.isEmpty() && m_update.scrollRect != clipRect) {
invalidateRect(clipRect);
return;
}
// Again, we only support scrolling along one axis at a time. Make sure this
// update doesn't scroll on a different axis than any existing one.
if ((dx && m_update.scrollDelta.y()) || (dy && m_update.scrollDelta.x())) {
invalidateRect(clipRect);
return;
}
// The scroll rect is new or isn't changing (though the scroll amount may
// be changing).
m_update.scrollRect = clipRect;
m_update.scrollDelta.move(dx, dy);
// We might have just wiped out a pre-existing scroll.
if (m_update.scrollDelta == IntPoint()) {
m_update.scrollRect = IntRect();
return;
}
// Adjust any contained paint rects and check for any overlapping paints.
for (size_t i = 0; i < m_update.paintRects.size(); ++i) {
if (m_update.scrollRect.contains(m_update.paintRects[i])) {
m_update.paintRects[i] = scrollPaintRect(m_update.paintRects[i], dx, dy);
// The rect may have been scrolled out of view.
if (m_update.paintRects[i].isEmpty()) {
m_update.paintRects.remove(i);
i--;
}
} else if (m_update.scrollRect.intersects(m_update.paintRects[i])) {
invalidateScrollRect();
return;
}
}
// If the new scroll overlaps too much with contained paint rects, then force
// an invalidation of the scroll.
if (shouldInvalidateScrollRect(IntRect()))
invalidateScrollRect();
}
IntRect PaintAggregator::scrollPaintRect(const IntRect& paintRect, int dx, int dy) const
{
IntRect result = paintRect;
result.move(dx, dy);
result = intersection(m_update.scrollRect, result);
// Subtract out the scroll damage rect to avoid redundant painting.
return subtractIntersection(result, m_update.calculateScrollDamage());
}
bool PaintAggregator::shouldInvalidateScrollRect(const IntRect& rect) const
{
if (!rect.isEmpty()) {
if (!m_update.scrollRect.intersects(rect))
return false;
if (!m_update.scrollRect.contains(rect))
return true;
}
// Check if the combined area of all contained paint rects plus this new
// rect comes too close to the area of the scrollRect. If so, then we
// might as well invalidate the scroll rect.
int paintArea = calculateArea(rect);
for (size_t i = 0; i < m_update.paintRects.size(); ++i) {
const IntRect& existingRect = m_update.paintRects[i];
if (m_update.scrollRect.contains(existingRect))
paintArea += calculateArea(existingRect);
}
int scrollArea = calculateArea(m_update.scrollRect);
if (float(paintArea) / float(scrollArea) > maxRedundantPaintToScrollArea)
return true;
return false;
}
void PaintAggregator::invalidateScrollRect()
{
IntRect scrollRect = m_update.scrollRect;
m_update.scrollRect = IntRect();
m_update.scrollDelta = IntPoint();
invalidateRect(scrollRect);
}
void PaintAggregator::combinePaintRects()
{
// Combine paint rects do to at most two rects: one inside the scrollRect
// and one outside the scrollRect. If there is no scrollRect, then just
// use the smallest bounding box for all paint rects.
//
// NOTE: This is a fairly simple algorithm. We could get fancier by only
// combining two rects to get us under the maxPaintRects limit, but if we
// reach this method then it means we're hitting a rare case, so there's no
// need to over-optimize it.
//
if (m_update.scrollRect.isEmpty()) {
IntRect bounds = m_update.calculatePaintBounds();
m_update.paintRects.clear();
m_update.paintRects.append(bounds);
} else {
IntRect inner, outer;
for (size_t i = 0; i < m_update.paintRects.size(); ++i) {
const IntRect& existingRect = m_update.paintRects[i];
if (m_update.scrollRect.contains(existingRect))
inner.unite(existingRect);
else
outer.unite(existingRect);
}
m_update.paintRects.clear();
m_update.paintRects.append(inner);
m_update.paintRects.append(outer);
}
}
} // namespace blink
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PaintAggregator_h
#define PaintAggregator_h
#include "platform/geometry/IntPoint.h"
#include "platform/geometry/IntRect.h"
#include "wtf/Vector.h"
namespace blink {
// This class is responsible for aggregating multiple invalidation and scroll
// commands to produce a scroll and repaint sequence.
class PaintAggregator {
public:
// This structure describes an aggregation of invalidateRect and scrollRect
// calls. If |scrollRect| is non-empty, then that rect should be scrolled
// by the amount specified by |scrollDelta|. If |paintRects| is non-empty,
// then those rects should be repainted. If |scrollRect| and |paintRects|
// are non-empty, then scrolling should be performed before repainting.
// |scrollDelta| can only specify scrolling in one direction (i.e., the x
// and y members cannot both be non-zero).
struct PendingUpdate {
PendingUpdate();
~PendingUpdate();
// Returns the rect damaged by scrolling within |scrollRect| by
// |scrollDelta|. This rect must be repainted.
IntRect calculateScrollDamage() const;
// Returns the smallest rect containing all paint rects.
IntRect calculatePaintBounds() const;
IntPoint scrollDelta;
IntRect scrollRect;
WTF::Vector<IntRect> paintRects;
};
// There is a PendingUpdate if invalidateRect or scrollRect were called and
// ClearPendingUpdate was not called.
bool hasPendingUpdate() const;
void clearPendingUpdate();
// Fills |update| and clears the pending update.
void popPendingUpdate(PendingUpdate*);
// The given rect should be repainted.
void invalidateRect(const IntRect&);
// The given rect should be scrolled by the given amounts.
void scrollRect(int dx, int dy, const IntRect& clipRect);
private:
IntRect scrollPaintRect(const IntRect& paintRect, int dx, int dy) const;
bool shouldInvalidateScrollRect(const IntRect&) const;
void invalidateScrollRect();
void combinePaintRects();
PendingUpdate m_update;
};
} // namespace blink
#endif
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "web/painting/PaintAggregator.h"
#include "testing/gtest/include/gtest/gtest.h"
using namespace blink;
namespace {
TEST(PaintAggregator, InitialState)
{
PaintAggregator greg;
EXPECT_FALSE(greg.hasPendingUpdate());
}
TEST(PaintAggregator, SingleInvalidation)
{
PaintAggregator greg;
IntRect rect(2, 4, 10, 16);
greg.invalidateRect(rect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
ASSERT_EQ(1U, update.paintRects.size());
EXPECT_EQ(rect, update.paintRects[0]);
}
TEST(PaintAggregator, DoubleDisjointInvalidation)
{
PaintAggregator greg;
IntRect r1(2, 4, 2, 40);
IntRect r2(4, 2, 40, 2);
greg.invalidateRect(r1);
greg.invalidateRect(r2);
IntRect expectedBounds = unionRect(r1, r2);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
EXPECT_EQ(2U, update.paintRects.size());
EXPECT_EQ(expectedBounds, update.calculatePaintBounds());
}
TEST(PaintAggregator, DisjointInvalidationsCombined)
{
PaintAggregator greg;
// Make the rectangles such that they don't overlap but cover a very large
// percentage of the area of covered by their union. This is so we're not
// very sensitive to the combining heuristic in the paint aggregator.
IntRect r1(2, 4, 2, 1000);
IntRect r2(5, 2, 2, 1000);
greg.invalidateRect(r1);
greg.invalidateRect(r2);
IntRect expectedBounds = unionRect(r1, r2);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
ASSERT_EQ(1U, update.paintRects.size());
EXPECT_EQ(expectedBounds, update.paintRects[0]);
}
TEST(PaintAggregator, SingleScroll)
{
PaintAggregator greg;
IntRect rect(1, 2, 3, 4);
IntPoint delta(1, 0);
greg.scrollRect(delta.x(), delta.y(), rect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.paintRects.isEmpty());
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(rect, update.scrollRect);
EXPECT_EQ(delta.x(), update.scrollDelta.x());
EXPECT_EQ(delta.y(), update.scrollDelta.y());
IntRect resultingDamage = update.calculateScrollDamage();
IntRect expectedDamage(1, 2, 1, 4);
EXPECT_EQ(expectedDamage, resultingDamage);
}
TEST(PaintAggregator, DoubleOverlappingScroll)
{
PaintAggregator greg;
IntRect rect(1, 2, 3, 4);
IntPoint delta1(1, 0);
IntPoint delta2(1, 0);
greg.scrollRect(delta1.x(), delta1.y(), rect);
greg.scrollRect(delta2.x(), delta2.y(), rect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.paintRects.isEmpty());
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(rect, update.scrollRect);
IntPoint expectedDelta(delta1.x() + delta2.x(),
delta1.y() + delta2.y());
EXPECT_EQ(expectedDelta.x(), update.scrollDelta.x());
EXPECT_EQ(expectedDelta.y(), update.scrollDelta.y());
IntRect resultingDamage = update.calculateScrollDamage();
IntRect expectedDamage(1, 2, 2, 4);
EXPECT_EQ(expectedDamage, resultingDamage);
}
TEST(PaintAggregator, NegatingScroll)
{
PaintAggregator greg;
// Scroll twice in opposite directions by equal amounts. The result
// should be no scrolling.
IntRect rect(1, 2, 3, 4);
IntPoint delta1(1, 0);
IntPoint delta2(-1, 0);
greg.scrollRect(delta1.x(), delta1.y(), rect);
greg.scrollRect(delta2.x(), delta2.y(), rect);
EXPECT_FALSE(greg.hasPendingUpdate());
}
TEST(PaintAggregator, DiagonalScroll)
{
PaintAggregator greg;
// We don't support optimized diagonal scrolling, so this should result in
// repainting.
IntRect rect(1, 2, 3, 4);
IntPoint delta(1, 1);
greg.scrollRect(delta.x(), delta.y(), rect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
ASSERT_EQ(1U, update.paintRects.size());
EXPECT_EQ(rect, update.paintRects[0]);
}
TEST(PaintAggregator, ContainedPaintAfterScroll)
{
PaintAggregator greg;
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(2, 0, scrollRect);
IntRect paintRect(4, 4, 2, 2);
greg.invalidateRect(paintRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
// expecting a paint rect inside the scroll rect
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(scrollRect, update.scrollRect);
EXPECT_EQ(paintRect, update.paintRects[0]);
}
TEST(PaintAggregator, ContainedPaintBeforeScroll)
{
PaintAggregator greg;
IntRect paintRect(4, 4, 2, 2);
greg.invalidateRect(paintRect);
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(2, 0, scrollRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
// Expecting a paint rect inside the scroll rect
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
paintRect.move(2, 0);
EXPECT_EQ(scrollRect, update.scrollRect);
EXPECT_EQ(paintRect, update.paintRects[0]);
}
TEST(PaintAggregator, ContainedPaintsBeforeAndAfterScroll)
{
PaintAggregator greg;
IntRect paintRect1(4, 4, 2, 2);
greg.invalidateRect(paintRect1);
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(2, 0, scrollRect);
IntRect paintRect2(6, 4, 2, 2);
greg.invalidateRect(paintRect2);
IntRect expectedPaintRect = paintRect2;
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
// Expecting a paint rect inside the scroll rect
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(scrollRect, update.scrollRect);
EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
}
TEST(PaintAggregator, LargeContainedPaintAfterScroll)
{
PaintAggregator greg;
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(0, 1, scrollRect);
IntRect paintRect(0, 0, 10, 9); // Repaint 90%
greg.invalidateRect(paintRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(scrollRect, update.paintRects[0]);
}
TEST(PaintAggregator, LargeContainedPaintBeforeScroll)
{
PaintAggregator greg;
IntRect paintRect(0, 0, 10, 9); // Repaint 90%
greg.invalidateRect(paintRect);
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(0, 1, scrollRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(scrollRect, update.paintRects[0]);
}
TEST(PaintAggregator, OverlappingPaintBeforeScroll)
{
PaintAggregator greg;
IntRect paintRect(4, 4, 10, 2);
greg.invalidateRect(paintRect);
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(2, 0, scrollRect);
IntRect expectedPaintRect = unionRect(scrollRect, paintRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
}
TEST(PaintAggregator, OverlappingPaintAfterScroll)
{
PaintAggregator greg;
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(2, 0, scrollRect);
IntRect paintRect(4, 4, 10, 2);
greg.invalidateRect(paintRect);
IntRect expectedPaintRect = unionRect(scrollRect, paintRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_TRUE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
}
TEST(PaintAggregator, DisjointPaintBeforeScroll)
{
PaintAggregator greg;
IntRect paintRect(4, 4, 10, 2);
greg.invalidateRect(paintRect);
IntRect scrollRect(0, 0, 2, 10);
greg.scrollRect(2, 0, scrollRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(paintRect, update.paintRects[0]);
EXPECT_EQ(scrollRect, update.scrollRect);
}
TEST(PaintAggregator, DisjointPaintAfterScroll)
{
PaintAggregator greg;
IntRect scrollRect(0, 0, 2, 10);
greg.scrollRect(2, 0, scrollRect);
IntRect paintRect(4, 4, 10, 2);
greg.invalidateRect(paintRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(paintRect, update.paintRects[0]);
EXPECT_EQ(scrollRect, update.scrollRect);
}
TEST(PaintAggregator, ContainedPaintTrimmedByScroll)
{
PaintAggregator greg;
IntRect paintRect(4, 4, 6, 6);
greg.invalidateRect(paintRect);
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(2, 0, scrollRect);
// The paint rect should have become narrower.
IntRect expectedPaintRect(6, 4, 4, 6);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
EXPECT_EQ(scrollRect, update.scrollRect);
}
TEST(PaintAggregator, ContainedPaintEliminatedByScroll)
{
PaintAggregator greg;
IntRect paintRect(4, 4, 6, 6);
greg.invalidateRect(paintRect);
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(6, 0, scrollRect);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_TRUE(update.paintRects.isEmpty());
EXPECT_EQ(scrollRect, update.scrollRect);
}
TEST(PaintAggregator, ContainedPaintAfterScrollTrimmedByScrollDamage)
{
PaintAggregator greg;
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(4, 0, scrollRect);
IntRect paintRect(2, 0, 4, 10);
greg.invalidateRect(paintRect);
IntRect expectedScrollDamage(0, 0, 4, 10);
IntRect expectedPaintRect(4, 0, 2, 10);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_EQ(1U, update.paintRects.size());
EXPECT_EQ(scrollRect, update.scrollRect);
EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage());
EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
}
TEST(PaintAggregator, ContainedPaintAfterScrollEliminatedByScrollDamage)
{
PaintAggregator greg;
IntRect scrollRect(0, 0, 10, 10);
greg.scrollRect(4, 0, scrollRect);
IntRect paintRect(2, 0, 2, 10);
greg.invalidateRect(paintRect);
IntRect expectedScrollDamage(0, 0, 4, 10);
EXPECT_TRUE(greg.hasPendingUpdate());
PaintAggregator::PendingUpdate update;
greg.popPendingUpdate(&update);
EXPECT_FALSE(update.scrollRect.isEmpty());
EXPECT_TRUE(update.paintRects.isEmpty());
EXPECT_EQ(scrollRect, update.scrollRect);
EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage());
}
} // namespace
...@@ -241,8 +241,6 @@ ...@@ -241,8 +241,6 @@
'linux/WebFontRendering.cpp', 'linux/WebFontRendering.cpp',
'mac/WebScrollbarTheme.mm', 'mac/WebScrollbarTheme.mm',
'mac/WebSubstringUtil.mm', 'mac/WebSubstringUtil.mm',
'painting/PaintAggregator.cpp',
'painting/PaintAggregator.h',
'win/WebFontRendering.cpp', 'win/WebFontRendering.cpp',
], ],
'web_unittest_files': [ 'web_unittest_files': [
...@@ -274,7 +272,6 @@ ...@@ -274,7 +272,6 @@
'tests/MHTMLTest.cpp', 'tests/MHTMLTest.cpp',
'tests/WebMeaningfulLayoutsTest.cpp', 'tests/WebMeaningfulLayoutsTest.cpp',
'tests/PageSerializerTest.cpp', 'tests/PageSerializerTest.cpp',
'tests/PaintAggregatorTest.cpp',
'tests/PrerenderingTest.cpp', 'tests/PrerenderingTest.cpp',
'tests/ProgrammaticScrollTest.cpp', 'tests/ProgrammaticScrollTest.cpp',
'tests/LayoutGeometryMapTest.cpp', 'tests/LayoutGeometryMapTest.cpp',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment