blob: 9a5d71727651310a29dfc9c987177a41a7d9a189 [file] [log] [blame]
reed@google.com5c3d1472011-02-22 19:12:23 +00001#include "SkClipStack.h"
2#include "SkPath.h"
3#include <new>
4
5struct SkClipStack::Rec {
6 enum State {
7 kEmpty_State,
8 kRect_State,
9 kPath_State
10 };
11
12 SkPath fPath;
13 SkRect fRect;
14 int fSaveCount;
15 SkRegion::Op fOp;
16 State fState;
17
18 Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
19 fSaveCount = saveCount;
20 fOp = op;
21 fState = kRect_State;
22 }
23
24 Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
25 fSaveCount = saveCount;
26 fOp = op;
27 fState = kPath_State;
28 }
29
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000030 bool operator==(const Rec& b) const {
31 if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) {
32 return false;
33 }
34 switch (fState) {
35 case kEmpty_State:
36 return true;
37 case kRect_State:
38 return fRect == b.fRect;
39 case kPath_State:
40 return fPath == b.fPath;
41 }
42 return false; // Silence the compiler.
43 }
44
45 bool operator!=(const Rec& b) const {
46 return !(*this == b);
47 }
48
49
reed@google.com5c3d1472011-02-22 19:12:23 +000050 /**
51 * Returns true if this Rec can be intersected in place with a new clip
52 */
53 bool canBeIntersected(int saveCount, SkRegion::Op op) const {
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000054 if (kEmpty_State == fState && (
55 SkRegion::kDifference_Op == op ||
56 SkRegion::kIntersect_Op == op)) {
reed@google.com5c3d1472011-02-22 19:12:23 +000057 return true;
58 }
59 return fSaveCount == saveCount &&
60 SkRegion::kIntersect_Op == fOp &&
61 SkRegion::kIntersect_Op == op;
62 }
63};
64
65SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
66 fSaveCount = 0;
67}
68
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000069SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
70 *this = b;
71}
72
73SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
74 if (this == &b) {
75 return *this;
76 }
77 reset();
78
79 fSaveCount = b.fSaveCount;
80 SkDeque::F2BIter recIter(b.fDeque);
81 for (const Rec* rec = (const Rec*)recIter.next();
82 rec != NULL;
83 rec = (const Rec*)recIter.next()) {
84 new (fDeque.push_back()) Rec(*rec);
85 }
86
87 return *this;
88}
89
90bool SkClipStack::operator==(const SkClipStack& b) const {
91 if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) {
92 return false;
93 }
94 SkDeque::F2BIter myIter(fDeque);
95 SkDeque::F2BIter bIter(b.fDeque);
96 const Rec* myRec = (const Rec*)myIter.next();
97 const Rec* bRec = (const Rec*)bIter.next();
98
99 while (myRec != NULL && bRec != NULL) {
100 if (*myRec != *bRec) {
101 return false;
102 }
103 myRec = (const Rec*)myIter.next();
104 bRec = (const Rec*)bIter.next();
105 }
106 return myRec == NULL && bRec == NULL;
107}
108
reed@google.com5c3d1472011-02-22 19:12:23 +0000109void SkClipStack::reset() {
110 // don't have a reset() on SkDeque, so fake it here
111 fDeque.~SkDeque();
112 new (&fDeque) SkDeque(sizeof(Rec));
113
114 fSaveCount = 0;
115}
116
117void SkClipStack::save() {
118 fSaveCount += 1;
119}
120
121void SkClipStack::restore() {
122 fSaveCount -= 1;
123 while (!fDeque.empty()) {
124 Rec* rec = (Rec*)fDeque.back();
125 if (rec->fSaveCount <= fSaveCount) {
126 break;
127 }
128 rec->~Rec();
129 fDeque.pop_back();
130 }
131}
132
133void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
134 Rec* rec = (Rec*)fDeque.back();
135 if (rec && rec->canBeIntersected(fSaveCount, op)) {
136 switch (rec->fState) {
137 case Rec::kEmpty_State:
138 return;
139 case Rec::kRect_State:
140 if (!rec->fRect.intersect(rect)) {
141 rec->fState = Rec::kEmpty_State;
142 }
143 return;
144 case Rec::kPath_State:
145 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
146 rec->fState = Rec::kEmpty_State;
147 return;
148 }
149 break;
150 }
151 }
152 new (fDeque.push_back()) Rec(fSaveCount, rect, op);
153}
154
155void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
156 Rec* rec = (Rec*)fDeque.back();
157 if (rec && rec->canBeIntersected(fSaveCount, op)) {
158 const SkRect& pathBounds = path.getBounds();
159 switch (rec->fState) {
160 case Rec::kEmpty_State:
161 return;
162 case Rec::kRect_State:
163 if (!SkRect::Intersects(rec->fRect, pathBounds)) {
164 rec->fState = Rec::kEmpty_State;
165 return;
166 }
167 break;
168 case Rec::kPath_State:
169 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
170 rec->fState = Rec::kEmpty_State;
171 return;
172 }
173 break;
174 }
175 }
176 new (fDeque.push_back()) Rec(fSaveCount, path, op);
177}
178
179///////////////////////////////////////////////////////////////////////////////
180
bsalomon@google.comd302f142011-03-03 13:54:13 +0000181SkClipStack::B2FIter::B2FIter() {
182}
183
184SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
185 this->reset(stack);
reed@google.com5c3d1472011-02-22 19:12:23 +0000186}
187
188const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
189 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
190 if (NULL == rec) {
191 return NULL;
192 }
193
194 switch (rec->fState) {
195 case SkClipStack::Rec::kEmpty_State:
196 fClip.fRect = NULL;
197 fClip.fPath = NULL;
198 break;
199 case SkClipStack::Rec::kRect_State:
200 fClip.fRect = &rec->fRect;
201 fClip.fPath = NULL;
202 break;
203 case SkClipStack::Rec::kPath_State:
204 fClip.fRect = NULL;
205 fClip.fPath = &rec->fPath;
206 break;
207 }
208 fClip.fOp = rec->fOp;
209 return &fClip;
210}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000211
212void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
213 fIter.reset(stack.fDeque);
214}