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 blink;
37
38 namespace {
39
TEST(PaintAggregator,InitialState)40 TEST(PaintAggregator, InitialState)
41 {
42 PaintAggregator greg;
43 EXPECT_FALSE(greg.hasPendingUpdate());
44 }
45
TEST(PaintAggregator,SingleInvalidation)46 TEST(PaintAggregator, SingleInvalidation)
47 {
48 PaintAggregator greg;
49
50 IntRect rect(2, 4, 10, 16);
51 greg.invalidateRect(rect);
52
53 EXPECT_TRUE(greg.hasPendingUpdate());
54 PaintAggregator::PendingUpdate update;
55 greg.popPendingUpdate(&update);
56
57 EXPECT_TRUE(update.scrollRect.isEmpty());
58 ASSERT_EQ(1U, update.paintRects.size());
59
60 EXPECT_EQ(rect, update.paintRects[0]);
61 }
62
TEST(PaintAggregator,DoubleDisjointInvalidation)63 TEST(PaintAggregator, DoubleDisjointInvalidation)
64 {
65 PaintAggregator greg;
66
67 IntRect r1(2, 4, 2, 40);
68 IntRect r2(4, 2, 40, 2);
69
70 greg.invalidateRect(r1);
71 greg.invalidateRect(r2);
72
73 IntRect expectedBounds = unionRect(r1, r2);
74
75 EXPECT_TRUE(greg.hasPendingUpdate());
76 PaintAggregator::PendingUpdate update;
77 greg.popPendingUpdate(&update);
78
79 EXPECT_TRUE(update.scrollRect.isEmpty());
80 EXPECT_EQ(2U, update.paintRects.size());
81
82 EXPECT_EQ(expectedBounds, update.calculatePaintBounds());
83 }
84
TEST(PaintAggregator,DisjointInvalidationsCombined)85 TEST(PaintAggregator, DisjointInvalidationsCombined)
86 {
87 PaintAggregator greg;
88
89 // Make the rectangles such that they don't overlap but cover a very large
90 // percentage of the area of covered by their union. This is so we're not
91 // very sensitive to the combining heuristic in the paint aggregator.
92 IntRect r1(2, 4, 2, 1000);
93 IntRect r2(5, 2, 2, 1000);
94
95 greg.invalidateRect(r1);
96 greg.invalidateRect(r2);
97
98 IntRect expectedBounds = unionRect(r1, r2);
99
100 EXPECT_TRUE(greg.hasPendingUpdate());
101 PaintAggregator::PendingUpdate update;
102 greg.popPendingUpdate(&update);
103
104 EXPECT_TRUE(update.scrollRect.isEmpty());
105 ASSERT_EQ(1U, update.paintRects.size());
106
107 EXPECT_EQ(expectedBounds, update.paintRects[0]);
108 }
109
TEST(PaintAggregator,SingleScroll)110 TEST(PaintAggregator, SingleScroll)
111 {
112 PaintAggregator greg;
113
114 IntRect rect(1, 2, 3, 4);
115 IntPoint delta(1, 0);
116 greg.scrollRect(delta.x(), delta.y(), rect);
117
118 EXPECT_TRUE(greg.hasPendingUpdate());
119 PaintAggregator::PendingUpdate update;
120 greg.popPendingUpdate(&update);
121
122 EXPECT_TRUE(update.paintRects.isEmpty());
123 EXPECT_FALSE(update.scrollRect.isEmpty());
124
125 EXPECT_EQ(rect, update.scrollRect);
126
127 EXPECT_EQ(delta.x(), update.scrollDelta.x());
128 EXPECT_EQ(delta.y(), update.scrollDelta.y());
129
130 IntRect resultingDamage = update.calculateScrollDamage();
131 IntRect expectedDamage(1, 2, 1, 4);
132 EXPECT_EQ(expectedDamage, resultingDamage);
133 }
134
TEST(PaintAggregator,DoubleOverlappingScroll)135 TEST(PaintAggregator, DoubleOverlappingScroll)
136 {
137 PaintAggregator greg;
138
139 IntRect rect(1, 2, 3, 4);
140 IntPoint delta1(1, 0);
141 IntPoint delta2(1, 0);
142 greg.scrollRect(delta1.x(), delta1.y(), rect);
143 greg.scrollRect(delta2.x(), delta2.y(), rect);
144
145 EXPECT_TRUE(greg.hasPendingUpdate());
146 PaintAggregator::PendingUpdate update;
147 greg.popPendingUpdate(&update);
148
149 EXPECT_TRUE(update.paintRects.isEmpty());
150 EXPECT_FALSE(update.scrollRect.isEmpty());
151
152 EXPECT_EQ(rect, update.scrollRect);
153
154 IntPoint expectedDelta(delta1.x() + delta2.x(),
155 delta1.y() + delta2.y());
156 EXPECT_EQ(expectedDelta.x(), update.scrollDelta.x());
157 EXPECT_EQ(expectedDelta.y(), update.scrollDelta.y());
158
159 IntRect resultingDamage = update.calculateScrollDamage();
160 IntRect expectedDamage(1, 2, 2, 4);
161 EXPECT_EQ(expectedDamage, resultingDamage);
162 }
163
TEST(PaintAggregator,NegatingScroll)164 TEST(PaintAggregator, NegatingScroll)
165 {
166 PaintAggregator greg;
167
168 // Scroll twice in opposite directions by equal amounts. The result
169 // should be no scrolling.
170
171 IntRect rect(1, 2, 3, 4);
172 IntPoint delta1(1, 0);
173 IntPoint delta2(-1, 0);
174 greg.scrollRect(delta1.x(), delta1.y(), rect);
175 greg.scrollRect(delta2.x(), delta2.y(), rect);
176
177 EXPECT_FALSE(greg.hasPendingUpdate());
178 }
179
TEST(PaintAggregator,DiagonalScroll)180 TEST(PaintAggregator, DiagonalScroll)
181 {
182 PaintAggregator greg;
183
184 // We don't support optimized diagonal scrolling, so this should result in
185 // repainting.
186
187 IntRect rect(1, 2, 3, 4);
188 IntPoint delta(1, 1);
189 greg.scrollRect(delta.x(), delta.y(), rect);
190
191 EXPECT_TRUE(greg.hasPendingUpdate());
192 PaintAggregator::PendingUpdate update;
193 greg.popPendingUpdate(&update);
194
195 EXPECT_TRUE(update.scrollRect.isEmpty());
196 ASSERT_EQ(1U, update.paintRects.size());
197
198 EXPECT_EQ(rect, update.paintRects[0]);
199 }
200
TEST(PaintAggregator,ContainedPaintAfterScroll)201 TEST(PaintAggregator, ContainedPaintAfterScroll)
202 {
203 PaintAggregator greg;
204
205 IntRect scrollRect(0, 0, 10, 10);
206 greg.scrollRect(2, 0, scrollRect);
207
208 IntRect paintRect(4, 4, 2, 2);
209 greg.invalidateRect(paintRect);
210
211 EXPECT_TRUE(greg.hasPendingUpdate());
212 PaintAggregator::PendingUpdate update;
213 greg.popPendingUpdate(&update);
214
215 // expecting a paint rect inside the scroll rect
216 EXPECT_FALSE(update.scrollRect.isEmpty());
217 EXPECT_EQ(1U, update.paintRects.size());
218
219 EXPECT_EQ(scrollRect, update.scrollRect);
220 EXPECT_EQ(paintRect, update.paintRects[0]);
221 }
222
TEST(PaintAggregator,ContainedPaintBeforeScroll)223 TEST(PaintAggregator, ContainedPaintBeforeScroll)
224 {
225 PaintAggregator greg;
226
227 IntRect paintRect(4, 4, 2, 2);
228 greg.invalidateRect(paintRect);
229
230 IntRect scrollRect(0, 0, 10, 10);
231 greg.scrollRect(2, 0, scrollRect);
232
233 EXPECT_TRUE(greg.hasPendingUpdate());
234 PaintAggregator::PendingUpdate update;
235 greg.popPendingUpdate(&update);
236
237 // Expecting a paint rect inside the scroll rect
238 EXPECT_FALSE(update.scrollRect.isEmpty());
239 EXPECT_EQ(1U, update.paintRects.size());
240
241 paintRect.move(2, 0);
242
243 EXPECT_EQ(scrollRect, update.scrollRect);
244 EXPECT_EQ(paintRect, update.paintRects[0]);
245 }
246
TEST(PaintAggregator,ContainedPaintsBeforeAndAfterScroll)247 TEST(PaintAggregator, ContainedPaintsBeforeAndAfterScroll)
248 {
249 PaintAggregator greg;
250
251 IntRect paintRect1(4, 4, 2, 2);
252 greg.invalidateRect(paintRect1);
253
254 IntRect scrollRect(0, 0, 10, 10);
255 greg.scrollRect(2, 0, scrollRect);
256
257 IntRect paintRect2(6, 4, 2, 2);
258 greg.invalidateRect(paintRect2);
259
260 IntRect expectedPaintRect = paintRect2;
261
262 EXPECT_TRUE(greg.hasPendingUpdate());
263 PaintAggregator::PendingUpdate update;
264 greg.popPendingUpdate(&update);
265
266 // Expecting a paint rect inside the scroll rect
267 EXPECT_FALSE(update.scrollRect.isEmpty());
268 EXPECT_EQ(1U, update.paintRects.size());
269
270 EXPECT_EQ(scrollRect, update.scrollRect);
271 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
272 }
273
TEST(PaintAggregator,LargeContainedPaintAfterScroll)274 TEST(PaintAggregator, LargeContainedPaintAfterScroll)
275 {
276 PaintAggregator greg;
277
278 IntRect scrollRect(0, 0, 10, 10);
279 greg.scrollRect(0, 1, scrollRect);
280
281 IntRect paintRect(0, 0, 10, 9); // Repaint 90%
282 greg.invalidateRect(paintRect);
283
284 EXPECT_TRUE(greg.hasPendingUpdate());
285 PaintAggregator::PendingUpdate update;
286 greg.popPendingUpdate(&update);
287
288 EXPECT_TRUE(update.scrollRect.isEmpty());
289 EXPECT_EQ(1U, update.paintRects.size());
290
291 EXPECT_EQ(scrollRect, update.paintRects[0]);
292 }
293
TEST(PaintAggregator,LargeContainedPaintBeforeScroll)294 TEST(PaintAggregator, LargeContainedPaintBeforeScroll)
295 {
296 PaintAggregator greg;
297
298 IntRect paintRect(0, 0, 10, 9); // Repaint 90%
299 greg.invalidateRect(paintRect);
300
301 IntRect scrollRect(0, 0, 10, 10);
302 greg.scrollRect(0, 1, scrollRect);
303
304 EXPECT_TRUE(greg.hasPendingUpdate());
305 PaintAggregator::PendingUpdate update;
306 greg.popPendingUpdate(&update);
307
308 EXPECT_TRUE(update.scrollRect.isEmpty());
309 EXPECT_EQ(1U, update.paintRects.size());
310
311 EXPECT_EQ(scrollRect, update.paintRects[0]);
312 }
313
TEST(PaintAggregator,OverlappingPaintBeforeScroll)314 TEST(PaintAggregator, OverlappingPaintBeforeScroll)
315 {
316 PaintAggregator greg;
317
318 IntRect paintRect(4, 4, 10, 2);
319 greg.invalidateRect(paintRect);
320
321 IntRect scrollRect(0, 0, 10, 10);
322 greg.scrollRect(2, 0, scrollRect);
323
324 IntRect expectedPaintRect = unionRect(scrollRect, paintRect);
325
326 EXPECT_TRUE(greg.hasPendingUpdate());
327 PaintAggregator::PendingUpdate update;
328 greg.popPendingUpdate(&update);
329
330 EXPECT_TRUE(update.scrollRect.isEmpty());
331 EXPECT_EQ(1U, update.paintRects.size());
332
333 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
334 }
335
TEST(PaintAggregator,OverlappingPaintAfterScroll)336 TEST(PaintAggregator, OverlappingPaintAfterScroll)
337 {
338 PaintAggregator greg;
339
340 IntRect scrollRect(0, 0, 10, 10);
341 greg.scrollRect(2, 0, scrollRect);
342
343 IntRect paintRect(4, 4, 10, 2);
344 greg.invalidateRect(paintRect);
345
346 IntRect expectedPaintRect = unionRect(scrollRect, paintRect);
347
348 EXPECT_TRUE(greg.hasPendingUpdate());
349 PaintAggregator::PendingUpdate update;
350 greg.popPendingUpdate(&update);
351
352 EXPECT_TRUE(update.scrollRect.isEmpty());
353 EXPECT_EQ(1U, update.paintRects.size());
354
355 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
356 }
357
TEST(PaintAggregator,DisjointPaintBeforeScroll)358 TEST(PaintAggregator, DisjointPaintBeforeScroll)
359 {
360 PaintAggregator greg;
361
362 IntRect paintRect(4, 4, 10, 2);
363 greg.invalidateRect(paintRect);
364
365 IntRect scrollRect(0, 0, 2, 10);
366 greg.scrollRect(2, 0, scrollRect);
367
368 EXPECT_TRUE(greg.hasPendingUpdate());
369 PaintAggregator::PendingUpdate update;
370 greg.popPendingUpdate(&update);
371
372 EXPECT_FALSE(update.scrollRect.isEmpty());
373 EXPECT_EQ(1U, update.paintRects.size());
374
375 EXPECT_EQ(paintRect, update.paintRects[0]);
376 EXPECT_EQ(scrollRect, update.scrollRect);
377 }
378
TEST(PaintAggregator,DisjointPaintAfterScroll)379 TEST(PaintAggregator, DisjointPaintAfterScroll)
380 {
381 PaintAggregator greg;
382
383 IntRect scrollRect(0, 0, 2, 10);
384 greg.scrollRect(2, 0, scrollRect);
385
386 IntRect paintRect(4, 4, 10, 2);
387 greg.invalidateRect(paintRect);
388
389 EXPECT_TRUE(greg.hasPendingUpdate());
390 PaintAggregator::PendingUpdate update;
391 greg.popPendingUpdate(&update);
392
393 EXPECT_FALSE(update.scrollRect.isEmpty());
394 EXPECT_EQ(1U, update.paintRects.size());
395
396 EXPECT_EQ(paintRect, update.paintRects[0]);
397 EXPECT_EQ(scrollRect, update.scrollRect);
398 }
399
TEST(PaintAggregator,ContainedPaintTrimmedByScroll)400 TEST(PaintAggregator, ContainedPaintTrimmedByScroll)
401 {
402 PaintAggregator greg;
403
404 IntRect paintRect(4, 4, 6, 6);
405 greg.invalidateRect(paintRect);
406
407 IntRect scrollRect(0, 0, 10, 10);
408 greg.scrollRect(2, 0, scrollRect);
409
410 // The paint rect should have become narrower.
411 IntRect expectedPaintRect(6, 4, 4, 6);
412
413 EXPECT_TRUE(greg.hasPendingUpdate());
414 PaintAggregator::PendingUpdate update;
415 greg.popPendingUpdate(&update);
416
417 EXPECT_FALSE(update.scrollRect.isEmpty());
418 EXPECT_EQ(1U, update.paintRects.size());
419
420 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
421 EXPECT_EQ(scrollRect, update.scrollRect);
422 }
423
TEST(PaintAggregator,ContainedPaintEliminatedByScroll)424 TEST(PaintAggregator, ContainedPaintEliminatedByScroll)
425 {
426 PaintAggregator greg;
427
428 IntRect paintRect(4, 4, 6, 6);
429 greg.invalidateRect(paintRect);
430
431 IntRect scrollRect(0, 0, 10, 10);
432 greg.scrollRect(6, 0, scrollRect);
433
434 EXPECT_TRUE(greg.hasPendingUpdate());
435 PaintAggregator::PendingUpdate update;
436 greg.popPendingUpdate(&update);
437
438 EXPECT_FALSE(update.scrollRect.isEmpty());
439 EXPECT_TRUE(update.paintRects.isEmpty());
440
441 EXPECT_EQ(scrollRect, update.scrollRect);
442 }
443
TEST(PaintAggregator,ContainedPaintAfterScrollTrimmedByScrollDamage)444 TEST(PaintAggregator, ContainedPaintAfterScrollTrimmedByScrollDamage)
445 {
446 PaintAggregator greg;
447
448 IntRect scrollRect(0, 0, 10, 10);
449 greg.scrollRect(4, 0, scrollRect);
450
451 IntRect paintRect(2, 0, 4, 10);
452 greg.invalidateRect(paintRect);
453
454 IntRect expectedScrollDamage(0, 0, 4, 10);
455 IntRect expectedPaintRect(4, 0, 2, 10);
456
457 EXPECT_TRUE(greg.hasPendingUpdate());
458 PaintAggregator::PendingUpdate update;
459 greg.popPendingUpdate(&update);
460
461 EXPECT_FALSE(update.scrollRect.isEmpty());
462 EXPECT_EQ(1U, update.paintRects.size());
463
464 EXPECT_EQ(scrollRect, update.scrollRect);
465 EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage());
466 EXPECT_EQ(expectedPaintRect, update.paintRects[0]);
467 }
468
TEST(PaintAggregator,ContainedPaintAfterScrollEliminatedByScrollDamage)469 TEST(PaintAggregator, ContainedPaintAfterScrollEliminatedByScrollDamage)
470 {
471 PaintAggregator greg;
472
473 IntRect scrollRect(0, 0, 10, 10);
474 greg.scrollRect(4, 0, scrollRect);
475
476 IntRect paintRect(2, 0, 2, 10);
477 greg.invalidateRect(paintRect);
478
479 IntRect expectedScrollDamage(0, 0, 4, 10);
480
481 EXPECT_TRUE(greg.hasPendingUpdate());
482 PaintAggregator::PendingUpdate update;
483 greg.popPendingUpdate(&update);
484
485 EXPECT_FALSE(update.scrollRect.isEmpty());
486 EXPECT_TRUE(update.paintRects.isEmpty());
487
488 EXPECT_EQ(scrollRect, update.scrollRect);
489 EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage());
490 }
491
492 } // namespace
493