SkClipStack.cpp revision 5836b6dec5563e6273099fcf23984dd3818a168f
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
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    bool            fDoAA;
25
26    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
33    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
41    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
57    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     */
65    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
77SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
78    fSaveCount = 0;
79}
80
81SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
82    *this = b;
83}
84
85SkClipStack::~SkClipStack() {
86    reset();
87}
88
89SkClipStack& 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
125void SkClipStack::reset() {
126    // 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    }
133
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
153void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
154    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    }
172    new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
173}
174
175void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
176    SkRect alt;
177    if (path.isRect(&alt)) {
178        return this->clipDevRect(alt, op, doAA);
179    }
180    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    }
200    new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
201}
202
203///////////////////////////////////////////////////////////////////////////////
204
205SkClipStack::Iter::Iter() : fStack(NULL) {
206}
207
208bool operator==(const SkClipStack::Iter::Clip& a,
209                const SkClipStack::Iter::Clip& b) {
210    return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
211           ((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));
215}
216
217bool operator!=(const SkClipStack::Iter::Clip& a,
218                const SkClipStack::Iter::Clip& b) {
219    return !(a == b);
220}
221
222SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc)
223    : fStack(&stack) {
224    this->reset(stack, startLoc);
225}
226
227const SkClipStack::Iter::Clip* SkClipStack::Iter::updateClip(
228                        const SkClipStack::Rec* rec) {
229    switch (rec->fState) {
230        case SkClipStack::Rec::kEmpty_State:
231            fClip.fRect = NULL;
232            fClip.fPath = NULL;
233            break;
234        case SkClipStack::Rec::kRect_State:
235            fClip.fRect = &rec->fRect;
236            fClip.fPath = NULL;
237            break;
238        case SkClipStack::Rec::kPath_State:
239            fClip.fRect = NULL;
240            fClip.fPath = &rec->fPath;
241            break;
242    }
243    fClip.fOp = rec->fOp;
244    fClip.fDoAA = rec->fDoAA;
245    return &fClip;
246}
247
248const SkClipStack::Iter::Clip* SkClipStack::Iter::next() {
249    const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
250    if (NULL == rec) {
251        return NULL;
252    }
253
254    return this->updateClip(rec);
255}
256
257const SkClipStack::Iter::Clip* SkClipStack::Iter::prev() {
258    const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.prev();
259    if (NULL == rec) {
260        return NULL;
261    }
262
263    return this->updateClip(rec);
264}
265
266const SkClipStack::Iter::Clip* SkClipStack::Iter::skipToLast(SkRegion::Op op) {
267
268    if (NULL == fStack) {
269        return NULL;
270    }
271
272    fIter.reset(fStack->fDeque, SkDeque::Iter::kBack_IterStart);
273
274    const SkClipStack::Rec* rec = NULL;
275
276    for (rec = (const SkClipStack::Rec*) fIter.prev();
277         NULL != rec;
278         rec = (const SkClipStack::Rec*) fIter.prev()) {
279
280        if (op == rec->fOp) {
281            // The Deque's iterator is actually one pace ahead of the
282            // returned value. So while "rec" is the element we want to
283            // return, the iterator is actually pointing at (and will
284            // return on the next "next" or "prev" call) the element
285            // in front of it in the deque. Bump the iterator forward a
286            // step so we get the expected result.
287            if (NULL == fIter.next()) {
288                // The reverse iterator has run off the front of the deque
289                // (i.e., the "op" clip is the first clip) and can't
290                // recover. Reset the iterator to start at the front.
291                fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart);
292            }
293            break;
294        }
295    }
296
297    if (NULL == rec) {
298        // There were no "op" clips
299        fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart);
300    }
301
302    return this->next();
303}
304
305void SkClipStack::Iter::reset(const SkClipStack& stack, IterStart startLoc) {
306    fIter.reset(stack.fDeque, static_cast<SkDeque::Iter::IterStart>(startLoc));
307}
308