blob: 2b63aea9a002e87d3d3617fb828f87c98d0c940f [file] [log] [blame]
reed@google.com5c3d1472011-02-22 19:12:23 +00001#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}