Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkCanvas.h"
      9 #include "SkClipStack.h"
     10 #include "SkPath.h"
     11 #include "SkPathOps.h"
     12 #include "SkThread.h"
     13 
     14 #include <new>
     15 
     16 
     17 // 0-2 are reserved for invalid, empty & wide-open
     18 static const int32_t kFirstUnreservedGenID = 3;
     19 int32_t SkClipStack::gGenID = kFirstUnreservedGenID;
     20 
     21 SkClipStack::Element::Element(const Element& that) {
     22     switch (that.getType()) {
     23         case kEmpty_Type:
     24             fPath.reset();
     25             break;
     26         case kRect_Type: // Rect uses rrect
     27         case kRRect_Type:
     28             fPath.reset();
     29             fRRect = that.fRRect;
     30             break;
     31         case kPath_Type:
     32             fPath.set(that.getPath());
     33             break;
     34     }
     35 
     36     fSaveCount = that.fSaveCount;
     37     fOp = that.fOp;
     38     fType = that.fType;
     39     fDoAA = that.fDoAA;
     40     fFiniteBoundType = that.fFiniteBoundType;
     41     fFiniteBound = that.fFiniteBound;
     42     fIsIntersectionOfRects = that.fIsIntersectionOfRects;
     43     fGenID = that.fGenID;
     44 }
     45 
     46 bool SkClipStack::Element::operator== (const Element& element) const {
     47     if (this == &element) {
     48         return true;
     49     }
     50     if (fOp != element.fOp ||
     51         fType != element.fType ||
     52         fDoAA != element.fDoAA ||
     53         fSaveCount != element.fSaveCount) {
     54         return false;
     55     }
     56     switch (fType) {
     57         case kPath_Type:
     58             return this->getPath() == element.getPath();
     59         case kRRect_Type:
     60             return fRRect == element.fRRect;
     61         case kRect_Type:
     62             return this->getRect() == element.getRect();
     63         case kEmpty_Type:
     64             return true;
     65         default:
     66             SkDEBUGFAIL("Unexpected type.");
     67             return false;
     68     }
     69 }
     70 
     71 void SkClipStack::Element::replay(SkCanvasClipVisitor* visitor) const {
     72     static const SkRect kEmptyRect = { 0, 0, 0, 0 };
     73 
     74     switch (fType) {
     75         case kPath_Type:
     76             visitor->clipPath(this->getPath(), this->getOp(), this->isAA());
     77             break;
     78         case kRRect_Type:
     79             visitor->clipRRect(this->getRRect(), this->getOp(), this->isAA());
     80             break;
     81         case kRect_Type:
     82             visitor->clipRect(this->getRect(), this->getOp(), this->isAA());
     83             break;
     84         case kEmpty_Type:
     85             visitor->clipRect(kEmptyRect, SkRegion::kIntersect_Op, false);
     86             break;
     87     }
     88 }
     89 
     90 void SkClipStack::Element::invertShapeFillType() {
     91     switch (fType) {
     92         case kRect_Type:
     93             fPath.init();
     94             fPath.get()->addRect(this->getRect());
     95             fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType);
     96             fType = kPath_Type;
     97             break;
     98         case kRRect_Type:
     99             fPath.init();
    100             fPath.get()->addRRect(fRRect);
    101             fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType);
    102             fType = kPath_Type;
    103             break;
    104         case kPath_Type:
    105             fPath.get()->toggleInverseFillType();
    106             break;
    107         case kEmpty_Type:
    108             // Should this set to an empty, inverse filled path?
    109             break;
    110     }
    111 }
    112 
    113 void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkRegion::Op op,
    114                                     bool doAA) {
    115     if (!path.isInverseFillType()) {
    116         SkRect r;
    117         if (path.isRect(&r)) {
    118             this->initRect(saveCount, r, op, doAA);
    119             return;
    120         }
    121         SkRect ovalRect;
    122         if (path.isOval(&ovalRect)) {
    123             SkRRect rrect;
    124             rrect.setOval(ovalRect);
    125             this->initRRect(saveCount, rrect, op, doAA);
    126             return;
    127         }
    128     }
    129     fPath.set(path);
    130     fPath.get()->setIsVolatile(true);
    131     fType = kPath_Type;
    132     this->initCommon(saveCount, op, doAA);
    133 }
    134 
    135 void SkClipStack::Element::asPath(SkPath* path) const {
    136     switch (fType) {
    137         case kEmpty_Type:
    138             path->reset();
    139             break;
    140         case kRect_Type:
    141             path->reset();
    142             path->addRect(this->getRect());
    143             break;
    144         case kRRect_Type:
    145             path->reset();
    146             path->addRRect(fRRect);
    147             break;
    148         case kPath_Type:
    149             *path = *fPath.get();
    150             break;
    151     }
    152     path->setIsVolatile(true);
    153 }
    154 
    155 void SkClipStack::Element::setEmpty() {
    156     fType = kEmpty_Type;
    157     fFiniteBound.setEmpty();
    158     fFiniteBoundType = kNormal_BoundsType;
    159     fIsIntersectionOfRects = false;
    160     fRRect.setEmpty();
    161     fPath.reset();
    162     fGenID = kEmptyGenID;
    163     SkDEBUGCODE(this->checkEmpty();)
    164 }
    165 
    166 void SkClipStack::Element::checkEmpty() const {
    167     SkASSERT(fFiniteBound.isEmpty());
    168     SkASSERT(kNormal_BoundsType == fFiniteBoundType);
    169     SkASSERT(!fIsIntersectionOfRects);
    170     SkASSERT(kEmptyGenID == fGenID);
    171     SkASSERT(!fPath.isValid());
    172 }
    173 
    174 bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const {
    175     if (kEmpty_Type == fType &&
    176         (SkRegion::kDifference_Op == op || SkRegion::kIntersect_Op == op)) {
    177         return true;
    178     }
    179     // Only clips within the same save/restore frame (as captured by
    180     // the save count) can be merged
    181     return  fSaveCount == saveCount &&
    182             SkRegion::kIntersect_Op == op &&
    183             (SkRegion::kIntersect_Op == fOp || SkRegion::kReplace_Op == fOp);
    184 }
    185 
    186 bool SkClipStack::Element::rectRectIntersectAllowed(const SkRect& newR, bool newAA) const {
    187     SkASSERT(kRect_Type == fType);
    188 
    189     if (fDoAA == newAA) {
    190         // if the AA setting is the same there is no issue
    191         return true;
    192     }
    193 
    194     if (!SkRect::Intersects(this->getRect(), newR)) {
    195         // The calling code will correctly set the result to the empty clip
    196         return true;
    197     }
    198 
    199     if (this->getRect().contains(newR)) {
    200         // if the new rect carves out a portion of the old one there is no
    201         // issue
    202         return true;
    203     }
    204 
    205     // So either the two overlap in some complex manner or newR contains oldR.
    206     // In the first, case the edges will require different AA. In the second,
    207     // the AA setting that would be carried forward is incorrect (e.g., oldR
    208     // is AA while newR is BW but since newR contains oldR, oldR will be
    209     // drawn BW) since the new AA setting will predominate.
    210     return false;
    211 }
    212 
    213 // a mirror of combineBoundsRevDiff
    214 void SkClipStack::Element::combineBoundsDiff(FillCombo combination, const SkRect& prevFinite) {
    215     switch (combination) {
    216         case kInvPrev_InvCur_FillCombo:
    217             // In this case the only pixels that can remain set
    218             // are inside the current clip rect since the extensions
    219             // to infinity of both clips cancel out and whatever
    220             // is outside of the current clip is removed
    221             fFiniteBoundType = kNormal_BoundsType;
    222             break;
    223         case kInvPrev_Cur_FillCombo:
    224             // In this case the current op is finite so the only pixels
    225             // that aren't set are whatever isn't set in the previous
    226             // clip and whatever this clip carves out
    227             fFiniteBound.join(prevFinite);
    228             fFiniteBoundType = kInsideOut_BoundsType;
    229             break;
    230         case kPrev_InvCur_FillCombo:
    231             // In this case everything outside of this clip's bound
    232             // is erased, so the only pixels that can remain set
    233             // occur w/in the intersection of the two finite bounds
    234             if (!fFiniteBound.intersect(prevFinite)) {
    235                 this->setEmpty();
    236             } else {
    237                 fFiniteBoundType = kNormal_BoundsType;
    238             }
    239             break;
    240         case kPrev_Cur_FillCombo:
    241             // The most conservative result bound is that of the
    242             // prior clip. This could be wildly incorrect if the
    243             // second clip either exactly matches the first clip
    244             // (which should yield the empty set) or reduces the
    245             // size of the prior bound (e.g., if the second clip
    246             // exactly matched the bottom half of the prior clip).
    247             // We ignore these two possibilities.
    248             fFiniteBound = prevFinite;
    249             break;
    250         default:
    251             SkDEBUGFAIL("SkClipStack::Element::combineBoundsDiff Invalid fill combination");
    252             break;
    253     }
    254 }
    255 
    256 void SkClipStack::Element::combineBoundsXOR(int combination, const SkRect& prevFinite) {
    257 
    258     switch (combination) {
    259         case kInvPrev_Cur_FillCombo:       // fall through
    260         case kPrev_InvCur_FillCombo:
    261             // With only one of the clips inverted the result will always
    262             // extend to infinity. The only pixels that may be un-writeable
    263             // lie within the union of the two finite bounds
    264             fFiniteBound.join(prevFinite);
    265             fFiniteBoundType = kInsideOut_BoundsType;
    266             break;
    267         case kInvPrev_InvCur_FillCombo:
    268             // The only pixels that can survive are within the
    269             // union of the two bounding boxes since the extensions
    270             // to infinity of both clips cancel out
    271             // fall through!
    272         case kPrev_Cur_FillCombo:
    273             // The most conservative bound for xor is the
    274             // union of the two bounds. If the two clips exactly overlapped
    275             // the xor could yield the empty set. Similarly the xor
    276             // could reduce the size of the original clip's bound (e.g.,
    277             // if the second clip exactly matched the bottom half of the
    278             // first clip). We ignore these two cases.
    279             fFiniteBound.join(prevFinite);
    280             fFiniteBoundType = kNormal_BoundsType;
    281             break;
    282         default:
    283             SkDEBUGFAIL("SkClipStack::Element::combineBoundsXOR Invalid fill combination");
    284             break;
    285     }
    286 }
    287 
    288 // a mirror of combineBoundsIntersection
    289 void SkClipStack::Element::combineBoundsUnion(int combination, const SkRect& prevFinite) {
    290 
    291     switch (combination) {
    292         case kInvPrev_InvCur_FillCombo:
    293             if (!fFiniteBound.intersect(prevFinite)) {
    294                 fFiniteBound.setEmpty();
    295                 fGenID = kWideOpenGenID;
    296             }
    297             fFiniteBoundType = kInsideOut_BoundsType;
    298             break;
    299         case kInvPrev_Cur_FillCombo:
    300             // The only pixels that won't be drawable are inside
    301             // the prior clip's finite bound
    302             fFiniteBound = prevFinite;
    303             fFiniteBoundType = kInsideOut_BoundsType;
    304             break;
    305         case kPrev_InvCur_FillCombo:
    306             // The only pixels that won't be drawable are inside
    307             // this clip's finite bound
    308             break;
    309         case kPrev_Cur_FillCombo:
    310             fFiniteBound.join(prevFinite);
    311             break;
    312         default:
    313             SkDEBUGFAIL("SkClipStack::Element::combineBoundsUnion Invalid fill combination");
    314             break;
    315     }
    316 }
    317 
    318 // a mirror of combineBoundsUnion
    319 void SkClipStack::Element::combineBoundsIntersection(int combination, const SkRect& prevFinite) {
    320 
    321     switch (combination) {
    322         case kInvPrev_InvCur_FillCombo:
    323             // The only pixels that aren't writable in this case
    324             // occur in the union of the two finite bounds
    325             fFiniteBound.join(prevFinite);
    326             fFiniteBoundType = kInsideOut_BoundsType;
    327             break;
    328         case kInvPrev_Cur_FillCombo:
    329             // In this case the only pixels that will remain writeable
    330             // are within the current clip
    331             break;
    332         case kPrev_InvCur_FillCombo:
    333             // In this case the only pixels that will remain writeable
    334             // are with the previous clip
    335             fFiniteBound = prevFinite;
    336             fFiniteBoundType = kNormal_BoundsType;
    337             break;
    338         case kPrev_Cur_FillCombo:
    339             if (!fFiniteBound.intersect(prevFinite)) {
    340                 this->setEmpty();
    341             }
    342             break;
    343         default:
    344             SkDEBUGFAIL("SkClipStack::Element::combineBoundsIntersection Invalid fill combination");
    345             break;
    346     }
    347 }
    348 
    349 // a mirror of combineBoundsDiff
    350 void SkClipStack::Element::combineBoundsRevDiff(int combination, const SkRect& prevFinite) {
    351 
    352     switch (combination) {
    353         case kInvPrev_InvCur_FillCombo:
    354             // The only pixels that can survive are in the
    355             // previous bound since the extensions to infinity in
    356             // both clips cancel out
    357             fFiniteBound = prevFinite;
    358             fFiniteBoundType = kNormal_BoundsType;
    359             break;
    360         case kInvPrev_Cur_FillCombo:
    361             if (!fFiniteBound.intersect(prevFinite)) {
    362                 this->setEmpty();
    363             } else {
    364                 fFiniteBoundType = kNormal_BoundsType;
    365             }
    366             break;
    367         case kPrev_InvCur_FillCombo:
    368             fFiniteBound.join(prevFinite);
    369             fFiniteBoundType = kInsideOut_BoundsType;
    370             break;
    371         case kPrev_Cur_FillCombo:
    372             // Fall through - as with the kDifference_Op case, the
    373             // most conservative result bound is the bound of the
    374             // current clip. The prior clip could reduce the size of this
    375             // bound (as in the kDifference_Op case) but we are ignoring
    376             // those cases.
    377             break;
    378         default:
    379             SkDEBUGFAIL("SkClipStack::Element::combineBoundsRevDiff Invalid fill combination");
    380             break;
    381     }
    382 }
    383 
    384 void SkClipStack::Element::updateBoundAndGenID(const Element* prior) {
    385     // We set this first here but we may overwrite it later if we determine that the clip is
    386     // either wide-open or empty.
    387     fGenID = GetNextGenID();
    388 
    389     // First, optimistically update the current Element's bound information
    390     // with the current clip's bound
    391     fIsIntersectionOfRects = false;
    392     switch (fType) {
    393         case kRect_Type:
    394             fFiniteBound = this->getRect();
    395             fFiniteBoundType = kNormal_BoundsType;
    396 
    397             if (SkRegion::kReplace_Op == fOp ||
    398                 (SkRegion::kIntersect_Op == fOp && NULL == prior) ||
    399                 (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects &&
    400                     prior->rectRectIntersectAllowed(this->getRect(), fDoAA))) {
    401                 fIsIntersectionOfRects = true;
    402             }
    403             break;
    404         case kRRect_Type:
    405             fFiniteBound = fRRect.getBounds();
    406             fFiniteBoundType = kNormal_BoundsType;
    407             break;
    408         case kPath_Type:
    409             fFiniteBound = fPath.get()->getBounds();
    410 
    411             if (fPath.get()->isInverseFillType()) {
    412                 fFiniteBoundType = kInsideOut_BoundsType;
    413             } else {
    414                 fFiniteBoundType = kNormal_BoundsType;
    415             }
    416             break;
    417         case kEmpty_Type:
    418             SkDEBUGFAIL("We shouldn't get here with an empty element.");
    419             break;
    420     }
    421 
    422     if (!fDoAA) {
    423         fFiniteBound.set(SkScalarFloorToScalar(fFiniteBound.fLeft+0.45f),
    424                          SkScalarRoundToScalar(fFiniteBound.fTop),
    425                          SkScalarRoundToScalar(fFiniteBound.fRight),
    426                          SkScalarRoundToScalar(fFiniteBound.fBottom));
    427     }
    428 
    429     // Now determine the previous Element's bound information taking into
    430     // account that there may be no previous clip
    431     SkRect prevFinite;
    432     SkClipStack::BoundsType prevType;
    433 
    434     if (NULL == prior) {
    435         // no prior clip means the entire plane is writable
    436         prevFinite.setEmpty();   // there are no pixels that cannot be drawn to
    437         prevType = kInsideOut_BoundsType;
    438     } else {
    439         prevFinite = prior->fFiniteBound;
    440         prevType = prior->fFiniteBoundType;
    441     }
    442 
    443     FillCombo combination = kPrev_Cur_FillCombo;
    444     if (kInsideOut_BoundsType == fFiniteBoundType) {
    445         combination = (FillCombo) (combination | 0x01);
    446     }
    447     if (kInsideOut_BoundsType == prevType) {
    448         combination = (FillCombo) (combination | 0x02);
    449     }
    450 
    451     SkASSERT(kInvPrev_InvCur_FillCombo == combination ||
    452                 kInvPrev_Cur_FillCombo == combination ||
    453                 kPrev_InvCur_FillCombo == combination ||
    454                 kPrev_Cur_FillCombo == combination);
    455 
    456     // Now integrate with clip with the prior clips
    457     switch (fOp) {
    458         case SkRegion::kDifference_Op:
    459             this->combineBoundsDiff(combination, prevFinite);
    460             break;
    461         case SkRegion::kXOR_Op:
    462             this->combineBoundsXOR(combination, prevFinite);
    463             break;
    464         case SkRegion::kUnion_Op:
    465             this->combineBoundsUnion(combination, prevFinite);
    466             break;
    467         case SkRegion::kIntersect_Op:
    468             this->combineBoundsIntersection(combination, prevFinite);
    469             break;
    470         case SkRegion::kReverseDifference_Op:
    471             this->combineBoundsRevDiff(combination, prevFinite);
    472             break;
    473         case SkRegion::kReplace_Op:
    474             // Replace just ignores everything prior
    475             // The current clip's bound information is already filled in
    476             // so nothing to do
    477             break;
    478         default:
    479             SkDebugf("SkRegion::Op error\n");
    480             SkASSERT(0);
    481             break;
    482     }
    483 }
    484 
    485 // This constant determines how many Element's are allocated together as a block in
    486 // the deque. As such it needs to balance allocating too much memory vs.
    487 // incurring allocation/deallocation thrashing. It should roughly correspond to
    488 // the deepest save/restore stack we expect to see.
    489 static const int kDefaultElementAllocCnt = 8;
    490 
    491 SkClipStack::SkClipStack()
    492     : fDeque(sizeof(Element), kDefaultElementAllocCnt)
    493     , fSaveCount(0) {
    494 }
    495 
    496 SkClipStack::SkClipStack(const SkClipStack& b)
    497     : fDeque(sizeof(Element), kDefaultElementAllocCnt) {
    498     *this = b;
    499 }
    500 
    501 SkClipStack::SkClipStack(const SkRect& r)
    502     : fDeque(sizeof(Element), kDefaultElementAllocCnt)
    503     , fSaveCount(0) {
    504     if (!r.isEmpty()) {
    505         this->clipDevRect(r, SkRegion::kReplace_Op, false);
    506     }
    507 }
    508 
    509 SkClipStack::SkClipStack(const SkIRect& r)
    510     : fDeque(sizeof(Element), kDefaultElementAllocCnt)
    511     , fSaveCount(0) {
    512     if (!r.isEmpty()) {
    513         SkRect temp;
    514         temp.set(r);
    515         this->clipDevRect(temp, SkRegion::kReplace_Op, false);
    516     }
    517 }
    518 
    519 SkClipStack::~SkClipStack() {
    520     reset();
    521 }
    522 
    523 SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
    524     if (this == &b) {
    525         return *this;
    526     }
    527     reset();
    528 
    529     fSaveCount = b.fSaveCount;
    530     SkDeque::F2BIter recIter(b.fDeque);
    531     for (const Element* element = (const Element*)recIter.next();
    532          element != NULL;
    533          element = (const Element*)recIter.next()) {
    534         new (fDeque.push_back()) Element(*element);
    535     }
    536 
    537     return *this;
    538 }
    539 
    540 bool SkClipStack::operator==(const SkClipStack& b) const {
    541     if (this->getTopmostGenID() == b.getTopmostGenID()) {
    542         return true;
    543     }
    544     if (fSaveCount != b.fSaveCount ||
    545         fDeque.count() != b.fDeque.count()) {
    546         return false;
    547     }
    548     SkDeque::F2BIter myIter(fDeque);
    549     SkDeque::F2BIter bIter(b.fDeque);
    550     const Element* myElement = (const Element*)myIter.next();
    551     const Element* bElement = (const Element*)bIter.next();
    552 
    553     while (myElement != NULL && bElement != NULL) {
    554         if (*myElement != *bElement) {
    555             return false;
    556         }
    557         myElement = (const Element*)myIter.next();
    558         bElement = (const Element*)bIter.next();
    559     }
    560     return myElement == NULL && bElement == NULL;
    561 }
    562 
    563 void SkClipStack::reset() {
    564     // We used a placement new for each object in fDeque, so we're responsible
    565     // for calling the destructor on each of them as well.
    566     while (!fDeque.empty()) {
    567         Element* element = (Element*)fDeque.back();
    568         element->~Element();
    569         fDeque.pop_back();
    570     }
    571 
    572     fSaveCount = 0;
    573 }
    574 
    575 void SkClipStack::save() {
    576     fSaveCount += 1;
    577 }
    578 
    579 void SkClipStack::restore() {
    580     fSaveCount -= 1;
    581     restoreTo(fSaveCount);
    582 }
    583 
    584 void SkClipStack::restoreTo(int saveCount) {
    585     while (!fDeque.empty()) {
    586         Element* element = (Element*)fDeque.back();
    587         if (element->fSaveCount <= saveCount) {
    588             break;
    589         }
    590         element->~Element();
    591         fDeque.pop_back();
    592     }
    593 }
    594 
    595 void SkClipStack::getBounds(SkRect* canvFiniteBound,
    596                             BoundsType* boundType,
    597                             bool* isIntersectionOfRects) const {
    598     SkASSERT(canvFiniteBound && boundType);
    599 
    600     Element* element = (Element*)fDeque.back();
    601 
    602     if (NULL == element) {
    603         // the clip is wide open - the infinite plane w/ no pixels un-writeable
    604         canvFiniteBound->setEmpty();
    605         *boundType = kInsideOut_BoundsType;
    606         if (isIntersectionOfRects) {
    607             *isIntersectionOfRects = false;
    608         }
    609         return;
    610     }
    611 
    612     *canvFiniteBound = element->fFiniteBound;
    613     *boundType = element->fFiniteBoundType;
    614     if (isIntersectionOfRects) {
    615         *isIntersectionOfRects = element->fIsIntersectionOfRects;
    616     }
    617 }
    618 
    619 bool SkClipStack::quickContains(const SkRect& rect) const {
    620 
    621     Iter iter(*this, Iter::kTop_IterStart);
    622     const Element* element = iter.prev();
    623     while (element != NULL) {
    624         if (SkRegion::kIntersect_Op != element->getOp() && SkRegion::kReplace_Op != element->getOp())
    625             return false;
    626         if (element->isInverseFilled()) {
    627             // Part of 'rect' could be trimmed off by the inverse-filled clip element
    628             if (SkRect::Intersects(element->getBounds(), rect)) {
    629                 return false;
    630             }
    631         } else {
    632             if (!element->contains(rect)) {
    633                 return false;
    634             }
    635         }
    636         if (SkRegion::kReplace_Op == element->getOp()) {
    637             break;
    638         }
    639         element = iter.prev();
    640     }
    641     return true;
    642 }
    643 
    644 bool SkClipStack::asPath(SkPath *path) const {
    645     bool isAA = false;
    646 
    647     path->reset();
    648     path->setFillType(SkPath::kInverseEvenOdd_FillType);
    649 
    650     SkClipStack::Iter iter(*this, SkClipStack::Iter::kBottom_IterStart);
    651     while (const SkClipStack::Element* element = iter.next()) {
    652         SkPath operand;
    653         if (element->getType() != SkClipStack::Element::kEmpty_Type) {
    654             element->asPath(&operand);
    655         }
    656 
    657         SkRegion::Op elementOp = element->getOp();
    658         if (elementOp == SkRegion::kReplace_Op) {
    659             *path = operand;
    660         } else {
    661             Op(*path, operand, (SkPathOp)elementOp, path);
    662         }
    663 
    664         // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
    665         // perhaps we need an API change to avoid this sort of mixed-signals about
    666         // clipping.
    667         isAA = (isAA || element->isAA());
    668     }
    669 
    670     return isAA;
    671 }
    672 
    673 void SkClipStack::pushElement(const Element& element) {
    674     // Use reverse iterator instead of back because Rect path may need previous
    675     SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart);
    676     Element* prior = (Element*) iter.prev();
    677 
    678     if (prior) {
    679         if (prior->canBeIntersectedInPlace(fSaveCount, element.getOp())) {
    680             switch (prior->fType) {
    681                 case Element::kEmpty_Type:
    682                     SkDEBUGCODE(prior->checkEmpty();)
    683                     return;
    684                 case Element::kRect_Type:
    685                     if (Element::kRect_Type == element.getType()) {
    686                         if (prior->rectRectIntersectAllowed(element.getRect(), element.isAA())) {
    687                             SkRect isectRect;
    688                             if (!isectRect.intersect(prior->getRect(), element.getRect())) {
    689                                 prior->setEmpty();
    690                                 return;
    691                             }
    692 
    693                             prior->fRRect.setRect(isectRect);
    694                             prior->fDoAA = element.isAA();
    695                             Element* priorPrior = (Element*) iter.prev();
    696                             prior->updateBoundAndGenID(priorPrior);
    697                             return;
    698                         }
    699                         break;
    700                     }
    701                     // fallthrough
    702                 default:
    703                     if (!SkRect::Intersects(prior->getBounds(), element.getBounds())) {
    704                         prior->setEmpty();
    705                         return;
    706                     }
    707                     break;
    708             }
    709         } else if (SkRegion::kReplace_Op == element.getOp()) {
    710             this->restoreTo(fSaveCount - 1);
    711             prior = (Element*) fDeque.back();
    712         }
    713     }
    714     Element* newElement = SkNEW_PLACEMENT_ARGS(fDeque.push_back(), Element, (element));
    715     newElement->updateBoundAndGenID(prior);
    716 }
    717 
    718 void SkClipStack::clipDevRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
    719     Element element(fSaveCount, rrect, op, doAA);
    720     this->pushElement(element);
    721 }
    722 
    723 void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
    724     Element element(fSaveCount, rect, op, doAA);
    725     this->pushElement(element);
    726 }
    727 
    728 void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
    729     Element element(fSaveCount, path, op, doAA);
    730     this->pushElement(element);
    731 }
    732 
    733 void SkClipStack::clipEmpty() {
    734     Element* element = (Element*) fDeque.back();
    735 
    736     if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kIntersect_Op)) {
    737         element->setEmpty();
    738     }
    739     new (fDeque.push_back()) Element(fSaveCount);
    740 
    741     ((Element*)fDeque.back())->fGenID = kEmptyGenID;
    742 }
    743 
    744 bool SkClipStack::isWideOpen() const {
    745     return this->getTopmostGenID() == kWideOpenGenID;
    746 }
    747 
    748 ///////////////////////////////////////////////////////////////////////////////
    749 
    750 SkClipStack::Iter::Iter() : fStack(NULL) {
    751 }
    752 
    753 SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc)
    754     : fStack(&stack) {
    755     this->reset(stack, startLoc);
    756 }
    757 
    758 const SkClipStack::Element* SkClipStack::Iter::next() {
    759     return (const SkClipStack::Element*)fIter.next();
    760 }
    761 
    762 const SkClipStack::Element* SkClipStack::Iter::prev() {
    763     return (const SkClipStack::Element*)fIter.prev();
    764 }
    765 
    766 const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) {
    767 
    768     if (NULL == fStack) {
    769         return NULL;
    770     }
    771 
    772     fIter.reset(fStack->fDeque, SkDeque::Iter::kBack_IterStart);
    773 
    774     const SkClipStack::Element* element = NULL;
    775 
    776     for (element = (const SkClipStack::Element*) fIter.prev();
    777          element;
    778          element = (const SkClipStack::Element*) fIter.prev()) {
    779 
    780         if (op == element->fOp) {
    781             // The Deque's iterator is actually one pace ahead of the
    782             // returned value. So while "element" is the element we want to
    783             // return, the iterator is actually pointing at (and will
    784             // return on the next "next" or "prev" call) the element
    785             // in front of it in the deque. Bump the iterator forward a
    786             // step so we get the expected result.
    787             if (NULL == fIter.next()) {
    788                 // The reverse iterator has run off the front of the deque
    789                 // (i.e., the "op" clip is the first clip) and can't
    790                 // recover. Reset the iterator to start at the front.
    791                 fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart);
    792             }
    793             break;
    794         }
    795     }
    796 
    797     if (NULL == element) {
    798         // There were no "op" clips
    799         fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart);
    800     }
    801 
    802     return this->next();
    803 }
    804 
    805 void SkClipStack::Iter::reset(const SkClipStack& stack, IterStart startLoc) {
    806     fStack = &stack;
    807     fIter.reset(stack.fDeque, static_cast<SkDeque::Iter::IterStart>(startLoc));
    808 }
    809 
    810 // helper method
    811 void SkClipStack::getConservativeBounds(int offsetX,
    812                                         int offsetY,
    813                                         int maxWidth,
    814                                         int maxHeight,
    815                                         SkRect* devBounds,
    816                                         bool* isIntersectionOfRects) const {
    817     SkASSERT(devBounds);
    818 
    819     devBounds->setLTRB(0, 0,
    820                        SkIntToScalar(maxWidth), SkIntToScalar(maxHeight));
    821 
    822     SkRect temp;
    823     SkClipStack::BoundsType boundType;
    824 
    825     // temp starts off in canvas space here
    826     this->getBounds(&temp, &boundType, isIntersectionOfRects);
    827     if (SkClipStack::kInsideOut_BoundsType == boundType) {
    828         return;
    829     }
    830 
    831     // but is converted to device space here
    832     temp.offset(SkIntToScalar(offsetX), SkIntToScalar(offsetY));
    833 
    834     if (!devBounds->intersect(temp)) {
    835         devBounds->setEmpty();
    836     }
    837 }
    838 
    839 int32_t SkClipStack::GetNextGenID() {
    840     // TODO: handle overflow.
    841     return sk_atomic_inc(&gGenID);
    842 }
    843 
    844 int32_t SkClipStack::getTopmostGenID() const {
    845     if (fDeque.empty()) {
    846         return kWideOpenGenID;
    847     }
    848 
    849     const Element* back = static_cast<const Element*>(fDeque.back());
    850     if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.isEmpty()) {
    851         return kWideOpenGenID;
    852     }
    853 
    854     return back->getGenID();
    855 }
    856 
    857 #ifdef SK_DEVELOPER
    858 void SkClipStack::Element::dump() const {
    859     static const char* kTypeStrings[] = {
    860         "empty",
    861         "rect",
    862         "rrect",
    863         "path"
    864     };
    865     SK_COMPILE_ASSERT(0 == kEmpty_Type, type_str);
    866     SK_COMPILE_ASSERT(1 == kRect_Type, type_str);
    867     SK_COMPILE_ASSERT(2 == kRRect_Type, type_str);
    868     SK_COMPILE_ASSERT(3 == kPath_Type, type_str);
    869     SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kTypeStrings) == kTypeCnt, type_str);
    870 
    871     static const char* kOpStrings[] = {
    872         "difference",
    873         "intersect",
    874         "union",
    875         "xor",
    876         "reverse-difference",
    877         "replace",
    878     };
    879     SK_COMPILE_ASSERT(0 == SkRegion::kDifference_Op, op_str);
    880     SK_COMPILE_ASSERT(1 == SkRegion::kIntersect_Op, op_str);
    881     SK_COMPILE_ASSERT(2 == SkRegion::kUnion_Op, op_str);
    882     SK_COMPILE_ASSERT(3 == SkRegion::kXOR_Op, op_str);
    883     SK_COMPILE_ASSERT(4 == SkRegion::kReverseDifference_Op, op_str);
    884     SK_COMPILE_ASSERT(5 == SkRegion::kReplace_Op, op_str);
    885     SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kOpStrings) == SkRegion::kOpCnt, op_str);
    886 
    887     SkDebugf("Type: %s, Op: %s, AA: %s, Save Count: %d\n", kTypeStrings[fType],
    888              kOpStrings[fOp], (fDoAA ? "yes" : "no"), fSaveCount);
    889     switch (fType) {
    890         case kEmpty_Type:
    891             SkDebugf("\n");
    892             break;
    893         case kRect_Type:
    894             this->getRect().dump();
    895             SkDebugf("\n");
    896             break;
    897         case kRRect_Type:
    898             this->getRRect().dump();
    899             SkDebugf("\n");
    900             break;
    901         case kPath_Type:
    902             this->getPath().dump(NULL, true, false);
    903             break;
    904     }
    905 }
    906 
    907 void SkClipStack::dump() const {
    908     B2TIter iter(*this);
    909     const Element* e;
    910     while ((e = iter.next())) {
    911         e->dump();
    912         SkDebugf("\n");
    913     }
    914 }
    915 #endif
    916