blob: f7ddc978915a07a1db521017000a5f6334c26b6b [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@google.com5c3d1472011-02-22 19:12:23 +00008#include "SkClipStack.h"
9#include "SkPath.h"
10#include <new>
11
12struct SkClipStack::Rec {
13 enum State {
14 kEmpty_State,
15 kRect_State,
16 kPath_State
17 };
18
19 SkPath fPath;
20 SkRect fRect;
21 int fSaveCount;
22 SkRegion::Op fOp;
23 State fState;
reed@google.com00177082011-10-12 14:34:30 +000024 bool fDoAA;
reed@google.com5c3d1472011-02-22 19:12:23 +000025
reed@google.com00177082011-10-12 14:34:30 +000026 Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) : fRect(rect) {
reed@google.com5c3d1472011-02-22 19:12:23 +000027 fSaveCount = saveCount;
28 fOp = op;
29 fState = kRect_State;
reed@google.com00177082011-10-12 14:34:30 +000030 fDoAA = doAA;
reed@google.com5c3d1472011-02-22 19:12:23 +000031 }
32
reed@google.com00177082011-10-12 14:34:30 +000033 Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) : fPath(path) {
vandebo@chromium.orge1bc2742011-06-21 22:26:39 +000034 fRect.setEmpty();
reed@google.com5c3d1472011-02-22 19:12:23 +000035 fSaveCount = saveCount;
36 fOp = op;
37 fState = kPath_State;
reed@google.com00177082011-10-12 14:34:30 +000038 fDoAA = doAA;
reed@google.com5c3d1472011-02-22 19:12:23 +000039 }
40
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000041 bool operator==(const Rec& b) const {
reed@google.com00177082011-10-12 14:34:30 +000042 if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState ||
43 fDoAA != b.fDoAA) {
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000044 return false;
45 }
46 switch (fState) {
47 case kEmpty_State:
48 return true;
49 case kRect_State:
50 return fRect == b.fRect;
51 case kPath_State:
52 return fPath == b.fPath;
53 }
54 return false; // Silence the compiler.
55 }
56
57 bool operator!=(const Rec& b) const {
58 return !(*this == b);
59 }
60
61
reed@google.com5c3d1472011-02-22 19:12:23 +000062 /**
63 * Returns true if this Rec can be intersected in place with a new clip
64 */
65 bool canBeIntersected(int saveCount, SkRegion::Op op) const {
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000066 if (kEmpty_State == fState && (
67 SkRegion::kDifference_Op == op ||
68 SkRegion::kIntersect_Op == op)) {
reed@google.com5c3d1472011-02-22 19:12:23 +000069 return true;
70 }
71 return fSaveCount == saveCount &&
72 SkRegion::kIntersect_Op == fOp &&
73 SkRegion::kIntersect_Op == op;
74 }
75};
76
77SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
78 fSaveCount = 0;
79}
80
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000081SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
82 *this = b;
83}
84
vandebo@chromium.org610f7162012-03-14 18:34:15 +000085SkClipStack::~SkClipStack() {
86 reset();
87}
88
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000089SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
90 if (this == &b) {
91 return *this;
92 }
93 reset();
94
95 fSaveCount = b.fSaveCount;
96 SkDeque::F2BIter recIter(b.fDeque);
97 for (const Rec* rec = (const Rec*)recIter.next();
98 rec != NULL;
99 rec = (const Rec*)recIter.next()) {
100 new (fDeque.push_back()) Rec(*rec);
101 }
102
103 return *this;
104}
105
106bool SkClipStack::operator==(const SkClipStack& b) const {
107 if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) {
108 return false;
109 }
110 SkDeque::F2BIter myIter(fDeque);
111 SkDeque::F2BIter bIter(b.fDeque);
112 const Rec* myRec = (const Rec*)myIter.next();
113 const Rec* bRec = (const Rec*)bIter.next();
114
115 while (myRec != NULL && bRec != NULL) {
116 if (*myRec != *bRec) {
117 return false;
118 }
119 myRec = (const Rec*)myIter.next();
120 bRec = (const Rec*)bIter.next();
121 }
122 return myRec == NULL && bRec == NULL;
123}
124
reed@google.com5c3d1472011-02-22 19:12:23 +0000125void SkClipStack::reset() {
vandebo@chromium.org610f7162012-03-14 18:34:15 +0000126 // We used a placement new for each object in fDeque, so we're responsible
127 // for calling the destructor on each of them as well.
128 while (!fDeque.empty()) {
129 Rec* rec = (Rec*)fDeque.back();
130 rec->~Rec();
131 fDeque.pop_back();
132 }
reed@google.com5c3d1472011-02-22 19:12:23 +0000133
134 fSaveCount = 0;
135}
136
137void SkClipStack::save() {
138 fSaveCount += 1;
139}
140
141void SkClipStack::restore() {
142 fSaveCount -= 1;
143 while (!fDeque.empty()) {
144 Rec* rec = (Rec*)fDeque.back();
145 if (rec->fSaveCount <= fSaveCount) {
146 break;
147 }
148 rec->~Rec();
149 fDeque.pop_back();
150 }
151}
152
reed@google.com00177082011-10-12 14:34:30 +0000153void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed@google.com5c3d1472011-02-22 19:12:23 +0000154 Rec* rec = (Rec*)fDeque.back();
155 if (rec && rec->canBeIntersected(fSaveCount, op)) {
156 switch (rec->fState) {
157 case Rec::kEmpty_State:
158 return;
159 case Rec::kRect_State:
160 if (!rec->fRect.intersect(rect)) {
161 rec->fState = Rec::kEmpty_State;
162 }
163 return;
164 case Rec::kPath_State:
165 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
166 rec->fState = Rec::kEmpty_State;
167 return;
168 }
169 break;
170 }
171 }
reed@google.com00177082011-10-12 14:34:30 +0000172 new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
reed@google.com5c3d1472011-02-22 19:12:23 +0000173}
174
reed@google.com00177082011-10-12 14:34:30 +0000175void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
tomhudson@google.com4c433722012-03-09 16:48:20 +0000176 SkRect alt;
177 if (path.isRect(&alt)) {
178 return this->clipDevRect(alt, op, doAA);
179 }
reed@google.com5c3d1472011-02-22 19:12:23 +0000180 Rec* rec = (Rec*)fDeque.back();
181 if (rec && rec->canBeIntersected(fSaveCount, op)) {
182 const SkRect& pathBounds = path.getBounds();
183 switch (rec->fState) {
184 case Rec::kEmpty_State:
185 return;
186 case Rec::kRect_State:
187 if (!SkRect::Intersects(rec->fRect, pathBounds)) {
188 rec->fState = Rec::kEmpty_State;
189 return;
190 }
191 break;
192 case Rec::kPath_State:
193 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
194 rec->fState = Rec::kEmpty_State;
195 return;
196 }
197 break;
198 }
199 }
reed@google.com00177082011-10-12 14:34:30 +0000200 new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
reed@google.com5c3d1472011-02-22 19:12:23 +0000201}
202
203///////////////////////////////////////////////////////////////////////////////
204
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000205SkClipStack::Iter::Iter() : fStack(NULL) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000206}
207
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000208bool operator==(const SkClipStack::Iter::Clip& a,
209 const SkClipStack::Iter::Clip& b) {
reed@google.com00177082011-10-12 14:34:30 +0000210 return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
vandebo@chromium.orge03c6522011-06-21 20:45:51 +0000211 ((a.fRect == NULL && b.fRect == NULL) ||
212 (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
213 ((a.fPath == NULL && b.fPath == NULL) ||
214 (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath));
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000215}
216
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000217bool operator!=(const SkClipStack::Iter::Clip& a,
218 const SkClipStack::Iter::Clip& b) {
vandebo@chromium.org8887ede2011-05-25 01:27:52 +0000219 return !(a == b);
220}
221
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000222SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc)
223 : fStack(&stack) {
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000224 this->reset(stack, startLoc);
reed@google.com5c3d1472011-02-22 19:12:23 +0000225}
226
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000227const SkClipStack::Iter::Clip* SkClipStack::Iter::updateClip(
228 const SkClipStack::Rec* rec) {
reed@google.com5c3d1472011-02-22 19:12:23 +0000229 switch (rec->fState) {
230 case SkClipStack::Rec::kEmpty_State:
231 fClip.fRect = NULL;
232 fClip.fPath = NULL;
233 break;
234 case SkClipStack::Rec::kRect_State:
235 fClip.fRect = &rec->fRect;
236 fClip.fPath = NULL;
237 break;
238 case SkClipStack::Rec::kPath_State:
239 fClip.fRect = NULL;
240 fClip.fPath = &rec->fPath;
241 break;
242 }
243 fClip.fOp = rec->fOp;
reed@google.com00177082011-10-12 14:34:30 +0000244 fClip.fDoAA = rec->fDoAA;
reed@google.com5c3d1472011-02-22 19:12:23 +0000245 return &fClip;
246}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000247
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000248const SkClipStack::Iter::Clip* SkClipStack::Iter::next() {
249 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
250 if (NULL == rec) {
251 return NULL;
252 }
253
254 return this->updateClip(rec);
255}
256
257const SkClipStack::Iter::Clip* SkClipStack::Iter::prev() {
258 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.prev();
259 if (NULL == rec) {
260 return NULL;
261 }
262
263 return this->updateClip(rec);
264}
265
robertphillips@google.com5836b6d2012-07-18 12:06:15 +0000266const SkClipStack::Iter::Clip* SkClipStack::Iter::skipToLast(SkRegion::Op op) {
267
268 if (NULL == fStack) {
269 return NULL;
270 }
271
272 fIter.reset(fStack->fDeque, SkDeque::Iter::kBack_IterStart);
273
274 const SkClipStack::Rec* rec = NULL;
275
276 for (rec = (const SkClipStack::Rec*) fIter.prev();
277 NULL != rec;
278 rec = (const SkClipStack::Rec*) fIter.prev()) {
279
280 if (op == rec->fOp) {
281 // The Deque's iterator is actually one pace ahead of the
282 // returned value. So while "rec" is the element we want to
283 // return, the iterator is actually pointing at (and will
284 // return on the next "next" or "prev" call) the element
285 // in front of it in the deque. Bump the iterator forward a
286 // step so we get the expected result.
287 if (NULL == fIter.next()) {
288 // The reverse iterator has run off the front of the deque
289 // (i.e., the "op" clip is the first clip) and can't
290 // recover. Reset the iterator to start at the front.
291 fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart);
292 }
293 break;
294 }
295 }
296
297 if (NULL == rec) {
298 // There were no "op" clips
299 fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart);
300 }
301
302 return this->next();
303}
304
robertphillips@google.com52cb2c72012-07-16 18:52:29 +0000305void SkClipStack::Iter::reset(const SkClipStack& stack, IterStart startLoc) {
306 fIter.reset(stack.fDeque, static_cast<SkDeque::Iter::IterStart>(startLoc));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000307}