ClipStackTest.cpp revision 72b2e6fff3f54c6aa80a98eab4c73f02a8cd450d
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "Test.h" 9#include "SkClipStack.h" 10#include "SkPath.h" 11#include "SkRect.h" 12 13 14 15static void test_assign_and_comparison(skiatest::Reporter* reporter) { 16 SkClipStack s; 17 bool doAA = false; 18 19 REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); 20 21 // Build up a clip stack with a path, an empty clip, and a rect. 22 s.save(); 23 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 24 25 SkPath p; 26 p.moveTo(5, 6); 27 p.lineTo(7, 8); 28 p.lineTo(5, 9); 29 p.close(); 30 s.clipDevPath(p, SkRegion::kIntersect_Op, doAA); 31 32 s.save(); 33 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 34 35 SkRect r = SkRect::MakeLTRB(1, 2, 3, 4); 36 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA); 37 r = SkRect::MakeLTRB(10, 11, 12, 13); 38 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA); 39 40 s.save(); 41 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 42 43 r = SkRect::MakeLTRB(14, 15, 16, 17); 44 s.clipDevRect(r, SkRegion::kUnion_Op, doAA); 45 46 // Test that assignment works. 47 SkClipStack copy = s; 48 REPORTER_ASSERT(reporter, s == copy); 49 50 // Test that different save levels triggers not equal. 51 s.restore(); 52 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 53 REPORTER_ASSERT(reporter, s != copy); 54 55 // Test that an equal, but not copied version is equal. 56 s.save(); 57 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 58 59 r = SkRect::MakeLTRB(14, 15, 16, 17); 60 s.clipDevRect(r, SkRegion::kUnion_Op, doAA); 61 REPORTER_ASSERT(reporter, s == copy); 62 63 // Test that a different op on one level triggers not equal. 64 s.restore(); 65 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 66 s.save(); 67 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 68 69 r = SkRect::MakeLTRB(14, 15, 16, 17); 70 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA); 71 REPORTER_ASSERT(reporter, s != copy); 72 73 // Test that different state (clip type) triggers not equal. 74 // NO LONGER VALID: if a path contains only a rect, we turn 75 // it into a bare rect for performance reasons (working 76 // around Chromium/JavaScript bad pattern). 77/* 78 s.restore(); 79 s.save(); 80 SkPath rp; 81 rp.addRect(r); 82 s.clipDevPath(rp, SkRegion::kUnion_Op, doAA); 83 REPORTER_ASSERT(reporter, s != copy); 84*/ 85 86 // Test that different rects triggers not equal. 87 s.restore(); 88 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 89 s.save(); 90 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 91 92 r = SkRect::MakeLTRB(24, 25, 26, 27); 93 s.clipDevRect(r, SkRegion::kUnion_Op, doAA); 94 REPORTER_ASSERT(reporter, s != copy); 95 96 // Sanity check 97 s.restore(); 98 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 99 100 copy.restore(); 101 REPORTER_ASSERT(reporter, 2 == copy.getSaveCount()); 102 REPORTER_ASSERT(reporter, s == copy); 103 s.restore(); 104 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 105 copy.restore(); 106 REPORTER_ASSERT(reporter, 1 == copy.getSaveCount()); 107 REPORTER_ASSERT(reporter, s == copy); 108 109 // Test that different paths triggers not equal. 110 s.restore(); 111 REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); 112 s.save(); 113 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 114 115 p.addRect(r); 116 s.clipDevPath(p, SkRegion::kIntersect_Op, doAA); 117 REPORTER_ASSERT(reporter, s != copy); 118} 119 120static void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack, 121 int count) { 122 SkClipStack::B2TIter iter(stack); 123 int counter = 0; 124 while (iter.next()) { 125 counter += 1; 126 } 127 REPORTER_ASSERT(reporter, count == counter); 128} 129 130// Exercise the SkClipStack's bottom to top and bidirectional iterators 131// (including the skipToTopmost functionality) 132static void test_iterators(skiatest::Reporter* reporter) { 133 SkClipStack stack; 134 135 static const SkRect gRects[] = { 136 { 0, 0, 40, 40 }, 137 { 60, 0, 100, 40 }, 138 { 0, 60, 40, 100 }, 139 { 60, 60, 100, 100 } 140 }; 141 142 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) { 143 // the union op will prevent these from being fused together 144 stack.clipDevRect(gRects[i], SkRegion::kUnion_Op, false); 145 } 146 147 assert_count(reporter, stack, 4); 148 149 // bottom to top iteration 150 { 151 const SkClipStack::B2TIter::Clip* clip = NULL; 152 153 SkClipStack::B2TIter iter(stack); 154 int i; 155 156 for (i = 0, clip = iter.next(); clip; ++i, clip = iter.next()) { 157 REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]); 158 } 159 160 SkASSERT(i == 4); 161 } 162 163 // top to bottom iteration 164 { 165 const SkClipStack::Iter::Clip* clip = NULL; 166 167 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); 168 int i; 169 170 for (i = 3, clip = iter.prev(); clip; --i, clip = iter.prev()) { 171 REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]); 172 } 173 174 SkASSERT(i == -1); 175 } 176 177 // skipToTopmost 178 { 179 const SkClipStack::Iter::Clip*clip = NULL; 180 181 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 182 183 clip = iter.skipToTopmost(SkRegion::kUnion_Op); 184 REPORTER_ASSERT(reporter, *clip->fRect == gRects[3]); 185 } 186} 187 188// Exercise the SkClipStack's getConservativeBounds computation 189static void test_bounds(skiatest::Reporter* reporter, bool useRects) { 190 191 static const int gNumCases = 20; 192 static const SkRect gAnswerRectsBW[gNumCases] = { 193 // A op B 194 { 40, 40, 50, 50 }, 195 { 10, 10, 50, 50 }, 196 { 10, 10, 80, 80 }, 197 { 10, 10, 80, 80 }, 198 { 40, 40, 80, 80 }, 199 200 // invA op B 201 { 40, 40, 80, 80 }, 202 { 0, 0, 100, 100 }, 203 { 0, 0, 100, 100 }, 204 { 0, 0, 100, 100 }, 205 { 40, 40, 50, 50 }, 206 207 // A op invB 208 { 10, 10, 50, 50 }, 209 { 40, 40, 50, 50 }, 210 { 0, 0, 100, 100 }, 211 { 0, 0, 100, 100 }, 212 { 0, 0, 100, 100 }, 213 214 // invA op invB 215 { 0, 0, 100, 100 }, 216 { 40, 40, 80, 80 }, 217 { 0, 0, 100, 100 }, 218 { 10, 10, 80, 80 }, 219 { 10, 10, 50, 50 }, 220 }; 221 222 static const SkRegion::Op gOps[] = { 223 SkRegion::kIntersect_Op, 224 SkRegion::kDifference_Op, 225 SkRegion::kUnion_Op, 226 SkRegion::kXOR_Op, 227 SkRegion::kReverseDifference_Op 228 }; 229 230 SkRect rectA, rectB; 231 232 rectA.iset(10, 10, 50, 50); 233 rectB.iset(40, 40, 80, 80); 234 235 SkPath clipA, clipB; 236 237 clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5)); 238 clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5)); 239 240 SkClipStack stack; 241 SkRect devClipBound; 242 bool isIntersectionOfRects = false; 243 244 int testCase = 0; 245 int numBitTests = useRects ? 1 : 4; 246 for (int invBits = 0; invBits < numBitTests; ++invBits) { 247 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) { 248 249 stack.save(); 250 bool doInvA = SkToBool(invBits & 1); 251 bool doInvB = SkToBool(invBits & 2); 252 253 clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType : 254 SkPath::kEvenOdd_FillType); 255 clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType : 256 SkPath::kEvenOdd_FillType); 257 258 if (useRects) { 259 stack.clipDevRect(rectA, SkRegion::kIntersect_Op, false); 260 stack.clipDevRect(rectB, gOps[op], false); 261 } else { 262 stack.clipDevPath(clipA, SkRegion::kIntersect_Op, false); 263 stack.clipDevPath(clipB, gOps[op], false); 264 } 265 266 REPORTER_ASSERT(reporter, !stack.isWideOpen()); 267 268 stack.getConservativeBounds(0, 0, 100, 100, &devClipBound, 269 &isIntersectionOfRects); 270 271 if (useRects) { 272 REPORTER_ASSERT(reporter, isIntersectionOfRects == 273 (gOps[op] == SkRegion::kIntersect_Op)); 274 } else { 275 REPORTER_ASSERT(reporter, !isIntersectionOfRects); 276 } 277 278 SkASSERT(testCase < gNumCases); 279 REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]); 280 ++testCase; 281 282 stack.restore(); 283 } 284 } 285} 286 287// Test out 'isWideOpen' entry point 288static void test_isWideOpen(skiatest::Reporter* reporter) { 289 290 SkRect rectA, rectB; 291 292 rectA.iset(10, 10, 40, 40); 293 rectB.iset(50, 50, 80, 80); 294 295 // Stack should initially be wide open 296 { 297 SkClipStack stack; 298 299 REPORTER_ASSERT(reporter, stack.isWideOpen()); 300 } 301 302 // Test out case where the user specifies a union that includes everything 303 { 304 SkClipStack stack; 305 306 SkPath clipA, clipB; 307 308 clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5)); 309 clipA.setFillType(SkPath::kInverseEvenOdd_FillType); 310 311 clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5)); 312 clipB.setFillType(SkPath::kInverseEvenOdd_FillType); 313 314 stack.clipDevPath(clipA, SkRegion::kReplace_Op, false); 315 stack.clipDevPath(clipB, SkRegion::kUnion_Op, false); 316 317 REPORTER_ASSERT(reporter, stack.isWideOpen()); 318 } 319 320 // Test out union w/ a wide open clip 321 { 322 SkClipStack stack; 323 324 stack.clipDevRect(rectA, SkRegion::kUnion_Op, false); 325 326 REPORTER_ASSERT(reporter, stack.isWideOpen()); 327 } 328 329 // Test out empty difference from a wide open clip 330 { 331 SkClipStack stack; 332 333 SkRect emptyRect; 334 emptyRect.setEmpty(); 335 336 stack.clipDevRect(emptyRect, SkRegion::kDifference_Op, false); 337 338 REPORTER_ASSERT(reporter, stack.isWideOpen()); 339 } 340 341 // Test out return to wide open 342 { 343 SkClipStack stack; 344 345 stack.save(); 346 347 stack.clipDevRect(rectA, SkRegion::kReplace_Op, false); 348 349 REPORTER_ASSERT(reporter, !stack.isWideOpen()); 350 351 stack.restore(); 352 353 REPORTER_ASSERT(reporter, stack.isWideOpen()); 354 } 355} 356 357static int count(const SkClipStack& stack) { 358 359 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); 360 361 const SkClipStack::Iter::Clip* clip = NULL; 362 int count = 0; 363 364 for (clip = iter.prev(); clip; clip = iter.prev(), ++count) { 365 ; 366 } 367 368 return count; 369} 370 371// Test out SkClipStack's merging of rect clips. In particular exercise 372// merging of aa vs. bw rects. 373static void test_rect_merging(skiatest::Reporter* reporter) { 374 375 SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50); 376 SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80); 377 378 SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90); 379 SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60); 380 381 SkRect bound; 382 SkClipStack::BoundsType type; 383 bool isIntersectionOfRects; 384 385 // all bw overlapping - should merge 386 { 387 SkClipStack stack; 388 389 stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, false); 390 391 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); 392 393 REPORTER_ASSERT(reporter, 1 == count(stack)); 394 395 stack.getBounds(&bound, &type, &isIntersectionOfRects); 396 397 REPORTER_ASSERT(reporter, isIntersectionOfRects); 398 } 399 400 // all aa overlapping - should merge 401 { 402 SkClipStack stack; 403 404 stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true); 405 406 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true); 407 408 REPORTER_ASSERT(reporter, 1 == count(stack)); 409 410 stack.getBounds(&bound, &type, &isIntersectionOfRects); 411 412 REPORTER_ASSERT(reporter, isIntersectionOfRects); 413 } 414 415 // mixed overlapping - should _not_ merge 416 { 417 SkClipStack stack; 418 419 stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true); 420 421 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); 422 423 REPORTER_ASSERT(reporter, 2 == count(stack)); 424 425 stack.getBounds(&bound, &type, &isIntersectionOfRects); 426 427 REPORTER_ASSERT(reporter, !isIntersectionOfRects); 428 } 429 430 // mixed nested (bw inside aa) - should merge 431 { 432 SkClipStack stack; 433 434 stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, true); 435 436 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, false); 437 438 REPORTER_ASSERT(reporter, 1 == count(stack)); 439 440 stack.getBounds(&bound, &type, &isIntersectionOfRects); 441 442 REPORTER_ASSERT(reporter, isIntersectionOfRects); 443 } 444 445 // mixed nested (aa inside bw) - should merge 446 { 447 SkClipStack stack; 448 449 stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, false); 450 451 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, true); 452 453 REPORTER_ASSERT(reporter, 1 == count(stack)); 454 455 stack.getBounds(&bound, &type, &isIntersectionOfRects); 456 457 REPORTER_ASSERT(reporter, isIntersectionOfRects); 458 } 459 460 // reverse nested (aa inside bw) - should _not_ merge 461 { 462 SkClipStack stack; 463 464 stack.clipDevRect(nestedChild, SkRegion::kReplace_Op, false); 465 466 stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, true); 467 468 REPORTER_ASSERT(reporter, 2 == count(stack)); 469 470 stack.getBounds(&bound, &type, &isIntersectionOfRects); 471 472 REPORTER_ASSERT(reporter, !isIntersectionOfRects); 473 } 474} 475 476 477// This is similar to the above test but tests the iterator's ability to merge rects in the 478// middle of a clip stack's sequence using nextCombined(). There is a save after every clip 479// element to prevent the clip stack from merging the rectangles as they are added. 480static void test_iter_rect_merging(skiatest::Reporter* reporter) { 481 482 SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50); 483 SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80); 484 485 SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90); 486 SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60); 487 488 SkRect farAway = SkRect::MakeLTRB(1000, 1000, 1010, 1010); 489 490 SkRect overlapIntersect; 491 overlapIntersect.intersect(overlapLeft, overlapRight); 492 493 SkPath path1, path2; 494 path1.addCircle(SkIntToScalar(30), SkIntToScalar(30), SkIntToScalar(1000)); 495 path2.addOval(SkRect::MakeWH(500, 600)); 496 497 const SkClipStack::Iter::Clip* clip; 498 499 // call nextCombined with an empty clip stack 500 { 501 SkClipStack stack; 502 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 503 REPORTER_ASSERT(reporter, NULL == iter.nextCombined()); 504 } 505 506 // two bw overlapping - should merge, bracketed by paths 507 { 508 SkClipStack stack; 509 stack.clipDevPath(path1, SkRegion::kIntersect_Op, false); stack.save(); 510 511 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, false); stack.save(); 512 513 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); stack.save(); 514 515 stack.clipDevPath(path2, SkRegion::kIntersect_Op, false); stack.save(); 516 517 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 518 519 clip = iter.nextCombined(); 520 REPORTER_ASSERT(reporter, *clip->fPath == path1 && !clip->fDoAA); 521 522 clip = iter.nextCombined(); 523 REPORTER_ASSERT(reporter, !clip->fDoAA && *clip->fRect == overlapIntersect); 524 525 clip = iter.nextCombined(); 526 REPORTER_ASSERT(reporter, *clip->fPath == path2 && !clip->fDoAA); 527 528 clip = iter.nextCombined(); 529 REPORTER_ASSERT(reporter, NULL == clip); 530 } 531 532 // same as above but rects are aa and no final path. 533 { 534 SkClipStack stack; 535 stack.clipDevPath(path1, SkRegion::kIntersect_Op, false); stack.save(); 536 537 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, true); stack.save(); 538 539 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true); stack.save(); 540 541 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 542 543 clip = iter.nextCombined(); 544 REPORTER_ASSERT(reporter, *clip->fPath == path1 && !clip->fDoAA); 545 546 clip = iter.nextCombined(); 547 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == overlapIntersect); 548 549 clip = iter.nextCombined(); 550 REPORTER_ASSERT(reporter, NULL == clip); 551 } 552 553 // mixed overlapping - no paths - should _not_ merge 554 { 555 SkClipStack stack; 556 557 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, true); stack.save(); 558 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); stack.save(); 559 560 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 561 562 clip = iter.nextCombined(); 563 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == overlapLeft); 564 565 clip = iter.nextCombined(); 566 REPORTER_ASSERT(reporter, !clip->fDoAA && *clip->fRect == overlapRight); 567 568 clip = iter.nextCombined(); 569 REPORTER_ASSERT(reporter, NULL == clip); 570 } 571 572 // three rects in a row where the third rect uses a non-intersect op. 573 { 574 SkClipStack stack; 575 576 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, true); stack.save(); 577 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true); stack.save(); 578 stack.clipDevRect(nestedParent, SkRegion::kXOR_Op, true); stack.save(); 579 580 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 581 582 clip = iter.nextCombined(); 583 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == overlapIntersect); 584 clip = iter.nextCombined(); 585 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == nestedParent); 586 clip = iter.nextCombined(); 587 REPORTER_ASSERT(reporter, NULL == clip); 588 } 589 590 // mixed nested (bw inside aa) - should merge 591 { 592 SkClipStack stack; 593 stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, false); stack.save(); 594 595 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, true); stack.save(); 596 597 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 598 599 clip = iter.nextCombined(); 600 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == nestedChild); 601 602 clip = iter.nextCombined(); 603 REPORTER_ASSERT(reporter, NULL == clip); 604 } 605 606 // mixed nested (aa inside bw) - should merge 607 { 608 SkClipStack stack; 609 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, false); stack.save(); 610 611 stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, true); stack.save(); 612 613 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 614 615 clip = iter.nextCombined(); 616 REPORTER_ASSERT(reporter, !clip->fDoAA && *clip->fRect == nestedChild); 617 618 clip = iter.nextCombined(); 619 REPORTER_ASSERT(reporter, NULL == clip); 620 } 621 622 // three rect intersects in a row where result is empty after the second. 623 { 624 SkClipStack stack; 625 626 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, false); stack.save(); 627 stack.clipDevRect(farAway, SkRegion::kIntersect_Op, false); stack.save(); 628 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); stack.save(); 629 630 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 631 632 clip = iter.nextCombined(); 633 REPORTER_ASSERT(reporter, clip->fRect->isEmpty()); 634 635 clip = iter.nextCombined(); 636 REPORTER_ASSERT(reporter, *clip->fRect == overlapRight); 637 638 clip = iter.nextCombined(); 639 REPORTER_ASSERT(reporter, NULL == clip); 640 } 641} 642 643static void TestClipStack(skiatest::Reporter* reporter) { 644 SkClipStack stack; 645 646 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 647 assert_count(reporter, stack, 0); 648 649 static const SkIRect gRects[] = { 650 { 0, 0, 100, 100 }, 651 { 25, 25, 125, 125 }, 652 { 0, 0, 1000, 1000 }, 653 { 0, 0, 75, 75 } 654 }; 655 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) { 656 stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op); 657 } 658 659 // all of the above rects should have been intersected, leaving only 1 rect 660 SkClipStack::B2TIter iter(stack); 661 const SkClipStack::B2TIter::Clip* clip = iter.next(); 662 SkRect answer; 663 answer.iset(25, 25, 75, 75); 664 665 REPORTER_ASSERT(reporter, clip); 666 REPORTER_ASSERT(reporter, clip->fRect); 667 REPORTER_ASSERT(reporter, !clip->fPath); 668 REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == clip->fOp); 669 REPORTER_ASSERT(reporter, *clip->fRect == answer); 670 // now check that we only had one in our iterator 671 REPORTER_ASSERT(reporter, !iter.next()); 672 673 stack.reset(); 674 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 675 assert_count(reporter, stack, 0); 676 677 test_assign_and_comparison(reporter); 678 test_iterators(reporter); 679 test_bounds(reporter, true); // once with rects 680 test_bounds(reporter, false); // once with paths 681 test_isWideOpen(reporter); 682 test_rect_merging(reporter); 683 test_iter_rect_merging(reporter); 684} 685 686#include "TestClassDef.h" 687DEFINE_TESTCLASS("ClipStack", TestClipStackClass, TestClipStack) 688