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 36using namespace blink; 37 38namespace { 39 40TEST(PaintAggregator, InitialState) 41{ 42 PaintAggregator greg; 43 EXPECT_FALSE(greg.hasPendingUpdate()); 44} 45 46TEST(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 63TEST(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 85TEST(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 110TEST(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 135TEST(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 164TEST(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 180TEST(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 201TEST(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 223TEST(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 247TEST(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 274TEST(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 294TEST(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 314TEST(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 336TEST(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 358TEST(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 379TEST(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 400TEST(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 424TEST(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 444TEST(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 469TEST(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