1 | /* |
2 | * Copyright 2017 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef SkRasterClipStack_DEFINED |
9 | #define SkRasterClipStack_DEFINED |
10 | |
11 | #include "include/core/SkClipOp.h" |
12 | #include "include/private/SkDeque.h" |
13 | #include "src/core/SkRasterClip.h" |
14 | #include <new> |
15 | |
16 | template <typename T> class SkTStack { |
17 | public: |
18 | SkTStack(void* storage, size_t size) : fDeque(sizeof(T), storage, size), fTop(nullptr) {} |
19 | ~SkTStack() { |
20 | while (!fDeque.empty()) { |
21 | ((T*)fDeque.back())->~T(); |
22 | fDeque.pop_back(); |
23 | } |
24 | } |
25 | |
26 | bool empty() const { return fDeque.empty(); } |
27 | |
28 | int count() const { return fDeque.count(); } |
29 | |
30 | const T& top() const { |
31 | SkASSERT(fTop); |
32 | return *fTop; |
33 | } |
34 | |
35 | T& top() { |
36 | SkASSERT(fTop); |
37 | return *fTop; |
38 | } |
39 | |
40 | T* push_raw() { return (T*)fDeque.push_back(); } |
41 | T& push() { |
42 | fTop = this->push_raw(); |
43 | new (fTop) T(); |
44 | return *fTop; |
45 | } |
46 | T& push(const T& src) { |
47 | fTop = this->push_raw(); |
48 | new (fTop) T(src); |
49 | return *fTop; |
50 | } |
51 | |
52 | void pop() { |
53 | fTop->~T(); |
54 | fDeque.pop_back(); |
55 | fTop = fDeque.empty() ? nullptr : (T*)fDeque.back(); |
56 | } |
57 | |
58 | private: |
59 | SkDeque fDeque; |
60 | T* fTop; |
61 | }; |
62 | |
63 | class SkRasterClipStack : SkNoncopyable { |
64 | int fCounter = 0; |
65 | public: |
66 | SkRasterClipStack(int width, int height) |
67 | : fStack(fStorage, sizeof(fStorage)) |
68 | , fRootBounds(SkIRect::MakeWH(width, height)) |
69 | { |
70 | Rec& rec = fStack.push(); |
71 | rec.fRC.setRect(fRootBounds); |
72 | rec.fDeferredCount = 0; |
73 | SkASSERT(fStack.count() == 1); |
74 | } |
75 | |
76 | void setNewSize(int w, int h) { |
77 | fRootBounds.setXYWH(0, 0, w, h); |
78 | |
79 | SkASSERT(fStack.count() == 1); |
80 | Rec& rec = fStack.top(); |
81 | SkASSERT(rec.fDeferredCount == 0); |
82 | rec.fRC.setRect(fRootBounds); |
83 | } |
84 | |
85 | const SkRasterClip& rc() const { return fStack.top().fRC; } |
86 | |
87 | void save() { |
88 | fCounter += 1; |
89 | SkASSERT(fStack.top().fDeferredCount >= 0); |
90 | fStack.top().fDeferredCount += 1; |
91 | } |
92 | |
93 | void restore() { |
94 | fCounter -= 1; SkASSERT(fCounter >= 0); |
95 | if (--fStack.top().fDeferredCount < 0) { |
96 | SkASSERT(fStack.top().fDeferredCount == -1); |
97 | SkASSERT(fStack.count() > 1); |
98 | fStack.pop(); |
99 | } |
100 | } |
101 | |
102 | void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) { |
103 | this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, aa); |
104 | this->trimIfExpanding(op); |
105 | this->validate(); |
106 | } |
107 | |
108 | void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) { |
109 | this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, aa); |
110 | this->trimIfExpanding(op); |
111 | this->validate(); |
112 | } |
113 | |
114 | void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) { |
115 | this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, aa); |
116 | this->trimIfExpanding(op); |
117 | this->validate(); |
118 | } |
119 | |
120 | void clipShader(sk_sp<SkShader> sh) { |
121 | this->writable_rc().op(std::move(sh)); |
122 | this->validate(); |
123 | } |
124 | |
125 | void clipRegion(const SkRegion& rgn, SkClipOp op) { |
126 | this->writable_rc().op(rgn, (SkRegion::Op)op); |
127 | this->trimIfExpanding(op); |
128 | this->validate(); |
129 | } |
130 | |
131 | void setDeviceClipRestriction(SkIRect* mutableClipRestriction) { |
132 | this->writable_rc().setDeviceClipRestriction(mutableClipRestriction); |
133 | } |
134 | |
135 | void validate() const { |
136 | #ifdef SK_DEBUG |
137 | const SkRasterClip& clip = this->rc(); |
138 | if (fRootBounds.isEmpty()) { |
139 | SkASSERT(clip.isEmpty()); |
140 | } else if (!clip.isEmpty()) { |
141 | SkASSERT(fRootBounds.contains(clip.getBounds())); |
142 | } |
143 | #endif |
144 | } |
145 | |
146 | private: |
147 | struct Rec { |
148 | SkRasterClip fRC; |
149 | int fDeferredCount; // 0 for a "normal" entry |
150 | }; |
151 | |
152 | enum { |
153 | ELEM_COUNT = 16, |
154 | PTR_COUNT = ELEM_COUNT * sizeof(Rec) / sizeof(void*) |
155 | }; |
156 | void* fStorage[PTR_COUNT]; |
157 | SkTStack<Rec> fStack; |
158 | SkIRect fRootBounds; |
159 | |
160 | SkRasterClip& writable_rc() { |
161 | SkASSERT(fStack.top().fDeferredCount >= 0); |
162 | if (fStack.top().fDeferredCount > 0) { |
163 | fStack.top().fDeferredCount -= 1; |
164 | fStack.push(fStack.top()); |
165 | fStack.top().fDeferredCount = 0; |
166 | } |
167 | return fStack.top().fRC; |
168 | } |
169 | |
170 | void trimIfExpanding(SkClipOp op) { |
171 | if ((int)op > (int)SkClipOp::kIntersect) { |
172 | Rec& rec = fStack.top(); |
173 | SkASSERT(rec.fDeferredCount == 0); |
174 | rec.fRC.op(fRootBounds, SkRegion::kIntersect_Op); |
175 | } |
176 | } |
177 | }; |
178 | |
179 | #endif |
180 | |