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