1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "web/painting/PaintAggregator.h"
33
34 #include <gtest/gtest.h>
35
36 using namespace WebCore;
37 using namespace blink;
38
39 namespace {
40
TEST(PaintAggregator,InitialState)41 TEST(PaintAggregator, InitialState)
42 {
43 PaintAggregator greg;
44 EXPECT_FALSE(greg.hasPendingUpdate());
45 }
46
TEST(PaintAggregator,SingleInvalidation)47 TEST(PaintAggregator, SingleInvalidation)
48 {
49 PaintAggregator greg;
50
51 IntRect rect(2, 4, 10, 16);
52 greg.invalidateRect(rect);
53
54 EXPECT_TRUE(greg.hasPendingUpdate());
55 PaintAggregator::PendingUpdate update;
56 greg.popPendingUpdate(&update);
57
58 EXPECT_TRUE(update.scrollRect.isEmpty());
59 ASSERT_EQ(1U, update.paintRects.size());
60
61 EXPECT_EQ(rect, update.paintRects[0]);
62 }
63
TEST(PaintAggregator,DoubleDisjointInvalidation)64 TEST(PaintAggregator, DoubleDisjointInvalidation)
65 {
66 PaintAggregator greg;
67
68 IntRect r1(2, 4, 2, 40);
69 IntRect r2(4, 2, 40, 2);
70
71 greg.invalidateRect(r1);
72 greg.invalidateRect(r2);
73
74 IntRect expectedBounds = unionRect(r1, r2);
75
76 EXPECT_TRUE(greg.hasPendingUpdate());
77 PaintAggregator::PendingUpdate update;
78 greg.popPendingUpdate(&update);
79
80 EXPECT_TRUE(update.scrollRect.isEmpty());
81 EXPECT_EQ(2U, update.paintRects.size());
82
83 EXPECT_EQ(expectedBounds, update.calculatePaintBounds());
84 }
85
TEST(PaintAggregator,DisjointInvalidationsCombined)86 TEST(PaintAggregator, DisjointInvalidationsCombined)
87 {
88 PaintAggregator greg;
89
90 // Make the rectangles such that they don't overlap but cover a very large
91 // percentage of the area of covered by their union. This is so we're not
92 // very sensitive to the combining heuristic in the paint aggregator.
93 IntRect r1(2, 4, 2, 1000);
94 IntRect r2(5, 2, 2, 1000);
95
96 greg.invalidateRect(r1);
97 greg.invalidateRect(r2);
98
99 IntRect expectedBounds = unionRect(r1, r2);
100
101 EXPECT_TRUE(greg.hasPendingUpdate());
102 PaintAggregator::PendingUpdate update;
103 greg.popPendingUpdate(&update);
104
105 EXPECT_TRUE(update.scrollRect.isEmpty());
106 ASSERT_EQ(1U, update.paintRects.size());
107
108 EXPECT_EQ(expectedBounds, update.paintRects[0]);
109 }
110
TEST(PaintAggregator,SingleScroll)111 TEST(PaintAggregator, SingleScroll)
112 {
113 PaintAggregator greg;
114
115 IntRect rect(1, 2, 3, 4);
116 IntPoint delta(1, 0);
117 greg.scrollRect(delta.x(), delta.y(), rect);
118
119 EXPECT_TRUE(greg.hasPendingUpdate());
120 PaintAggregator::PendingUpdate update;
121 greg.popPendingUpdate(&update);
122
123 EXPECT_TRUE(update.paintRects.isEmpty());
124 EXPECT_FALSE(update.scrollRect.isEmpty());
125
126 EXPECT_EQ(rect, update.scrollRect);
127
128 EXPECT_EQ(delta.x(), update.scrollDelta.x());
129 EXPECT_EQ(delta.y(), update.scrollDelta.y());
130
131 IntRect resultingDamage = update.calculateScrollDamage();
132 IntRect expectedDamage(1, 2, 1, 4);
133 EXPECT_EQ(expectedDamage, resultingDamage);
134 }
135
TEST(PaintAggregator,DoubleOverlappingScroll)136 TEST(PaintAggregator, DoubleOverlappingScroll)
137 {
138 PaintAggregator greg;
139
140 IntRect rect(1, 2, 3, 4);
141 IntPoint delta1(1, 0);
142 IntPoint delta2(1, 0);
143 greg.scrollRect(delta1.x(), delta1.y(), rect);
144 greg.scrollRect(delta2.x(), delta2.y(), rect);
145
146 EXPECT_TRUE(greg.hasPendingUpdate());
147 PaintAggregator::PendingUpdate update;
148 greg.popPendingUpdate(&update);
149
150 EXPECT_TRUE(update.paintRects.isEmpty());
151 EXPECT_FALSE(update.scrollRect.isEmpty());
152
153 EXPECT_EQ(rect, update.scrollRect);
154
155 IntPoint expectedDelta(delta1.x() + delta2.x(),
156 delta1.y() + delta2.y());
157 EXPECT_EQ(expectedDelta.x(), update.scrollDelta.x());
158 EXPECT_EQ(expectedDelta.y(), update.scrollDelta.y());
159
160 IntRect resultingDamage = update.calculateScrollDamage();
161 IntRect expectedDamage(1, 2, 2, 4);
162 EXPECT_EQ(expectedDamage, resultingDamage);
163 }
164
TEST(PaintAggregator,NegatingScroll)165 TEST(PaintAggregator, NegatingScroll)
166 {
167 PaintAggregator greg;
168
169 // Scroll twice in opposite directions by equal amounts. The result
170 // should be no scrolling.
171
172 IntRect rect(1, 2, 3, 4);
173 IntPoint delta1(1, 0);
174 IntPoint delta2(-1, 0);
175 greg.scrollRect(delta1.x(), delta1.y(), rect);
176 greg.scrollRect(delta2.x(), delta2.y(), rect);
177
178 EXPECT_FALSE(greg.hasPendingUpdate());
179 }
180
TEST(PaintAggregator,DiagonalScroll)181 TEST(PaintAggregator, DiagonalScroll)
182 {
183 PaintAggregator greg;
184
185 // We don't support optimized diagonal scrolling, so this should result in
186 // repainting.
187
188 IntRect rect(1, 2, 3, 4);
189 IntPoint delta(1, 1);
190 greg.scrollRect(delta.x(), delta.y(), rect);
191
192 EXPECT_TRUE(greg.hasPendingUpdate());
193 PaintAggregator::PendingUpdate update;
194 greg.popPendingUpdate(&update);
195
196 EXPECT_TRUE(update.scrollRect.isEmpty());
197 ASSERT_EQ(1U, update.paintRects.size());
198
199 EXPECT_EQ(rect, update.paintRects[0]);
200 }
201
TEST(PaintAggregator,ContainedPaintAfterScroll)202 TEST(PaintAggregator, ContainedPaintAfterScroll)
203 {
204 PaintAggregator greg;
205
206 IntRect scrollRect(0, 0, 10, 10);
207 greg.scrollRect(2, 0, scrollRect);
208
209 IntRect paintRect(4, 4, 2, 2);
210 greg.invalidateRect(paintRect);
211
212 EXPECT_TRUE(greg.hasPendingUpdate());
213 PaintAggregator::PendingUpdate update;
214 greg.popPendingUpdate(&update);
215
216 // expecting a paint rect inside the scroll rect
217 EXPECT_FALSE(update.scrollRect.isEmpty());
218 EXPECT_EQ(1U, update.paintRects.size());
219
220 EXPECT_EQ(scrollRect, update.scrollRect);
221 EXPECT_EQ(paintRect, update.paintRects[0]);
222 }
223
TEST(PaintAggregator,ContainedPaintBeforeScroll)224 TEST(PaintAggregator, ContainedPaintBeforeScroll)
225 {
226 PaintAggregator greg;
227
228 IntRect paintRect(4, 4, 2, 2);
229 greg.invalidateRect(paintRect);
230
231 IntRect scrollRect(0, 0, 10, 10);
232 greg.scrollRect(2, 0, scrollRect);
233
234 EXPECT_TRUE(greg.hasPendingUpdate());
235 PaintAggregator::PendingUpdate update;
236 greg.popPendingUpdate(&update);
237
238 // Expecting a paint rect inside the scroll rect
239 EXPECT_FALSE(update.scrollRect.isEmpty());
240 EXPECT_EQ(1U, update.paintRects.size());
241
242 paintRect.move(2, 0);
243
244 EXPECT_EQ(scrollRect, update.scrollRect);
245 EXPECT_EQ(paintRect, update.paintRects[0]);
246 }
247
TEST(PaintAggregator,ContainedPaintsBeforeAndAfterScroll)248 TEST(PaintAggregator, ContainedPaintsBeforeAndAfterScroll)
249 {
250 PaintAggregator greg;
251
252 IntRect paintRect1(4, 4, 2, 2);
253 greg.invalidateRect(paintRect1);
254
255 IntRect scrollRect(0, 0, 10, 10);
256 greg.scrollRect(2, 0, scrollRect);
257
258 IntRect paintRect2(6, 4, 2, 2);
259 greg.invalidateRect(paintRect2);
260
261 IntRect expectedPaintRect = paintRect2;
262
263 EXPECT_TRUE(greg.hasPendingUpdate());
264 PaintAggregator::PendingUpdate update;
265 greg.popPendingUpdate(&update);
266
267 // Expecting a paint rect inside the scroll rect
268 EXPECT_FALSE(update.scrollRect.isEmpty());
269 EXPECT_EQ(1U, update.paintRects.size());
270
271 EXPECT_EQ(scrollRect, update.scrollRect);
272 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
273 }
274
TEST(PaintAggregator,LargeContainedPaintAfterScroll)275 TEST(PaintAggregator, LargeContainedPaintAfterScroll)
276 {
277 PaintAggregator greg;
278
279 IntRect scrollRect(0, 0, 10, 10);
280 greg.scrollRect(0, 1, scrollRect);
281
282 IntRect paintRect(0, 0, 10, 9); // Repaint 90%
283 greg.invalidateRect(paintRect);
284
285 EXPECT_TRUE(greg.hasPendingUpdate());
286 PaintAggregator::PendingUpdate update;
287 greg.popPendingUpdate(&update);
288
289 EXPECT_TRUE(update.scrollRect.isEmpty());
290 EXPECT_EQ(1U, update.paintRects.size());
291
292 EXPECT_EQ(scrollRect, update.paintRects[0]);
293 }
294
TEST(PaintAggregator,LargeContainedPaintBeforeScroll)295 TEST(PaintAggregator, LargeContainedPaintBeforeScroll)
296 {
297 PaintAggregator greg;
298
299 IntRect paintRect(0, 0, 10, 9); // Repaint 90%
300 greg.invalidateRect(paintRect);
301
302 IntRect scrollRect(0, 0, 10, 10);
303 greg.scrollRect(0, 1, scrollRect);
304
305 EXPECT_TRUE(greg.hasPendingUpdate());
306 PaintAggregator::PendingUpdate update;
307 greg.popPendingUpdate(&update);
308
309 EXPECT_TRUE(update.scrollRect.isEmpty());
310 EXPECT_EQ(1U, update.paintRects.size());
311
312 EXPECT_EQ(scrollRect, update.paintRects[0]);
313 }
314
TEST(PaintAggregator,OverlappingPaintBeforeScroll)315 TEST(PaintAggregator, OverlappingPaintBeforeScroll)
316 {
317 PaintAggregator greg;
318
319 IntRect paintRect(4, 4, 10, 2);
320 greg.invalidateRect(paintRect);
321
322 IntRect scrollRect(0, 0, 10, 10);
323 greg.scrollRect(2, 0, scrollRect);
324
325 IntRect expectedPaintRect = unionRect(scrollRect, paintRect);
326
327 EXPECT_TRUE(greg.hasPendingUpdate());
328 PaintAggregator::PendingUpdate update;
329 greg.popPendingUpdate(&update);
330
331 EXPECT_TRUE(update.scrollRect.isEmpty());
332 EXPECT_EQ(1U, update.paintRects.size());
333
334 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
335 }
336
TEST(PaintAggregator,OverlappingPaintAfterScroll)337 TEST(PaintAggregator, OverlappingPaintAfterScroll)
338 {
339 PaintAggregator greg;
340
341 IntRect scrollRect(0, 0, 10, 10);
342 greg.scrollRect(2, 0, scrollRect);
343
344 IntRect paintRect(4, 4, 10, 2);
345 greg.invalidateRect(paintRect);
346
347 IntRect expectedPaintRect = unionRect(scrollRect, paintRect);
348
349 EXPECT_TRUE(greg.hasPendingUpdate());
350 PaintAggregator::PendingUpdate update;
351 greg.popPendingUpdate(&update);
352
353 EXPECT_TRUE(update.scrollRect.isEmpty());
354 EXPECT_EQ(1U, update.paintRects.size());
355
356 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
357 }
358
TEST(PaintAggregator,DisjointPaintBeforeScroll)359 TEST(PaintAggregator, DisjointPaintBeforeScroll)
360 {
361 PaintAggregator greg;
362
363 IntRect paintRect(4, 4, 10, 2);
364 greg.invalidateRect(paintRect);
365
366 IntRect scrollRect(0, 0, 2, 10);
367 greg.scrollRect(2, 0, scrollRect);
368
369 EXPECT_TRUE(greg.hasPendingUpdate());
370 PaintAggregator::PendingUpdate update;
371 greg.popPendingUpdate(&update);
372
373 EXPECT_FALSE(update.scrollRect.isEmpty());
374 EXPECT_EQ(1U, update.paintRects.size());
375
376 EXPECT_EQ(paintRect, update.paintRects[0]);
377 EXPECT_EQ(scrollRect, update.scrollRect);
378 }
379
TEST(PaintAggregator,DisjointPaintAfterScroll)380 TEST(PaintAggregator, DisjointPaintAfterScroll)
381 {
382 PaintAggregator greg;
383
384 IntRect scrollRect(0, 0, 2, 10);
385 greg.scrollRect(2, 0, scrollRect);
386
387 IntRect paintRect(4, 4, 10, 2);
388 greg.invalidateRect(paintRect);
389
390 EXPECT_TRUE(greg.hasPendingUpdate());
391 PaintAggregator::PendingUpdate update;
392 greg.popPendingUpdate(&update);
393
394 EXPECT_FALSE(update.scrollRect.isEmpty());
395 EXPECT_EQ(1U, update.paintRects.size());
396
397 EXPECT_EQ(paintRect, update.paintRects[0]);
398 EXPECT_EQ(scrollRect, update.scrollRect);
399 }
400
TEST(PaintAggregator,ContainedPaintTrimmedByScroll)401 TEST(PaintAggregator, ContainedPaintTrimmedByScroll)
402 {
403 PaintAggregator greg;
404
405 IntRect paintRect(4, 4, 6, 6);
406 greg.invalidateRect(paintRect);
407
408 IntRect scrollRect(0, 0, 10, 10);
409 greg.scrollRect(2, 0, scrollRect);
410
411 // The paint rect should have become narrower.
412 IntRect expectedPaintRect(6, 4, 4, 6);
413
414 EXPECT_TRUE(greg.hasPendingUpdate());
415 PaintAggregator::PendingUpdate update;
416 greg.popPendingUpdate(&update);
417
418 EXPECT_FALSE(update.scrollRect.isEmpty());
419 EXPECT_EQ(1U, update.paintRects.size());
420
421 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
422 EXPECT_EQ(scrollRect, update.scrollRect);
423 }
424
TEST(PaintAggregator,ContainedPaintEliminatedByScroll)425 TEST(PaintAggregator, ContainedPaintEliminatedByScroll)
426 {
427 PaintAggregator greg;
428
429 IntRect paintRect(4, 4, 6, 6);
430 greg.invalidateRect(paintRect);
431
432 IntRect scrollRect(0, 0, 10, 10);
433 greg.scrollRect(6, 0, scrollRect);
434
435 EXPECT_TRUE(greg.hasPendingUpdate());
436 PaintAggregator::PendingUpdate update;
437 greg.popPendingUpdate(&update);
438
439 EXPECT_FALSE(update.scrollRect.isEmpty());
440 EXPECT_TRUE(update.paintRects.isEmpty());
441
442 EXPECT_EQ(scrollRect, update.scrollRect);
443 }
444
TEST(PaintAggregator,ContainedPaintAfterScrollTrimmedByScrollDamage)445 TEST(PaintAggregator, ContainedPaintAfterScrollTrimmedByScrollDamage)
446 {
447 PaintAggregator greg;
448
449 IntRect scrollRect(0, 0, 10, 10);
450 greg.scrollRect(4, 0, scrollRect);
451
452 IntRect paintRect(2, 0, 4, 10);
453 greg.invalidateRect(paintRect);
454
455 IntRect expectedScrollDamage(0, 0, 4, 10);
456 IntRect expectedPaintRect(4, 0, 2, 10);
457
458 EXPECT_TRUE(greg.hasPendingUpdate());
459 PaintAggregator::PendingUpdate update;
460 greg.popPendingUpdate(&update);
461
462 EXPECT_FALSE(update.scrollRect.isEmpty());
463 EXPECT_EQ(1U, update.paintRects.size());
464
465 EXPECT_EQ(scrollRect, update.scrollRect);
466 EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage());
467 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
468 }
469
TEST(PaintAggregator,ContainedPaintAfterScrollEliminatedByScrollDamage)470 TEST(PaintAggregator, ContainedPaintAfterScrollEliminatedByScrollDamage)
471 {
472 PaintAggregator greg;
473
474 IntRect scrollRect(0, 0, 10, 10);
475 greg.scrollRect(4, 0, scrollRect);
476
477 IntRect paintRect(2, 0, 2, 10);
478 greg.invalidateRect(paintRect);
479
480 IntRect expectedScrollDamage(0, 0, 4, 10);
481
482 EXPECT_TRUE(greg.hasPendingUpdate());
483 PaintAggregator::PendingUpdate update;
484 greg.popPendingUpdate(&update);
485
486 EXPECT_FALSE(update.scrollRect.isEmpty());
487 EXPECT_TRUE(update.paintRects.isEmpty());
488
489 EXPECT_EQ(scrollRect, update.scrollRect);
490 EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage());
491 }
492
493 } // namespace
494