SkClipStack.cpp revision 0557d9ea94d5435a9072c9b4141a05190d648442
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 "SkClipStack.h" 9#include "SkPath.h" 10#include "SkThread.h" 11 12#include <new> 13 14 15// 0-2 are reserved for invalid, empty & wide-open 16int32_t SkClipStack::gGenID = 3; 17 18struct SkClipStack::Rec { 19 enum State { 20 kEmpty_State, 21 kRect_State, 22 kPath_State 23 }; 24 25 SkPath fPath; 26 SkRect fRect; 27 int fSaveCount; 28 SkRegion::Op fOp; 29 State fState; 30 bool fDoAA; 31 32 // fFiniteBoundType and fFiniteBound are used to incrementally update 33 // the clip stack's bound. When fFiniteBoundType is kNormal_BoundsType, 34 // fFiniteBound represents the conservative bounding box of the pixels 35 // that aren't clipped (i.e., any pixels that can be drawn to are inside 36 // the bound). When fFiniteBoundType is kInsideOut_BoundsType (which occurs 37 // when a clip is inverse filled), fFiniteBound represents the 38 // conservative bounding box of the pixels that _are_ clipped (i.e., any 39 // pixels that cannot be drawn to are inside the bound). When 40 // fFiniteBoundType is kInsideOut_BoundsType the actual bound is 41 // the infinite plane. This behavior of fFiniteBoundType and 42 // fFiniteBound is required so that we can capture the cancelling out 43 // of the extensions to infinity when two inverse filled clips are 44 // Booleaned together. 45 SkClipStack::BoundsType fFiniteBoundType; 46 SkRect fFiniteBound; 47 bool fIsIntersectionOfRects; 48 49 int fGenID; 50 51 Rec(int saveCount) 52 : fGenID(kInvalidGenID) { 53 fSaveCount = saveCount; 54 this->setEmpty(); 55 } 56 57 Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) 58 : fRect(rect) 59 , fGenID(kInvalidGenID) { 60 fSaveCount = saveCount; 61 fOp = op; 62 fState = kRect_State; 63 fDoAA = doAA; 64 // bounding box members are updated in a following updateBound call 65 } 66 67 Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) 68 : fPath(path) 69 , fGenID(kInvalidGenID) { 70 fRect.setEmpty(); 71 fSaveCount = saveCount; 72 fOp = op; 73 fState = kPath_State; 74 fDoAA = doAA; 75 // bounding box members are updated in a following updateBound call 76 } 77 78 void setEmpty() { 79 fState = kEmpty_State; 80 fFiniteBound.setEmpty(); 81 fFiniteBoundType = kNormal_BoundsType; 82 fIsIntersectionOfRects = false; 83 fGenID = kEmptyGenID; 84 } 85 86 void checkEmpty() { 87 SkASSERT(fFiniteBound.isEmpty()); 88 SkASSERT(kNormal_BoundsType == fFiniteBoundType); 89 SkASSERT(!fIsIntersectionOfRects); 90 SkASSERT(kEmptyGenID == fGenID); 91 } 92 93 bool operator==(const Rec& b) const { 94 if (fSaveCount != b.fSaveCount || 95 fOp != b.fOp || 96 fState != b.fState || 97 fDoAA != b.fDoAA) { 98 return false; 99 } 100 switch (fState) { 101 case kEmpty_State: 102 return true; 103 case kRect_State: 104 return fRect == b.fRect; 105 case kPath_State: 106 return fPath == b.fPath; 107 } 108 return false; // Silence the compiler. 109 } 110 111 bool operator!=(const Rec& b) const { 112 return !(*this == b); 113 } 114 115 116 /** 117 * Returns true if this Rec can be intersected in place with a new clip 118 */ 119 bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const { 120 if (kEmpty_State == fState && ( 121 SkRegion::kDifference_Op == op || 122 SkRegion::kIntersect_Op == op)) { 123 return true; 124 } 125 // Only clips within the same save/restore frame (as captured by 126 // the save count) can be merged 127 return fSaveCount == saveCount && 128 SkRegion::kIntersect_Op == op && 129 (SkRegion::kIntersect_Op == fOp || SkRegion::kReplace_Op == fOp); 130 } 131 132 /** 133 * This method checks to see if two rect clips can be safely merged into 134 * one. The issue here is that to be strictly correct all the edges of 135 * the resulting rect must have the same anti-aliasing. 136 */ 137 bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const { 138 SkASSERT(kRect_State == fState); 139 140 if (fDoAA == newAA) { 141 // if the AA setting is the same there is no issue 142 return true; 143 } 144 145 if (!SkRect::Intersects(fRect, newR)) { 146 // The calling code will correctly set the result to the empty clip 147 return true; 148 } 149 150 if (fRect.contains(newR)) { 151 // if the new rect carves out a portion of the old one there is no 152 // issue 153 return true; 154 } 155 156 // So either the two overlap in some complex manner or newR contains oldR. 157 // In the first, case the edges will require different AA. In the second, 158 // the AA setting that would be carried forward is incorrect (e.g., oldR 159 // is AA while newR is BW but since newR contains oldR, oldR will be 160 // drawn BW) since the new AA setting will predominate. 161 return false; 162 } 163 164 165 /** 166 * The different combination of fill & inverse fill when combining 167 * bounding boxes 168 */ 169 enum FillCombo { 170 kPrev_Cur_FillCombo, 171 kPrev_InvCur_FillCombo, 172 kInvPrev_Cur_FillCombo, 173 kInvPrev_InvCur_FillCombo 174 }; 175 176 // a mirror of CombineBoundsRevDiff 177 void CombineBoundsDiff(FillCombo combination, const SkRect& prevFinite) { 178 switch (combination) { 179 case kInvPrev_InvCur_FillCombo: 180 // In this case the only pixels that can remain set 181 // are inside the current clip rect since the extensions 182 // to infinity of both clips cancel out and whatever 183 // is outside of the current clip is removed 184 fFiniteBoundType = kNormal_BoundsType; 185 break; 186 case kInvPrev_Cur_FillCombo: 187 // In this case the current op is finite so the only pixels 188 // that aren't set are whatever isn't set in the previous 189 // clip and whatever this clip carves out 190 fFiniteBound.join(prevFinite); 191 fFiniteBoundType = kInsideOut_BoundsType; 192 break; 193 case kPrev_InvCur_FillCombo: 194 // In this case everything outside of this clip's bound 195 // is erased, so the only pixels that can remain set 196 // occur w/in the intersection of the two finite bounds 197 if (!fFiniteBound.intersect(prevFinite)) { 198 fFiniteBound.setEmpty(); 199 } 200 fFiniteBoundType = kNormal_BoundsType; 201 break; 202 case kPrev_Cur_FillCombo: 203 // The most conservative result bound is that of the 204 // prior clip. This could be wildly incorrect if the 205 // second clip either exactly matches the first clip 206 // (which should yield the empty set) or reduces the 207 // size of the prior bound (e.g., if the second clip 208 // exactly matched the bottom half of the prior clip). 209 // We ignore these two possibilities. 210 fFiniteBound = prevFinite; 211 break; 212 default: 213 SkDEBUGFAIL("SkClipStack::Rec::CombineBoundsDiff Invalid fill combination"); 214 break; 215 } 216 } 217 218 void CombineBoundsXOR(int combination, const SkRect& prevFinite) { 219 220 switch (combination) { 221 case kInvPrev_Cur_FillCombo: // fall through 222 case kPrev_InvCur_FillCombo: 223 // With only one of the clips inverted the result will always 224 // extend to infinity. The only pixels that may be un-writeable 225 // lie within the union of the two finite bounds 226 fFiniteBound.join(prevFinite); 227 fFiniteBoundType = kInsideOut_BoundsType; 228 break; 229 case kInvPrev_InvCur_FillCombo: 230 // The only pixels that can survive are within the 231 // union of the two bounding boxes since the extensions 232 // to infinity of both clips cancel out 233 // fall through! 234 case kPrev_Cur_FillCombo: 235 // The most conservative bound for xor is the 236 // union of the two bounds. If the two clips exactly overlapped 237 // the xor could yield the empty set. Similarly the xor 238 // could reduce the size of the original clip's bound (e.g., 239 // if the second clip exactly matched the bottom half of the 240 // first clip). We ignore these two cases. 241 fFiniteBound.join(prevFinite); 242 fFiniteBoundType = kNormal_BoundsType; 243 break; 244 default: 245 SkDEBUGFAIL("SkClipStack::Rec::CombineBoundsXOR Invalid fill combination"); 246 break; 247 } 248 } 249 250 // a mirror of CombineBoundsIntersection 251 void CombineBoundsUnion(int combination, const SkRect& prevFinite) { 252 253 switch (combination) { 254 case kInvPrev_InvCur_FillCombo: 255 if (!fFiniteBound.intersect(prevFinite)) { 256 fFiniteBound.setEmpty(); 257 } 258 fFiniteBoundType = kInsideOut_BoundsType; 259 break; 260 case kInvPrev_Cur_FillCombo: 261 // The only pixels that won't be drawable are inside 262 // the prior clip's finite bound 263 fFiniteBound = prevFinite; 264 fFiniteBoundType = kInsideOut_BoundsType; 265 break; 266 case kPrev_InvCur_FillCombo: 267 // The only pixels that won't be drawable are inside 268 // this clip's finite bound 269 break; 270 case kPrev_Cur_FillCombo: 271 fFiniteBound.join(prevFinite); 272 break; 273 default: 274 SkDEBUGFAIL("SkClipStack::Rec::CombineBoundsUnion Invalid fill combination"); 275 break; 276 } 277 } 278 279 // a mirror of CombineBoundsUnion 280 void CombineBoundsIntersection(int combination, const SkRect& prevFinite) { 281 282 switch (combination) { 283 case kInvPrev_InvCur_FillCombo: 284 // The only pixels that aren't writable in this case 285 // occur in the union of the two finite bounds 286 fFiniteBound.join(prevFinite); 287 fFiniteBoundType = kInsideOut_BoundsType; 288 break; 289 case kInvPrev_Cur_FillCombo: 290 // In this case the only pixels that will remain writeable 291 // are within the current clip 292 break; 293 case kPrev_InvCur_FillCombo: 294 // In this case the only pixels that will remain writeable 295 // are with the previous clip 296 fFiniteBound = prevFinite; 297 fFiniteBoundType = kNormal_BoundsType; 298 break; 299 case kPrev_Cur_FillCombo: 300 if (!fFiniteBound.intersect(prevFinite)) { 301 fFiniteBound.setEmpty(); 302 } 303 break; 304 default: 305 SkDEBUGFAIL("SkClipStack::Rec::CombineBoundsIntersection Invalid fill combination"); 306 break; 307 } 308 } 309 310 // a mirror of CombineBoundsDiff 311 void CombineBoundsRevDiff(int combination, const SkRect& prevFinite) { 312 313 switch (combination) { 314 case kInvPrev_InvCur_FillCombo: 315 // The only pixels that can survive are in the 316 // previous bound since the extensions to infinity in 317 // both clips cancel out 318 fFiniteBound = prevFinite; 319 fFiniteBoundType = kNormal_BoundsType; 320 break; 321 case kInvPrev_Cur_FillCombo: 322 if (!fFiniteBound.intersect(prevFinite)) { 323 fFiniteBound.setEmpty(); 324 } 325 fFiniteBoundType = kNormal_BoundsType; 326 break; 327 case kPrev_InvCur_FillCombo: 328 fFiniteBound.join(prevFinite); 329 fFiniteBoundType = kInsideOut_BoundsType; 330 break; 331 case kPrev_Cur_FillCombo: 332 // Fall through - as with the kDifference_Op case, the 333 // most conservative result bound is the bound of the 334 // current clip. The prior clip could reduce the size of this 335 // bound (as in the kDifference_Op case) but we are ignoring 336 // those cases. 337 break; 338 default: 339 SkDEBUGFAIL("SkClipStack::Rec::CombineBoundsRevDiff Invalid fill combination"); 340 break; 341 } 342 } 343 344 void updateBound(const Rec* prior) { 345 346 // First, optimistically update the current Rec's bound information 347 // with the current clip's bound 348 fIsIntersectionOfRects = false; 349 if (kRect_State == fState) { 350 fFiniteBound = fRect; 351 fFiniteBoundType = kNormal_BoundsType; 352 353 if (SkRegion::kReplace_Op == fOp || 354 (SkRegion::kIntersect_Op == fOp && NULL == prior) || 355 (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && 356 prior->rectRectIntersectAllowed(fRect, fDoAA))) { 357 fIsIntersectionOfRects = true; 358 } 359 360 } else { 361 SkASSERT(kPath_State == fState); 362 363 fFiniteBound = fPath.getBounds(); 364 365 if (fPath.isInverseFillType()) { 366 fFiniteBoundType = kInsideOut_BoundsType; 367 } else { 368 fFiniteBoundType = kNormal_BoundsType; 369 } 370 } 371 372 if (!fDoAA) { 373 // Here we mimic a non-anti-aliased scanline system. If there is 374 // no anti-aliasing we can integerize the bounding box to exclude 375 // fractional parts that won't be rendered. 376 // Note: the left edge is handled slightly differently below. We 377 // are a bit more generous in the rounding since we don't want to 378 // risk missing the left pixels when fLeft is very close to .5 379 fFiniteBound.set(SkIntToScalar(SkScalarFloorToInt(fFiniteBound.fLeft+0.45f)), 380 SkIntToScalar(SkScalarRound(fFiniteBound.fTop)), 381 SkIntToScalar(SkScalarRound(fFiniteBound.fRight)), 382 SkIntToScalar(SkScalarRound(fFiniteBound.fBottom))); 383 } 384 385 // Now set up the previous Rec's bound information taking into 386 // account that there may be no previous clip 387 SkRect prevFinite; 388 SkClipStack::BoundsType prevType; 389 390 if (NULL == prior) { 391 // no prior clip means the entire plane is writable 392 prevFinite.setEmpty(); // there are no pixels that cannot be drawn to 393 prevType = kInsideOut_BoundsType; 394 } else { 395 prevFinite = prior->fFiniteBound; 396 prevType = prior->fFiniteBoundType; 397 } 398 399 FillCombo combination = kPrev_Cur_FillCombo; 400 if (kInsideOut_BoundsType == fFiniteBoundType) { 401 combination = (FillCombo) (combination | 0x01); 402 } 403 if (kInsideOut_BoundsType == prevType) { 404 combination = (FillCombo) (combination | 0x02); 405 } 406 407 SkASSERT(kInvPrev_InvCur_FillCombo == combination || 408 kInvPrev_Cur_FillCombo == combination || 409 kPrev_InvCur_FillCombo == combination || 410 kPrev_Cur_FillCombo == combination); 411 412 // Now integrate with clip with the prior clips 413 switch (fOp) { 414 case SkRegion::kDifference_Op: 415 this->CombineBoundsDiff(combination, prevFinite); 416 break; 417 case SkRegion::kXOR_Op: 418 this->CombineBoundsXOR(combination, prevFinite); 419 break; 420 case SkRegion::kUnion_Op: 421 this->CombineBoundsUnion(combination, prevFinite); 422 break; 423 case SkRegion::kIntersect_Op: 424 this->CombineBoundsIntersection(combination, prevFinite); 425 break; 426 case SkRegion::kReverseDifference_Op: 427 this->CombineBoundsRevDiff(combination, prevFinite); 428 break; 429 case SkRegion::kReplace_Op: 430 // Replace just ignores everything prior 431 // The current clip's bound information is already filled in 432 // so nothing to do 433 break; 434 default: 435 SkDebugf("SkRegion::Op error/n"); 436 SkASSERT(0); 437 break; 438 } 439 } 440}; 441 442 443SkClipStack::SkClipStack() 444 : fDeque(sizeof(Rec)) 445 , fSaveCount(0) { 446} 447 448SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) { 449 *this = b; 450} 451 452SkClipStack::SkClipStack(const SkRect& r) 453 : fDeque(sizeof(Rec)) 454 , fSaveCount(0) { 455 if (!r.isEmpty()) { 456 this->clipDevRect(r, SkRegion::kReplace_Op, false); 457 } 458} 459 460SkClipStack::SkClipStack(const SkIRect& r) 461 : fDeque(sizeof(Rec)) 462 , fSaveCount(0) { 463 if (!r.isEmpty()) { 464 SkRect temp; 465 temp.set(r); 466 this->clipDevRect(temp, SkRegion::kReplace_Op, false); 467 } 468} 469 470SkClipStack::~SkClipStack() { 471 reset(); 472} 473 474SkClipStack& SkClipStack::operator=(const SkClipStack& b) { 475 if (this == &b) { 476 return *this; 477 } 478 reset(); 479 480 fSaveCount = b.fSaveCount; 481 SkDeque::F2BIter recIter(b.fDeque); 482 for (const Rec* rec = (const Rec*)recIter.next(); 483 rec != NULL; 484 rec = (const Rec*)recIter.next()) { 485 new (fDeque.push_back()) Rec(*rec); 486 } 487 488 return *this; 489} 490 491bool SkClipStack::operator==(const SkClipStack& b) const { 492 if (fSaveCount != b.fSaveCount || 493 fDeque.count() != b.fDeque.count()) { 494 return false; 495 } 496 SkDeque::F2BIter myIter(fDeque); 497 SkDeque::F2BIter bIter(b.fDeque); 498 const Rec* myRec = (const Rec*)myIter.next(); 499 const Rec* bRec = (const Rec*)bIter.next(); 500 501 while (myRec != NULL && bRec != NULL) { 502 if (*myRec != *bRec) { 503 return false; 504 } 505 myRec = (const Rec*)myIter.next(); 506 bRec = (const Rec*)bIter.next(); 507 } 508 return myRec == NULL && bRec == NULL; 509} 510 511void SkClipStack::reset() { 512 // We used a placement new for each object in fDeque, so we're responsible 513 // for calling the destructor on each of them as well. 514 while (!fDeque.empty()) { 515 Rec* rec = (Rec*)fDeque.back(); 516 rec->~Rec(); 517 fDeque.pop_back(); 518 } 519 520 fSaveCount = 0; 521} 522 523void SkClipStack::save() { 524 fSaveCount += 1; 525} 526 527void SkClipStack::restore() { 528 fSaveCount -= 1; 529 while (!fDeque.empty()) { 530 Rec* rec = (Rec*)fDeque.back(); 531 if (rec->fSaveCount <= fSaveCount) { 532 break; 533 } 534 this->purgeClip(rec); 535 rec->~Rec(); 536 fDeque.pop_back(); 537 } 538} 539 540void SkClipStack::getBounds(SkRect* canvFiniteBound, 541 BoundsType* boundType, 542 bool* isIntersectionOfRects) const { 543 SkASSERT(NULL != canvFiniteBound && NULL != boundType); 544 545 Rec* rec = (Rec*)fDeque.back(); 546 547 if (NULL == rec) { 548 // the clip is wide open - the infinite plane w/ no pixels un-writeable 549 canvFiniteBound->setEmpty(); 550 *boundType = kInsideOut_BoundsType; 551 if (NULL != isIntersectionOfRects) { 552 *isIntersectionOfRects = false; 553 } 554 return; 555 } 556 557 *canvFiniteBound = rec->fFiniteBound; 558 *boundType = rec->fFiniteBoundType; 559 if (NULL != isIntersectionOfRects) { 560 *isIntersectionOfRects = rec->fIsIntersectionOfRects; 561 } 562} 563 564void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 565 566 int32_t genID = GetNextGenID(); 567 568 SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); 569 Rec* rec = (Rec*) iter.prev(); 570 571 if (rec && rec->canBeIntersectedInPlace(fSaveCount, op)) { 572 switch (rec->fState) { 573 case Rec::kEmpty_State: 574 rec->checkEmpty(); 575 return; 576 case Rec::kRect_State: 577 if (rec->rectRectIntersectAllowed(rect, doAA)) { 578 this->purgeClip(rec); 579 if (!rec->fRect.intersect(rect)) { 580 rec->setEmpty(); 581 return; 582 } 583 584 rec->fDoAA = doAA; 585 Rec* prev = (Rec*) iter.prev(); 586 rec->updateBound(prev); 587 rec->fGenID = genID; 588 return; 589 } 590 break; 591 case Rec::kPath_State: 592 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) { 593 this->purgeClip(rec); 594 rec->setEmpty(); 595 return; 596 } 597 break; 598 } 599 } 600 new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA); 601 ((Rec*) fDeque.back())->updateBound(rec); 602 ((Rec*) fDeque.back())->fGenID = genID; 603 604 if (rec && rec->fSaveCount == fSaveCount) { 605 this->purgeClip(rec); 606 } 607} 608 609void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { 610 SkRect alt; 611 if (path.isRect(&alt)) { 612 return this->clipDevRect(alt, op, doAA); 613 } 614 615 int32_t genID = GetNextGenID(); 616 617 Rec* rec = (Rec*)fDeque.back(); 618 if (rec && rec->canBeIntersectedInPlace(fSaveCount, op)) { 619 const SkRect& pathBounds = path.getBounds(); 620 switch (rec->fState) { 621 case Rec::kEmpty_State: 622 rec->checkEmpty(); 623 return; 624 case Rec::kRect_State: 625 if (!SkRect::Intersects(rec->fRect, pathBounds)) { 626 this->purgeClip(rec); 627 rec->setEmpty(); 628 return; 629 } 630 break; 631 case Rec::kPath_State: 632 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) { 633 this->purgeClip(rec); 634 rec->setEmpty(); 635 return; 636 } 637 break; 638 } 639 } 640 new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA); 641 ((Rec*) fDeque.back())->updateBound(rec); 642 ((Rec*) fDeque.back())->fGenID = genID; 643 644 if (rec && rec->fSaveCount == fSaveCount) { 645 this->purgeClip(rec); 646 } 647} 648 649void SkClipStack::clipEmpty() { 650 651 SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); 652 Rec* rec = (Rec*) iter.prev(); 653 654 if (rec && rec->canBeIntersectedInPlace(fSaveCount, SkRegion::kIntersect_Op)) { 655 switch (rec->fState) { 656 case Rec::kEmpty_State: 657 rec->checkEmpty(); 658 return; 659 case Rec::kRect_State: 660 case Rec::kPath_State: 661 this->purgeClip(rec); 662 rec->setEmpty(); 663 return; 664 } 665 } 666 new (fDeque.push_back()) Rec(fSaveCount); 667 668 if (rec && rec->fSaveCount == fSaveCount) { 669 this->purgeClip(rec); 670 } 671} 672 673bool SkClipStack::isWideOpen() const { 674 if (0 == fDeque.count()) { 675 return true; 676 } 677 678 const Rec* back = (const Rec*) fDeque.back(); 679 return kInsideOut_BoundsType == back->fFiniteBoundType && 680 back->fFiniteBound.isEmpty(); 681} 682 683/////////////////////////////////////////////////////////////////////////////// 684 685SkClipStack::Iter::Iter() : fStack(NULL) { 686} 687 688bool operator==(const SkClipStack::Iter::Clip& a, 689 const SkClipStack::Iter::Clip& b) { 690 return a.fOp == b.fOp && a.fDoAA == b.fDoAA && 691 ((a.fRect == NULL && b.fRect == NULL) || 692 (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) && 693 ((a.fPath == NULL && b.fPath == NULL) || 694 (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath)); 695} 696 697bool operator!=(const SkClipStack::Iter::Clip& a, 698 const SkClipStack::Iter::Clip& b) { 699 return !(a == b); 700} 701 702SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc) 703 : fStack(&stack) { 704 this->reset(stack, startLoc); 705} 706 707const SkClipStack::Iter::Clip* SkClipStack::Iter::updateClip( 708 const SkClipStack::Rec* rec) { 709 switch (rec->fState) { 710 case SkClipStack::Rec::kEmpty_State: 711 fClip.fRect = NULL; 712 fClip.fPath = NULL; 713 break; 714 case SkClipStack::Rec::kRect_State: 715 fClip.fRect = &rec->fRect; 716 fClip.fPath = NULL; 717 break; 718 case SkClipStack::Rec::kPath_State: 719 fClip.fRect = NULL; 720 fClip.fPath = &rec->fPath; 721 break; 722 } 723 fClip.fOp = rec->fOp; 724 fClip.fDoAA = rec->fDoAA; 725 fClip.fGenID = rec->fGenID; 726 return &fClip; 727} 728 729const SkClipStack::Iter::Clip* SkClipStack::Iter::next() { 730 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next(); 731 if (NULL == rec) { 732 return NULL; 733 } 734 735 return this->updateClip(rec); 736} 737 738const SkClipStack::Iter::Clip* SkClipStack::Iter::prev() { 739 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.prev(); 740 if (NULL == rec) { 741 return NULL; 742 } 743 744 return this->updateClip(rec); 745} 746 747const SkClipStack::Iter::Clip* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) { 748 749 if (NULL == fStack) { 750 return NULL; 751 } 752 753 fIter.reset(fStack->fDeque, SkDeque::Iter::kBack_IterStart); 754 755 const SkClipStack::Rec* rec = NULL; 756 757 for (rec = (const SkClipStack::Rec*) fIter.prev(); 758 NULL != rec; 759 rec = (const SkClipStack::Rec*) fIter.prev()) { 760 761 if (op == rec->fOp) { 762 // The Deque's iterator is actually one pace ahead of the 763 // returned value. So while "rec" is the element we want to 764 // return, the iterator is actually pointing at (and will 765 // return on the next "next" or "prev" call) the element 766 // in front of it in the deque. Bump the iterator forward a 767 // step so we get the expected result. 768 if (NULL == fIter.next()) { 769 // The reverse iterator has run off the front of the deque 770 // (i.e., the "op" clip is the first clip) and can't 771 // recover. Reset the iterator to start at the front. 772 fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart); 773 } 774 break; 775 } 776 } 777 778 if (NULL == rec) { 779 // There were no "op" clips 780 fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart); 781 } 782 783 return this->next(); 784} 785 786void SkClipStack::Iter::reset(const SkClipStack& stack, IterStart startLoc) { 787 fStack = &stack; 788 fIter.reset(stack.fDeque, static_cast<SkDeque::Iter::IterStart>(startLoc)); 789} 790 791// helper method 792void SkClipStack::getConservativeBounds(int offsetX, 793 int offsetY, 794 int maxWidth, 795 int maxHeight, 796 SkRect* devBounds, 797 bool* isIntersectionOfRects) const { 798 SkASSERT(NULL != devBounds); 799 800 devBounds->setLTRB(0, 0, 801 SkIntToScalar(maxWidth), SkIntToScalar(maxHeight)); 802 803 SkRect temp; 804 SkClipStack::BoundsType boundType; 805 806 // temp starts off in canvas space here 807 this->getBounds(&temp, &boundType, isIntersectionOfRects); 808 if (SkClipStack::kInsideOut_BoundsType == boundType) { 809 return; 810 } 811 812 // but is converted to device space here 813 temp.offset(SkIntToScalar(offsetX), SkIntToScalar(offsetY)); 814 815 if (!devBounds->intersect(temp)) { 816 devBounds->setEmpty(); 817 } 818} 819 820void SkClipStack::addPurgeClipCallback(PFPurgeClipCB callback, void* data) const { 821 ClipCallbackData temp = { callback, data }; 822 fCallbackData.append(1, &temp); 823} 824 825void SkClipStack::removePurgeClipCallback(PFPurgeClipCB callback, void* data) const { 826 ClipCallbackData temp = { callback, data }; 827 int index = fCallbackData.find(temp); 828 if (index >= 0) { 829 fCallbackData.removeShuffle(index); 830 } 831} 832 833// The clip state represented by 'rec' will never be used again. Purge it. 834void SkClipStack::purgeClip(Rec* rec) { 835 SkASSERT(NULL != rec); 836 837 for (int i = 0; i < fCallbackData.count(); ++i) { 838 (*fCallbackData[i].fCallback)(rec->fGenID, fCallbackData[i].fData); 839 } 840 841 // Invalidate rec's gen ID so handlers can detect already handled records 842 rec->fGenID = kInvalidGenID; 843} 844 845int32_t SkClipStack::GetNextGenID() { 846 return sk_atomic_inc(&gGenID); 847} 848 849int32_t SkClipStack::getTopmostGenID() const { 850 851 if (fDeque.empty()) { 852 return kInvalidGenID; 853 } 854 855 Rec* rec = (Rec*)fDeque.back(); 856 return rec->fGenID; 857} 858