1/* 2 * Copyright 2017 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#ifndef SkRasterClipStack_DEFINED 9#define SkRasterClipStack_DEFINED 10 11#include "include/core/SkClipOp.h" 12#include "src/core/SkRasterClip.h" 13#include "src/core/SkScan.h" 14#include "src/core/SkTBlockList.h" 15 16class SkRasterClipStack : SkNoncopyable { 17public: 18 SkRasterClipStack(int width, int height) 19 : fRootBounds(SkIRect::MakeWH(width, height)) 20 , fDisableAA(SkScan::DowngradeClipAA(fRootBounds)) { 21 fStack.emplace_back(SkRasterClip(fRootBounds)); 22 SkASSERT(fStack.count() == 1); 23 } 24 25 void setNewSize(int w, int h) { 26 fRootBounds.setXYWH(0, 0, w, h); 27 28 SkASSERT(fStack.count() == 1); 29 Rec& rec = fStack.back(); 30 SkASSERT(rec.fDeferredCount == 0); 31 rec.fRC.setRect(fRootBounds); 32 } 33 34 const SkRasterClip& rc() const { return fStack.back().fRC; } 35 36 void save() { 37 SkDEBUGCODE(fCounter += 1); 38 SkASSERT(fStack.back().fDeferredCount >= 0); 39 fStack.back().fDeferredCount += 1; 40 } 41 42 void restore() { 43 SkDEBUGCODE(fCounter -= 1); 44 SkASSERT(fCounter >= 0); 45 46 if (--fStack.back().fDeferredCount < 0) { 47 SkASSERT(fStack.back().fDeferredCount == -1); 48 SkASSERT(fStack.count() > 1); 49 fStack.pop_back(); 50 } 51 } 52 53 void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) { 54 this->writable_rc().op(rect, ctm, op, this->finalAA(aa)); 55 this->validate(); 56 } 57 58 void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) { 59 this->writable_rc().op(rrect, ctm, op, this->finalAA(aa)); 60 this->validate(); 61 } 62 63 void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) { 64 this->writable_rc().op(path, ctm, op, this->finalAA(aa)); 65 this->validate(); 66 } 67 68 void clipShader(sk_sp<SkShader> sh) { 69 this->writable_rc().op(std::move(sh)); 70 this->validate(); 71 } 72 73 void clipRegion(const SkRegion& rgn, SkClipOp op) { 74 this->writable_rc().op(rgn, op); 75 this->validate(); 76 } 77 78 void replaceClip(const SkIRect& rect) { 79 SkIRect devRect = rect; 80 if (!devRect.intersect(fRootBounds)) { 81 this->writable_rc().setEmpty(); 82 } else { 83 this->writable_rc().setRect(devRect); 84 } 85 } 86 87 void validate() const { 88#ifdef SK_DEBUG 89 const SkRasterClip& clip = this->rc(); 90 if (fRootBounds.isEmpty()) { 91 SkASSERT(clip.isEmpty()); 92 } else if (!clip.isEmpty()) { 93 SkASSERT(fRootBounds.contains(clip.getBounds())); 94 } 95#endif 96 } 97 98private: 99 struct Rec { 100 SkRasterClip fRC; 101 int fDeferredCount; // 0 for a "normal" entry 102 103 Rec(const SkRasterClip& rc) : fRC(rc), fDeferredCount(0) {} 104 }; 105 106 SkTBlockList<Rec, 16> fStack; 107 SkIRect fRootBounds; 108 bool fDisableAA; 109 SkDEBUGCODE(int fCounter = 0); 110 111 SkRasterClip& writable_rc() { 112 SkASSERT(fStack.back().fDeferredCount >= 0); 113 if (fStack.back().fDeferredCount > 0) { 114 fStack.back().fDeferredCount -= 1; 115 fStack.emplace_back(fStack.back().fRC); 116 } 117 return fStack.back().fRC; 118 } 119 120 bool finalAA(bool aa) const { return aa && !fDisableAA; } 121}; 122 123#endif 124