SkClipStack.cpp revision 5c3d1471e4908706cd053a5e2ea9ded3a6c2eaeb
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    /**
31     *  Returns true if this Rec can be intersected in place with a new clip
32     */
33    bool canBeIntersected(int saveCount, SkRegion::Op op) const {
34        if (kEmpty_State == fState) {
35            return true;
36        }
37        return  fSaveCount == saveCount &&
38                SkRegion::kIntersect_Op == fOp &&
39                SkRegion::kIntersect_Op == op;
40    }
41};
42
43SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
44    fSaveCount = 0;
45}
46
47void SkClipStack::reset() {
48    // don't have a reset() on SkDeque, so fake it here
49    fDeque.~SkDeque();
50    new (&fDeque) SkDeque(sizeof(Rec));
51
52    fSaveCount = 0;
53}
54
55void SkClipStack::save() {
56    fSaveCount += 1;
57}
58
59void SkClipStack::restore() {
60    fSaveCount -= 1;
61    while (!fDeque.empty()) {
62        Rec* rec = (Rec*)fDeque.back();
63        if (rec->fSaveCount <= fSaveCount) {
64            break;
65        }
66        rec->~Rec();
67        fDeque.pop_back();
68    }
69}
70
71void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
72    Rec* rec = (Rec*)fDeque.back();
73    if (rec && rec->canBeIntersected(fSaveCount, op)) {
74        switch (rec->fState) {
75            case Rec::kEmpty_State:
76                return;
77            case Rec::kRect_State:
78                if (!rec->fRect.intersect(rect)) {
79                    rec->fState = Rec::kEmpty_State;
80                }
81                return;
82            case Rec::kPath_State:
83                if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
84                    rec->fState = Rec::kEmpty_State;
85                    return;
86                }
87                break;
88        }
89    }
90    new (fDeque.push_back()) Rec(fSaveCount, rect, op);
91}
92
93void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
94    Rec* rec = (Rec*)fDeque.back();
95    if (rec && rec->canBeIntersected(fSaveCount, op)) {
96        const SkRect& pathBounds = path.getBounds();
97        switch (rec->fState) {
98            case Rec::kEmpty_State:
99                return;
100            case Rec::kRect_State:
101                if (!SkRect::Intersects(rec->fRect, pathBounds)) {
102                    rec->fState = Rec::kEmpty_State;
103                    return;
104                }
105                break;
106            case Rec::kPath_State:
107                if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
108                    rec->fState = Rec::kEmpty_State;
109                    return;
110                }
111                break;
112        }
113    }
114    new (fDeque.push_back()) Rec(fSaveCount, path, op);
115}
116
117///////////////////////////////////////////////////////////////////////////////
118
119SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) : fIter(stack.fDeque) {
120}
121
122const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
123    const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
124    if (NULL == rec) {
125        return NULL;
126    }
127
128    switch (rec->fState) {
129        case SkClipStack::Rec::kEmpty_State:
130            fClip.fRect = NULL;
131            fClip.fPath = NULL;
132            break;
133        case SkClipStack::Rec::kRect_State:
134            fClip.fRect = &rec->fRect;
135            fClip.fPath = NULL;
136            break;
137        case SkClipStack::Rec::kPath_State:
138            fClip.fRect = NULL;
139            fClip.fPath = &rec->fPath;
140            break;
141    }
142    fClip.fOp = rec->fOp;
143    return &fClip;
144}
145