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 "painting/PaintAggregator.h" 33 34#include <gtest/gtest.h> 35 36using namespace WebCore; 37using namespace WebKit; 38 39namespace { 40 41TEST(PaintAggregator, InitialState) 42{ 43 PaintAggregator greg; 44 EXPECT_FALSE(greg.hasPendingUpdate()); 45} 46 47TEST(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 64TEST(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 86TEST(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 111TEST(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 136TEST(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 165TEST(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 181TEST(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 202TEST(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 224TEST(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 248TEST(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 275TEST(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 295TEST(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 315TEST(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 337TEST(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 359TEST(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 380TEST(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 401TEST(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 425TEST(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 445TEST(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 470TEST(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