1
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 */
8 #include "SkClipStack.h"
9 #include "SkPath.h"
10 #include <new>
11
12 struct 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;
24 bool fDoAA;
25
RecSkClipStack::Rec26 Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) : fRect(rect) {
27 fSaveCount = saveCount;
28 fOp = op;
29 fState = kRect_State;
30 fDoAA = doAA;
31 }
32
RecSkClipStack::Rec33 Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) : fPath(path) {
34 fRect.setEmpty();
35 fSaveCount = saveCount;
36 fOp = op;
37 fState = kPath_State;
38 fDoAA = doAA;
39 }
40
operator ==SkClipStack::Rec41 bool operator==(const Rec& b) const {
42 if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState ||
43 fDoAA != b.fDoAA) {
44 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
operator !=SkClipStack::Rec57 bool operator!=(const Rec& b) const {
58 return !(*this == b);
59 }
60
61
62 /**
63 * Returns true if this Rec can be intersected in place with a new clip
64 */
canBeIntersectedSkClipStack::Rec65 bool canBeIntersected(int saveCount, SkRegion::Op op) const {
66 if (kEmpty_State == fState && (
67 SkRegion::kDifference_Op == op ||
68 SkRegion::kIntersect_Op == op)) {
69 return true;
70 }
71 return fSaveCount == saveCount &&
72 SkRegion::kIntersect_Op == fOp &&
73 SkRegion::kIntersect_Op == op;
74 }
75 };
76
SkClipStack()77 SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
78 fSaveCount = 0;
79 }
80
SkClipStack(const SkClipStack & b)81 SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
82 *this = b;
83 }
84
operator =(const SkClipStack & b)85 SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
86 if (this == &b) {
87 return *this;
88 }
89 reset();
90
91 fSaveCount = b.fSaveCount;
92 SkDeque::F2BIter recIter(b.fDeque);
93 for (const Rec* rec = (const Rec*)recIter.next();
94 rec != NULL;
95 rec = (const Rec*)recIter.next()) {
96 new (fDeque.push_back()) Rec(*rec);
97 }
98
99 return *this;
100 }
101
operator ==(const SkClipStack & b) const102 bool SkClipStack::operator==(const SkClipStack& b) const {
103 if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) {
104 return false;
105 }
106 SkDeque::F2BIter myIter(fDeque);
107 SkDeque::F2BIter bIter(b.fDeque);
108 const Rec* myRec = (const Rec*)myIter.next();
109 const Rec* bRec = (const Rec*)bIter.next();
110
111 while (myRec != NULL && bRec != NULL) {
112 if (*myRec != *bRec) {
113 return false;
114 }
115 myRec = (const Rec*)myIter.next();
116 bRec = (const Rec*)bIter.next();
117 }
118 return myRec == NULL && bRec == NULL;
119 }
120
reset()121 void SkClipStack::reset() {
122 // don't have a reset() on SkDeque, so fake it here
123 fDeque.~SkDeque();
124 new (&fDeque) SkDeque(sizeof(Rec));
125
126 fSaveCount = 0;
127 }
128
save()129 void SkClipStack::save() {
130 fSaveCount += 1;
131 }
132
restore()133 void SkClipStack::restore() {
134 fSaveCount -= 1;
135 while (!fDeque.empty()) {
136 Rec* rec = (Rec*)fDeque.back();
137 if (rec->fSaveCount <= fSaveCount) {
138 break;
139 }
140 rec->~Rec();
141 fDeque.pop_back();
142 }
143 }
144
clipDevRect(const SkRect & rect,SkRegion::Op op,bool doAA)145 void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
146 Rec* rec = (Rec*)fDeque.back();
147 if (rec && rec->canBeIntersected(fSaveCount, op)) {
148 switch (rec->fState) {
149 case Rec::kEmpty_State:
150 return;
151 case Rec::kRect_State:
152 if (!rec->fRect.intersect(rect)) {
153 rec->fState = Rec::kEmpty_State;
154 }
155 return;
156 case Rec::kPath_State:
157 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
158 rec->fState = Rec::kEmpty_State;
159 return;
160 }
161 break;
162 }
163 }
164 new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
165 }
166
clipDevPath(const SkPath & path,SkRegion::Op op,bool doAA)167 void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
168 Rec* rec = (Rec*)fDeque.back();
169 if (rec && rec->canBeIntersected(fSaveCount, op)) {
170 const SkRect& pathBounds = path.getBounds();
171 switch (rec->fState) {
172 case Rec::kEmpty_State:
173 return;
174 case Rec::kRect_State:
175 if (!SkRect::Intersects(rec->fRect, pathBounds)) {
176 rec->fState = Rec::kEmpty_State;
177 return;
178 }
179 break;
180 case Rec::kPath_State:
181 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
182 rec->fState = Rec::kEmpty_State;
183 return;
184 }
185 break;
186 }
187 }
188 new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
189 }
190
191 ///////////////////////////////////////////////////////////////////////////////
192
B2FIter()193 SkClipStack::B2FIter::B2FIter() {
194 }
195
operator ==(const SkClipStack::B2FIter::Clip & a,const SkClipStack::B2FIter::Clip & b)196 bool operator==(const SkClipStack::B2FIter::Clip& a,
197 const SkClipStack::B2FIter::Clip& b) {
198 return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
199 ((a.fRect == NULL && b.fRect == NULL) ||
200 (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
201 ((a.fPath == NULL && b.fPath == NULL) ||
202 (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath));
203 }
204
operator !=(const SkClipStack::B2FIter::Clip & a,const SkClipStack::B2FIter::Clip & b)205 bool operator!=(const SkClipStack::B2FIter::Clip& a,
206 const SkClipStack::B2FIter::Clip& b) {
207 return !(a == b);
208 }
209
B2FIter(const SkClipStack & stack)210 SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
211 this->reset(stack);
212 }
213
next()214 const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
215 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
216 if (NULL == rec) {
217 return NULL;
218 }
219
220 switch (rec->fState) {
221 case SkClipStack::Rec::kEmpty_State:
222 fClip.fRect = NULL;
223 fClip.fPath = NULL;
224 break;
225 case SkClipStack::Rec::kRect_State:
226 fClip.fRect = &rec->fRect;
227 fClip.fPath = NULL;
228 break;
229 case SkClipStack::Rec::kPath_State:
230 fClip.fRect = NULL;
231 fClip.fPath = &rec->fPath;
232 break;
233 }
234 fClip.fOp = rec->fOp;
235 fClip.fDoAA = rec->fDoAA;
236 return &fClip;
237 }
238
reset(const SkClipStack & stack)239 void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
240 fIter.reset(stack.fDeque);
241 }
242