|
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 |
|
11 SkRasterClip::SkRasterClip() { |
|
12 fIsBW = true; |
|
13 fIsEmpty = true; |
|
14 fIsRect = false; |
|
15 SkDEBUGCODE(this->validate();) |
|
16 } |
|
17 |
|
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 |
|
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 |
|
40 SkRasterClip::~SkRasterClip() { |
|
41 SkDEBUGCODE(this->validate();) |
|
42 } |
|
43 |
|
44 bool SkRasterClip::isComplex() const { |
|
45 return fIsBW ? fBW.isComplex() : !fAA.isEmpty(); |
|
46 } |
|
47 |
|
48 const SkIRect& SkRasterClip::getBounds() const { |
|
49 return fIsBW ? fBW.getBounds() : fAA.getBounds(); |
|
50 } |
|
51 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 */ |
|
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 |
|
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 |
|
177 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 |
|
204 bool SkRasterClip::quickContains(const SkIRect& ir) const { |
|
205 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir); |
|
206 } |
|
207 |
|
208 /////////////////////////////////////////////////////////////////////////////// |
|
209 |
|
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 |
|
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 |
|
229 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 |
|
245 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() { |
|
246 SkDEBUGCODE(fClipRgn = NULL;) |
|
247 SkDEBUGCODE(fBlitter = NULL;) |
|
248 } |
|
249 |
|
250 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip, |
|
251 SkBlitter* blitter) { |
|
252 this->init(clip, blitter); |
|
253 } |
|
254 |
|
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 |
|
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 } |