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 "SkClipOp.h"
12 #include "SkDeque.h"
13 #include "SkRasterClip.h"
14 
15 template <typename T> class SkTStack {
16 public:
SkTStack(void * storage,size_t size)17     SkTStack(void* storage, size_t size) : fDeque(sizeof(T), storage, size), fTop(nullptr) {}
~SkTStack()18     ~SkTStack() {
19         while (!fDeque.empty()) {
20             ((T*)fDeque.back())->~T();
21             fDeque.pop_back();
22         }
23     }
24 
empty()25     bool empty() const { return fDeque.empty(); }
26 
count()27     int count() const { return fDeque.count(); }
28 
top()29     const T& top() const {
30         SkASSERT(fTop);
31         return *fTop;
32     }
33 
top()34     T& top() {
35         SkASSERT(fTop);
36         return *fTop;
37     }
38 
push_raw()39     T* push_raw() { return (T*)fDeque.push_back(); }
push()40     T& push() {
41         fTop = this->push_raw();
42         new (fTop) T();
43         return *fTop;
44     }
push(const T & src)45     T& push(const T& src) {
46         fTop = this->push_raw();
47         new (fTop) T(src);
48         return *fTop;
49     }
50 
pop()51     void pop() {
52         fTop->~T();
53         fDeque.pop_back();
54         fTop = fDeque.empty() ? nullptr : (T*)fDeque.back();
55     }
56 
57 private:
58     SkDeque fDeque;
59     T*      fTop;
60 };
61 
62 class SkRasterClipStack : SkNoncopyable {
63     int fCounter = 0;
64 public:
SkRasterClipStack(int width,int height)65     SkRasterClipStack(int width, int height)
66         : fStack(fStorage, sizeof(fStorage))
67         , fRootBounds(SkIRect::MakeWH(width, height))
68     {
69         Rec& rec = fStack.push();
70         rec.fRC.setRect(fRootBounds);
71         rec.fDeferredCount = 0;
72         SkASSERT(fStack.count() == 1);
73     }
74 
setNewSize(int w,int h)75     void setNewSize(int w, int h) {
76         fRootBounds.setXYWH(0, 0, w, h);
77 
78         SkASSERT(fStack.count() == 1);
79         Rec& rec = fStack.top();
80         SkASSERT(rec.fDeferredCount == 0);
81         rec.fRC.setRect(fRootBounds);
82     }
83 
rc()84     const SkRasterClip& rc() const { return fStack.top().fRC; }
85 
save()86     void save() {
87         fCounter += 1;
88         SkASSERT(fStack.top().fDeferredCount >= 0);
89         fStack.top().fDeferredCount += 1;
90     }
91 
restore()92     void restore() {
93         fCounter -= 1; SkASSERT(fCounter >= 0);
94         if (--fStack.top().fDeferredCount < 0) {
95             SkASSERT(fStack.top().fDeferredCount == -1);
96             SkASSERT(fStack.count() > 1);
97             fStack.pop();
98         }
99     }
100 
clipRect(const SkMatrix & ctm,const SkRect & rect,SkClipOp op,bool aa)101     void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) {
102         this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, aa);
103         this->trimIfExpanding(op);
104         this->validate();
105     }
106 
clipRRect(const SkMatrix & ctm,const SkRRect & rrect,SkClipOp op,bool aa)107     void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) {
108         this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, aa);
109         this->trimIfExpanding(op);
110         this->validate();
111     }
112 
clipPath(const SkMatrix & ctm,const SkPath & path,SkClipOp op,bool aa)113     void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) {
114         this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, aa);
115         this->trimIfExpanding(op);
116         this->validate();
117     }
118 
clipRegion(const SkRegion & rgn,SkClipOp op)119     void clipRegion(const SkRegion& rgn, SkClipOp op) {
120         this->writable_rc().op(rgn, (SkRegion::Op)op);
121         this->trimIfExpanding(op);
122         this->validate();
123     }
124 
setDeviceClipRestriction(SkIRect * mutableClipRestriction)125     void setDeviceClipRestriction(SkIRect* mutableClipRestriction) {
126         this->writable_rc().setDeviceClipRestriction(mutableClipRestriction);
127     }
128 
validate()129     void validate() const {
130 #ifdef SK_DEBUG
131         const SkRasterClip& clip = this->rc();
132         if (fRootBounds.isEmpty()) {
133             SkASSERT(clip.isEmpty());
134         } else if (!clip.isEmpty()) {
135             SkASSERT(fRootBounds.contains(clip.getBounds()));
136         }
137 #endif
138     }
139 
140 private:
141     struct Rec {
142         SkRasterClip    fRC;
143         int             fDeferredCount; // 0 for a "normal" entry
144     };
145 
146     enum {
147         ELEM_COUNT = 16,
148         PTR_COUNT = ELEM_COUNT * sizeof(Rec) / sizeof(void*)
149     };
150     void*           fStorage[PTR_COUNT];
151     SkTStack<Rec>   fStack;
152     SkIRect         fRootBounds;
153 
writable_rc()154     SkRasterClip& writable_rc() {
155         SkASSERT(fStack.top().fDeferredCount >= 0);
156         if (fStack.top().fDeferredCount > 0) {
157             fStack.top().fDeferredCount -= 1;
158             fStack.push(fStack.top());
159             fStack.top().fDeferredCount = 0;
160         }
161         return fStack.top().fRC;
162     }
163 
trimIfExpanding(SkClipOp op)164     void trimIfExpanding(SkClipOp op) {
165         if ((int)op > (int)SkClipOp::kIntersect) {
166             Rec& rec = fStack.top();
167             SkASSERT(rec.fDeferredCount == 0);
168             rec.fRC.op(fRootBounds, SkRegion::kIntersect_Op);
169         }
170     }
171 };
172 
173 #endif
174