• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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