blob: 9b7538fbec90a5839647c9f3b36feac92440afe3 [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;
24
25 Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
26 fSaveCount = saveCount;
27 fOp = op;
28 fState = kRect_State;
29 }
30
31 Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
vandebo@chromium.orge1bc2742011-06-21 22:26:39 +000032 fRect.setEmpty();
reed@google.com5c3d1472011-02-22 19:12:23 +000033 fSaveCount = saveCount;
34 fOp = op;
35 fState = kPath_State;
36 }
37
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000038 bool operator==(const Rec& b) const {
39 if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) {
40 return false;
41 }
42 switch (fState) {
43 case kEmpty_State:
44 return true;
45 case kRect_State:
46 return fRect == b.fRect;
47 case kPath_State:
48 return fPath == b.fPath;
49 }
50 return false; // Silence the compiler.
51 }
52
53 bool operator!=(const Rec& b) const {
54 return !(*this == b);
55 }
56
57
reed@google.com5c3d1472011-02-22 19:12:23 +000058 /**
59 * Returns true if this Rec can be intersected in place with a new clip
60 */
61 bool canBeIntersected(int saveCount, SkRegion::Op op) const {
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000062 if (kEmpty_State == fState && (
63 SkRegion::kDifference_Op == op ||
64 SkRegion::kIntersect_Op == op)) {
reed@google.com5c3d1472011-02-22 19:12:23 +000065 return true;
66 }
67 return fSaveCount == saveCount &&
68 SkRegion::kIntersect_Op == fOp &&
69 SkRegion::kIntersect_Op == op;
70 }
71};
72
73SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
74 fSaveCount = 0;
75}
76
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000077SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
78 *this = b;
79}
80
81SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
82 if (this == &b) {
83 return *this;
84 }
85 reset();
86
87 fSaveCount = b.fSaveCount;
88 SkDeque::F2BIter recIter(b.fDeque);
89 for (const Rec* rec = (const Rec*)recIter.next();
90 rec != NULL;
91 rec = (const Rec*)recIter.next()) {
92 new (fDeque.push_back()) Rec(*rec);
93 }
94
95 return *this;
96}
97
98bool SkClipStack::operator==(const SkClipStack& b) const {
99 if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) {
100 return false;
101 }
102 SkDeque::F2BIter myIter(fDeque);
103 SkDeque::F2BIter bIter(b.fDeque);
104 const Rec* myRec = (const Rec*)myIter.next();
105 const Rec* bRec = (const Rec*)bIter.next();
106
107 while (myRec != NULL && bRec != NULL) {
108 if (*myRec != *bRec) {
109 return false;
110 }
111 myRec = (const Rec*)myIter.next();
112 bRec = (const Rec*)bIter.next();
113 }
114 return myRec == NULL && bRec == NULL;
115}
116
reed@google.com5c3d1472011-02-22 19:12:23 +0000117void SkClipStack::reset() {
118 // don't have a reset() on SkDeque, so fake it here
119 fDeque.~SkDeque();
120 new (&fDeque) SkDeque(sizeof(Rec));
121
122 fSaveCount = 0;
123}
124
125void SkClipStack::save() {
126 fSaveCount += 1;
127}
128
129void SkClipStack::restore() {
130 fSaveCount -= 1;
131 while (!fDeque.empty()) {
132 Rec* rec = (Rec*)fDeque.back();
133 if (rec->fSaveCount <= fSaveCount) {
134 break;
135 }
136 rec->~Rec();
137 fDeque.pop_back();
138 }
139}
140
141void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
142 Rec* rec = (Rec*)fDeque.back();
143 if (rec && rec->canBeIntersected(fSaveCount, op)) {
144 switch (rec->fState) {
145 case Rec::kEmpty_State:
146 return;
147 case Rec::kRect_State:
148 if (!rec->fRect.intersect(rect)) {
149 rec->fState = Rec::kEmpty_State;
150 }
151 return;
152 case Rec::kPath_State:
153 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
154 rec->fState = Rec::kEmpty_State;
155 return;
156 }
157 break;
158 }
159 }
160 new (fDeque.push_back()) Rec(fSaveCount, rect, op);
161}
162
163void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
164 Rec* rec = (Rec*)fDeque.back();
165 if (rec && rec->canBeIntersected(fSaveCount, op)) {
166 const SkRect& pathBounds = path.getBounds();
167 switch (rec->fState) {
168 case Rec::kEmpty_State:
169 return;
170 case Rec::kRect_State:
171 if (!SkRect::Intersects(rec->fRect, pathBounds)) {
172 rec->fState = Rec::kEmpty_State;
173 return;
174 }
175 break;
176 case Rec::kPath_State:
177 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
178 rec->fState = Rec::kEmpty_State;
179 return;
180 }
181 break;
182 }
183 }
184 new (fDeque.push_back()) Rec(fSaveCount, path, op);
185}
186
187///////////////////////////////////////////////////////////////////////////////
188
bsalomon@google.comd302f142011-03-03 13:54:13 +0000189SkClipStack::B2FIter::B2FIter() {
190}
191
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000192bool operator==(const SkClipStack::B2FIter::Clip& a,
193 const SkClipStack::B2FIter::Clip& b) {
194 return a.fOp == b.fOp &&
vandebo@chromium.orge03c6522011-06-21 20:45:51 +0000195 ((a.fRect == NULL && b.fRect == NULL) ||
196 (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
197 ((a.fPath == NULL && b.fPath == NULL) ||
198 (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath));
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000199}
200
vandebo@chromium.org8887ede2011-05-25 01:27:52 +0000201bool operator!=(const SkClipStack::B2FIter::Clip& a,
202 const SkClipStack::B2FIter::Clip& b) {
203 return !(a == b);
204}
205
bsalomon@google.comd302f142011-03-03 13:54:13 +0000206SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
207 this->reset(stack);
reed@google.com5c3d1472011-02-22 19:12:23 +0000208}
209
210const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
211 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
212 if (NULL == rec) {
213 return NULL;
214 }
215
216 switch (rec->fState) {
217 case SkClipStack::Rec::kEmpty_State:
218 fClip.fRect = NULL;
219 fClip.fPath = NULL;
220 break;
221 case SkClipStack::Rec::kRect_State:
222 fClip.fRect = &rec->fRect;
223 fClip.fPath = NULL;
224 break;
225 case SkClipStack::Rec::kPath_State:
226 fClip.fRect = NULL;
227 fClip.fPath = &rec->fPath;
228 break;
229 }
230 fClip.fOp = rec->fOp;
231 return &fClip;
232}
bsalomon@google.comd302f142011-03-03 13:54:13 +0000233
234void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
235 fIter.reset(stack.fDeque);
236}