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