blob: ca4841b130507ce198a1a5644710dcdc38b6ba33 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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);
}
|