1 /*
2 * Copyright 2010 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 #include "SkRasterClip.h"
9
10
SkRasterClip()11 SkRasterClip::SkRasterClip() {
12 fIsBW = true;
13 fIsEmpty = true;
14 fIsRect = false;
15 SkDEBUGCODE(this->validate();)
16 }
17
SkRasterClip(const SkRasterClip & src)18 SkRasterClip::SkRasterClip(const SkRasterClip& src) {
19 AUTO_RASTERCLIP_VALIDATE(src);
20
21 fIsBW = src.fIsBW;
22 if (fIsBW) {
23 fBW = src.fBW;
24 } else {
25 fAA = src.fAA;
26 }
27
28 fIsEmpty = src.isEmpty();
29 fIsRect = src.isRect();
30 SkDEBUGCODE(this->validate();)
31 }
32
SkRasterClip(const SkIRect & bounds)33 SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
34 fIsBW = true;
35 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
36 fIsRect = !fIsEmpty;
37 SkDEBUGCODE(this->validate();)
38 }
39
~SkRasterClip()40 SkRasterClip::~SkRasterClip() {
41 SkDEBUGCODE(this->validate();)
42 }
43
isComplex() const44 bool SkRasterClip::isComplex() const {
45 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
46 }
47
getBounds() const48 const SkIRect& SkRasterClip::getBounds() const {
49 return fIsBW ? fBW.getBounds() : fAA.getBounds();
50 }
51
setEmpty()52 bool SkRasterClip::setEmpty() {
53 AUTO_RASTERCLIP_VALIDATE(*this);
54
55 fIsBW = true;
56 fBW.setEmpty();
57 fAA.setEmpty();
58 fIsEmpty = true;
59 fIsRect = false;
60 return false;
61 }
62
setRect(const SkIRect & rect)63 bool SkRasterClip::setRect(const SkIRect& rect) {
64 AUTO_RASTERCLIP_VALIDATE(*this);
65
66 fIsBW = true;
67 fAA.setEmpty();
68 fIsRect = fBW.setRect(rect);
69 fIsEmpty = !fIsRect;
70 return fIsRect;
71 }
72
setPath(const SkPath & path,const SkRegion & clip,bool doAA)73 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
74 AUTO_RASTERCLIP_VALIDATE(*this);
75
76 if (this->isBW() && !doAA) {
77 (void)fBW.setPath(path, clip);
78 } else {
79 // TODO: since we are going to over-write fAA completely (aren't we?)
80 // we should just clear our BW data (if any) and set fIsAA=true
81 if (this->isBW()) {
82 this->convertToAA();
83 }
84 (void)fAA.setPath(path, &clip, doAA);
85 }
86 return this->updateCacheAndReturnNonEmpty();
87 }
88
setPath(const SkPath & path,const SkIRect & clip,bool doAA)89 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
90 SkRegion tmp;
91 tmp.setRect(clip);
92 return this->setPath(path, tmp, doAA);
93 }
94
op(const SkIRect & rect,SkRegion::Op op)95 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
96 AUTO_RASTERCLIP_VALIDATE(*this);
97
98 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
99 return this->updateCacheAndReturnNonEmpty();
100 }
101
op(const SkRegion & rgn,SkRegion::Op op)102 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
103 AUTO_RASTERCLIP_VALIDATE(*this);
104
105 if (fIsBW) {
106 (void)fBW.op(rgn, op);
107 } else {
108 SkAAClip tmp;
109 tmp.setRegion(rgn);
110 (void)fAA.op(tmp, op);
111 }
112 return this->updateCacheAndReturnNonEmpty();
113 }
114
op(const SkRasterClip & clip,SkRegion::Op op)115 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
116 AUTO_RASTERCLIP_VALIDATE(*this);
117 clip.validate();
118
119 if (this->isBW() && clip.isBW()) {
120 (void)fBW.op(clip.fBW, op);
121 } else {
122 SkAAClip tmp;
123 const SkAAClip* other;
124
125 if (this->isBW()) {
126 this->convertToAA();
127 }
128 if (clip.isBW()) {
129 tmp.setRegion(clip.bwRgn());
130 other = &tmp;
131 } else {
132 other = &clip.aaRgn();
133 }
134 (void)fAA.op(*other, op);
135 }
136 return this->updateCacheAndReturnNonEmpty();
137 }
138
139 /**
140 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
141 * axis. Thus we can treat an axis coordinate as an integer if it differs
142 * from its nearest int by < half of that value (1.8 in this case).
143 */
nearly_integral(SkScalar x)144 static bool nearly_integral(SkScalar x) {
145 static const SkScalar domain = SK_Scalar1 / 4;
146 static const SkScalar halfDomain = domain / 2;
147
148 x += halfDomain;
149 return x - SkScalarFloorToScalar(x) < domain;
150 }
151
op(const SkRect & r,SkRegion::Op op,bool doAA)152 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
153 AUTO_RASTERCLIP_VALIDATE(*this);
154
155 if (fIsBW && doAA) {
156 // check that the rect really needs aa, or is it close enought to
157 // integer boundaries that we can just treat it as a BW rect?
158 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
159 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
160 doAA = false;
161 }
162 }
163
164 if (fIsBW && !doAA) {
165 SkIRect ir;
166 r.round(&ir);
167 (void)fBW.op(ir, op);
168 } else {
169 if (fIsBW) {
170 this->convertToAA();
171 }
172 (void)fAA.op(r, op, doAA);
173 }
174 return this->updateCacheAndReturnNonEmpty();
175 }
176
translate(int dx,int dy,SkRasterClip * dst) const177 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
178 if (NULL == dst) {
179 return;
180 }
181
182 AUTO_RASTERCLIP_VALIDATE(*this);
183
184 if (this->isEmpty()) {
185 dst->setEmpty();
186 return;
187 }
188 if (0 == (dx | dy)) {
189 *dst = *this;
190 return;
191 }
192
193 dst->fIsBW = fIsBW;
194 if (fIsBW) {
195 fBW.translate(dx, dy, &dst->fBW);
196 dst->fAA.setEmpty();
197 } else {
198 fAA.translate(dx, dy, &dst->fAA);
199 dst->fBW.setEmpty();
200 }
201 dst->updateCacheAndReturnNonEmpty();
202 }
203
quickContains(const SkIRect & ir) const204 bool SkRasterClip::quickContains(const SkIRect& ir) const {
205 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
206 }
207
208 ///////////////////////////////////////////////////////////////////////////////
209
forceGetBW()210 const SkRegion& SkRasterClip::forceGetBW() {
211 AUTO_RASTERCLIP_VALIDATE(*this);
212
213 if (!fIsBW) {
214 fBW.setRect(fAA.getBounds());
215 }
216 return fBW;
217 }
218
convertToAA()219 void SkRasterClip::convertToAA() {
220 AUTO_RASTERCLIP_VALIDATE(*this);
221
222 SkASSERT(fIsBW);
223 fAA.setRegion(fBW);
224 fIsBW = false;
225 (void)this->updateCacheAndReturnNonEmpty();
226 }
227
228 #ifdef SK_DEBUG
validate() const229 void SkRasterClip::validate() const {
230 // can't ever assert that fBW is empty, since we may have called forceGetBW
231 if (fIsBW) {
232 SkASSERT(fAA.isEmpty());
233 }
234
235 fBW.validate();
236 fAA.validate();
237
238 SkASSERT(this->computeIsEmpty() == fIsEmpty);
239 SkASSERT(this->computeIsRect() == fIsRect);
240 }
241 #endif
242
243 ///////////////////////////////////////////////////////////////////////////////
244
SkAAClipBlitterWrapper()245 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
246 SkDEBUGCODE(fClipRgn = NULL;)
247 SkDEBUGCODE(fBlitter = NULL;)
248 }
249
SkAAClipBlitterWrapper(const SkRasterClip & clip,SkBlitter * blitter)250 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
251 SkBlitter* blitter) {
252 this->init(clip, blitter);
253 }
254
SkAAClipBlitterWrapper(const SkAAClip * aaclip,SkBlitter * blitter)255 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
256 SkBlitter* blitter) {
257 SkASSERT(blitter);
258 SkASSERT(aaclip);
259 fBWRgn.setRect(aaclip->getBounds());
260 fAABlitter.init(blitter, aaclip);
261 // now our return values
262 fClipRgn = &fBWRgn;
263 fBlitter = &fAABlitter;
264 }
265
init(const SkRasterClip & clip,SkBlitter * blitter)266 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
267 SkASSERT(blitter);
268 if (clip.isBW()) {
269 fClipRgn = &clip.bwRgn();
270 fBlitter = blitter;
271 } else {
272 const SkAAClip& aaclip = clip.aaRgn();
273 fBWRgn.setRect(aaclip.getBounds());
274 fAABlitter.init(blitter, &aaclip);
275 // now our return values
276 fClipRgn = &fBWRgn;
277 fBlitter = &fAABlitter;
278 }
279 }
280