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::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
102bool 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
121void 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
129void SkClipStack::save() {
130    fSaveCount += 1;
131}
132
133void 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
145void 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
167void 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
193SkClipStack::B2FIter::B2FIter() {
194}
195
196bool 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
205bool operator!=(const SkClipStack::B2FIter::Clip& a,
206               const SkClipStack::B2FIter::Clip& b) {
207    return !(a == b);
208}
209
210SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
211    this->reset(stack);
212}
213
214const 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
239void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
240    fIter.reset(stack.fDeque);
241}
242