OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 #include "SkClipStack.h" | 8 #include "SkClipStack.h" |
9 #include "SkPath.h" | 9 #include "SkPath.h" |
10 #include "SkThread.h" | 10 #include "SkThread.h" |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
445 fSaveCount -= 1; | 445 fSaveCount -= 1; |
446 restoreTo(fSaveCount); | 446 restoreTo(fSaveCount); |
447 } | 447 } |
448 | 448 |
449 void SkClipStack::restoreTo(int saveCount) { | 449 void SkClipStack::restoreTo(int saveCount) { |
450 while (!fDeque.empty()) { | 450 while (!fDeque.empty()) { |
451 Element* element = (Element*)fDeque.back(); | 451 Element* element = (Element*)fDeque.back(); |
452 if (element->fSaveCount <= saveCount) { | 452 if (element->fSaveCount <= saveCount) { |
453 break; | 453 break; |
454 } | 454 } |
| 455 this->purgeClip(element); |
455 element->~Element(); | 456 element->~Element(); |
456 fDeque.pop_back(); | 457 fDeque.pop_back(); |
457 } | 458 } |
458 } | 459 } |
459 | 460 |
460 void SkClipStack::getBounds(SkRect* canvFiniteBound, | 461 void SkClipStack::getBounds(SkRect* canvFiniteBound, |
461 BoundsType* boundType, | 462 BoundsType* boundType, |
462 bool* isIntersectionOfRects) const { | 463 bool* isIntersectionOfRects) const { |
463 SkASSERT(NULL != canvFiniteBound && NULL != boundType); | 464 SkASSERT(NULL != canvFiniteBound && NULL != boundType); |
464 | 465 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 Element* element = (Element*) iter.prev(); | 533 Element* element = (Element*) iter.prev(); |
533 | 534 |
534 if (NULL != element) { | 535 if (NULL != element) { |
535 if (element->canBeIntersectedInPlace(fSaveCount, op)) { | 536 if (element->canBeIntersectedInPlace(fSaveCount, op)) { |
536 switch (element->fType) { | 537 switch (element->fType) { |
537 case Element::kEmpty_Type: | 538 case Element::kEmpty_Type: |
538 element->checkEmpty(); | 539 element->checkEmpty(); |
539 return; | 540 return; |
540 case Element::kRect_Type: | 541 case Element::kRect_Type: |
541 if (element->rectRectIntersectAllowed(rect, doAA)) { | 542 if (element->rectRectIntersectAllowed(rect, doAA)) { |
| 543 this->purgeClip(element); |
542 if (!element->fRect.intersect(rect)) { | 544 if (!element->fRect.intersect(rect)) { |
543 element->setEmpty(); | 545 element->setEmpty(); |
544 return; | 546 return; |
545 } | 547 } |
546 | 548 |
547 element->fDoAA = doAA; | 549 element->fDoAA = doAA; |
548 Element* prev = (Element*) iter.prev(); | 550 Element* prev = (Element*) iter.prev(); |
549 element->updateBoundAndGenID(prev); | 551 element->updateBoundAndGenID(prev); |
550 return; | 552 return; |
551 } | 553 } |
552 break; | 554 break; |
553 case Element::kPath_Type: | 555 case Element::kPath_Type: |
554 if (!SkRect::Intersects(element->fPath.getBounds(), rect)) { | 556 if (!SkRect::Intersects(element->fPath.getBounds(), rect)) { |
| 557 this->purgeClip(element); |
555 element->setEmpty(); | 558 element->setEmpty(); |
556 return; | 559 return; |
557 } | 560 } |
558 break; | 561 break; |
559 } | 562 } |
560 } else if (SkRegion::kReplace_Op == op) { | 563 } else if (SkRegion::kReplace_Op == op) { |
561 this->restoreTo(fSaveCount - 1); | 564 this->restoreTo(fSaveCount - 1); |
562 element = (Element*) fDeque.back(); | 565 element = (Element*) fDeque.back(); |
563 } | 566 } |
564 } | 567 } |
565 new (fDeque.push_back()) Element(fSaveCount, rect, op, doAA); | 568 new (fDeque.push_back()) Element(fSaveCount, rect, op, doAA); |
566 ((Element*) fDeque.back())->updateBoundAndGenID(element); | 569 ((Element*) fDeque.back())->updateBoundAndGenID(element); |
| 570 |
| 571 if (element && element->fSaveCount == fSaveCount) { |
| 572 this->purgeClip(element); |
| 573 } |
567 } | 574 } |
568 | 575 |
569 void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 576 void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
570 SkRect alt; | 577 SkRect alt; |
571 if (path.isRect(&alt) && !path.isInverseFillType()) { | 578 if (path.isRect(&alt) && !path.isInverseFillType()) { |
572 return this->clipDevRect(alt, op, doAA); | 579 return this->clipDevRect(alt, op, doAA); |
573 } | 580 } |
574 | 581 |
575 Element* element = (Element*)fDeque.back(); | 582 Element* element = (Element*)fDeque.back(); |
576 if (NULL != element) { | 583 if (NULL != element) { |
577 if (element->canBeIntersectedInPlace(fSaveCount, op)) { | 584 if (element->canBeIntersectedInPlace(fSaveCount, op)) { |
578 const SkRect& pathBounds = path.getBounds(); | 585 const SkRect& pathBounds = path.getBounds(); |
579 switch (element->fType) { | 586 switch (element->fType) { |
580 case Element::kEmpty_Type: | 587 case Element::kEmpty_Type: |
581 element->checkEmpty(); | 588 element->checkEmpty(); |
582 return; | 589 return; |
583 case Element::kRect_Type: | 590 case Element::kRect_Type: |
584 if (!SkRect::Intersects(element->fRect, pathBounds)) { | 591 if (!SkRect::Intersects(element->fRect, pathBounds)) { |
| 592 this->purgeClip(element); |
585 element->setEmpty(); | 593 element->setEmpty(); |
586 return; | 594 return; |
587 } | 595 } |
588 break; | 596 break; |
589 case Element::kPath_Type: | 597 case Element::kPath_Type: |
590 if (!SkRect::Intersects(element->fPath.getBounds(), pathBoun
ds)) { | 598 if (!SkRect::Intersects(element->fPath.getBounds(), pathBoun
ds)) { |
| 599 this->purgeClip(element); |
591 element->setEmpty(); | 600 element->setEmpty(); |
592 return; | 601 return; |
593 } | 602 } |
594 break; | 603 break; |
595 } | 604 } |
596 } else if (SkRegion::kReplace_Op == op) { | 605 } else if (SkRegion::kReplace_Op == op) { |
597 this->restoreTo(fSaveCount - 1); | 606 this->restoreTo(fSaveCount - 1); |
598 element = (Element*) fDeque.back(); | 607 element = (Element*) fDeque.back(); |
599 } | 608 } |
600 } | 609 } |
601 new (fDeque.push_back()) Element(fSaveCount, path, op, doAA); | 610 new (fDeque.push_back()) Element(fSaveCount, path, op, doAA); |
602 ((Element*) fDeque.back())->updateBoundAndGenID(element); | 611 ((Element*) fDeque.back())->updateBoundAndGenID(element); |
| 612 |
| 613 if (element && element->fSaveCount == fSaveCount) { |
| 614 this->purgeClip(element); |
| 615 } |
603 } | 616 } |
604 | 617 |
605 void SkClipStack::clipEmpty() { | 618 void SkClipStack::clipEmpty() { |
606 | 619 |
607 Element* element = (Element*) fDeque.back(); | 620 Element* element = (Element*) fDeque.back(); |
608 | 621 |
609 if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kInter
sect_Op)) { | 622 if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kInter
sect_Op)) { |
610 switch (element->fType) { | 623 switch (element->fType) { |
611 case Element::kEmpty_Type: | 624 case Element::kEmpty_Type: |
612 element->checkEmpty(); | 625 element->checkEmpty(); |
613 return; | 626 return; |
614 case Element::kRect_Type: | 627 case Element::kRect_Type: |
615 case Element::kPath_Type: | 628 case Element::kPath_Type: |
| 629 this->purgeClip(element); |
616 element->setEmpty(); | 630 element->setEmpty(); |
617 return; | 631 return; |
618 } | 632 } |
619 } | 633 } |
620 new (fDeque.push_back()) Element(fSaveCount); | 634 new (fDeque.push_back()) Element(fSaveCount); |
621 | 635 |
| 636 if (element && element->fSaveCount == fSaveCount) { |
| 637 this->purgeClip(element); |
| 638 } |
622 ((Element*)fDeque.back())->fGenID = kEmptyGenID; | 639 ((Element*)fDeque.back())->fGenID = kEmptyGenID; |
623 } | 640 } |
624 | 641 |
625 bool SkClipStack::isWideOpen() const { | 642 bool SkClipStack::isWideOpen() const { |
626 return this->getTopmostGenID() == kWideOpenGenID; | 643 if (0 == fDeque.count()) { |
| 644 return true; |
| 645 } |
| 646 |
| 647 const Element* back = (const Element*) fDeque.back(); |
| 648 return kWideOpenGenID == back->fGenID || |
| 649 (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBoun
d.isEmpty()); |
627 } | 650 } |
628 | 651 |
629 /////////////////////////////////////////////////////////////////////////////// | 652 /////////////////////////////////////////////////////////////////////////////// |
630 | 653 |
631 SkClipStack::Iter::Iter() : fStack(NULL) { | 654 SkClipStack::Iter::Iter() : fStack(NULL) { |
632 } | 655 } |
633 | 656 |
634 SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc) | 657 SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc) |
635 : fStack(&stack) { | 658 : fStack(&stack) { |
636 this->reset(stack, startLoc); | 659 this->reset(stack, startLoc); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 } | 733 } |
711 | 734 |
712 // but is converted to device space here | 735 // but is converted to device space here |
713 temp.offset(SkIntToScalar(offsetX), SkIntToScalar(offsetY)); | 736 temp.offset(SkIntToScalar(offsetX), SkIntToScalar(offsetY)); |
714 | 737 |
715 if (!devBounds->intersect(temp)) { | 738 if (!devBounds->intersect(temp)) { |
716 devBounds->setEmpty(); | 739 devBounds->setEmpty(); |
717 } | 740 } |
718 } | 741 } |
719 | 742 |
| 743 void SkClipStack::addPurgeClipCallback(PFPurgeClipCB callback, void* data) const
{ |
| 744 ClipCallbackData temp = { callback, data }; |
| 745 fCallbackData.append(1, &temp); |
| 746 } |
| 747 |
| 748 void SkClipStack::removePurgeClipCallback(PFPurgeClipCB callback, void* data) co
nst { |
| 749 ClipCallbackData temp = { callback, data }; |
| 750 int index = fCallbackData.find(temp); |
| 751 if (index >= 0) { |
| 752 fCallbackData.removeShuffle(index); |
| 753 } |
| 754 } |
| 755 |
| 756 // The clip state represented by 'element' will never be used again. Purge it. |
| 757 void SkClipStack::purgeClip(Element* element) { |
| 758 SkASSERT(NULL != element); |
| 759 if (element->fGenID >= 0 && element->fGenID < kFirstUnreservedGenID) { |
| 760 return; |
| 761 } |
| 762 |
| 763 for (int i = 0; i < fCallbackData.count(); ++i) { |
| 764 (*fCallbackData[i].fCallback)(element->fGenID, fCallbackData[i].fData); |
| 765 } |
| 766 |
| 767 // Invalidate element's gen ID so handlers can detect already handled record
s |
| 768 element->fGenID = kInvalidGenID; |
| 769 } |
| 770 |
720 int32_t SkClipStack::GetNextGenID() { | 771 int32_t SkClipStack::GetNextGenID() { |
721 // TODO: handle overflow. | 772 // TODO: handle overflow. |
722 return sk_atomic_inc(&gGenID); | 773 return sk_atomic_inc(&gGenID); |
723 } | 774 } |
724 | 775 |
725 int32_t SkClipStack::getTopmostGenID() const { | 776 int32_t SkClipStack::getTopmostGenID() const { |
| 777 |
726 if (fDeque.empty()) { | 778 if (fDeque.empty()) { |
727 return kWideOpenGenID; | 779 return kInvalidGenID; |
728 } | 780 } |
729 | 781 |
730 const Element* back = static_cast<const Element*>(fDeque.back()); | 782 Element* element = (Element*)fDeque.back(); |
731 if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.is
Empty()) { | 783 return element->fGenID; |
732 return kWideOpenGenID; | |
733 } | |
734 | |
735 return back->getGenID(); | |
736 } | 784 } |
OLD | NEW |