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 36 using namespace WebCore; 37 using namespace WebKit; 38 39 namespace { 40 41 TEST(PaintAggregator, InitialState) 42 { 43 PaintAggregator greg; 44 EXPECT_FALSE(greg.hasPendingUpdate()); 45 } 46 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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