blob: 567fd7e32741c3424e8b96419f83e0d047d87a5f [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
bsalomon@google.comd302f142011-03-03 13:54:13 +0000205SkClipStack::B2FIter::B2FIter() {
206}
207
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000208bool operator==(const SkClipStack::B2FIter::Clip& a,
209 const SkClipStack::B2FIter::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
vandebo@chromium.org8887ede2011-05-25 01:27:52 +0000217bool operator!=(const SkClipStack::B2FIter::Clip& a,
218 const SkClipStack::B2FIter::Clip& b) {
219 return !(a == b);
220}
221
bsalomon@google.comd302f142011-03-03 13:54:13 +0000222SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
223 this->reset(stack);
reed@google.com5c3d1472011-02-22 19:12:23 +0000224}
225
226const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
227 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
228 if (NULL == rec) {
229 return NULL;
230 }
231
232 switch (rec->fState) {
233 case SkClipStack::Rec::kEmpty_State:
234 fClip.fRect = NULL;
235 fClip.fPath = NULL;
236 break;
237 case SkClipStack::Rec::kRect_State:
238 fClip.fRect = &rec->fRect;
239 fClip.fPath = NULL;
240 break;
241 case SkClipStack::Rec::kPath_State:
242 fClip.fRect = NULL;
243 fClip.fPath = &rec->fPath;
244 break;
245 }
246 fClip.fOp = rec->fOp;
reed@google.com00177082011-10-12 14:34:30 +0000247 fClip.fDoAA = rec->fDoAA;
reed@google.com5c3d1472011-02-22 19:12:23 +0000248 return &fClip;
249}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000250
251void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
252 fIter.reset(stack.fDeque);
253}