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 
Element(const Element & that)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 
operator ==(const Element & element) const46 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 
replay(SkCanvasClipVisitor * visitor) const71 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 
invertShapeFillType()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 
initPath(int saveCount,const SkPath & path,SkRegion::Op op,bool doAA)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 
asPath(SkPath * path) const135 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 
setEmpty()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 
checkEmpty() const169 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 
canBeIntersectedInPlace(int saveCount,SkRegion::Op op) const177 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 
rectRectIntersectAllowed(const SkRect & newR,bool newAA) const189 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
combineBoundsDiff(FillCombo combination,const SkRect & prevFinite)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 
combineBoundsXOR(int combination,const SkRect & prevFinite)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
combineBoundsUnion(int combination,const SkRect & prevFinite)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
combineBoundsIntersection(int combination,const SkRect & prevFinite)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
combineBoundsRevDiff(int combination,const SkRect & prevFinite)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 
updateBoundAndGenID(const Element * prior)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 
SkClipStack()494 SkClipStack::SkClipStack()
495     : fDeque(sizeof(Element), kDefaultElementAllocCnt)
496     , fSaveCount(0) {
497 }
498 
SkClipStack(const SkClipStack & b)499 SkClipStack::SkClipStack(const SkClipStack& b)
500     : fDeque(sizeof(Element), kDefaultElementAllocCnt) {
501     *this = b;
502 }
503 
SkClipStack(const SkRect & r)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 
SkClipStack(const SkIRect & r)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 
~SkClipStack()522 SkClipStack::~SkClipStack() {
523     reset();
524 }
525 
operator =(const SkClipStack & b)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 
operator ==(const SkClipStack & b) const543 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 
reset()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 
save()578 void SkClipStack::save() {
579     fSaveCount += 1;
580 }
581 
restore()582 void SkClipStack::restore() {
583     fSaveCount -= 1;
584     restoreTo(fSaveCount);
585 }
586 
restoreTo(int saveCount)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 
getBounds(SkRect * canvFiniteBound,BoundsType * boundType,bool * isIntersectionOfRects) const598 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 
quickContains(const SkRect & rect) const622 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 
asPath(SkPath * path) const647 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 
pushElement(const Element & element)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 
clipDevRRect(const SkRRect & rrect,SkRegion::Op op,bool doAA)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 
clipDevRect(const SkRect & rect,SkRegion::Op op,bool doAA)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 
clipDevPath(const SkPath & path,SkRegion::Op op,bool doAA)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 
clipEmpty()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 
isWideOpen() const747 bool SkClipStack::isWideOpen() const {
748     return this->getTopmostGenID() == kWideOpenGenID;
749 }
750 
751 ///////////////////////////////////////////////////////////////////////////////
752 
Iter()753 SkClipStack::Iter::Iter() : fStack(nullptr) {
754 }
755 
Iter(const SkClipStack & stack,IterStart startLoc)756 SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc)
757     : fStack(&stack) {
758     this->reset(stack, startLoc);
759 }
760 
next()761 const SkClipStack::Element* SkClipStack::Iter::next() {
762     return (const SkClipStack::Element*)fIter.next();
763 }
764 
prev()765 const SkClipStack::Element* SkClipStack::Iter::prev() {
766     return (const SkClipStack::Element*)fIter.prev();
767 }
768 
skipToTopmost(SkRegion::Op op)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 
reset(const SkClipStack & stack,IterStart startLoc)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
getConservativeBounds(int offsetX,int offsetY,int maxWidth,int maxHeight,SkRect * devBounds,bool * isIntersectionOfRects) const814 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 
GetNextGenID()842 int32_t SkClipStack::GetNextGenID() {
843     // TODO: handle overflow.
844     return sk_atomic_inc(&gGenID);
845 }
846 
getTopmostGenID() const847 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
dump() const861 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 
dump() const910 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