OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2010 Google Inc. | 2 * Copyright 2010 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkRasterClip.h" | 8 #include "SkRasterClip.h" |
9 #include "SkPath.h" | 9 |
| 10 |
| 11 SkRasterClip::SkRasterClip() { |
| 12 fIsBW = true; |
| 13 fIsEmpty = true; |
| 14 fIsRect = false; |
| 15 SkDEBUGCODE(this->validate();) |
| 16 } |
10 | 17 |
11 SkRasterClip::SkRasterClip(const SkRasterClip& src) { | 18 SkRasterClip::SkRasterClip(const SkRasterClip& src) { |
12 AUTO_RASTERCLIP_VALIDATE(src); | 19 AUTO_RASTERCLIP_VALIDATE(src); |
13 | 20 |
14 fForceConservativeRects = src.fForceConservativeRects; | |
15 fIsBW = src.fIsBW; | 21 fIsBW = src.fIsBW; |
16 if (fIsBW) { | 22 if (fIsBW) { |
17 fBW = src.fBW; | 23 fBW = src.fBW; |
18 } else { | 24 } else { |
19 fAA = src.fAA; | 25 fAA = src.fAA; |
20 } | 26 } |
21 | 27 |
22 fIsEmpty = src.isEmpty(); | 28 fIsEmpty = src.isEmpty(); |
23 fIsRect = src.isRect(); | 29 fIsRect = src.isRect(); |
24 SkDEBUGCODE(this->validate();) | 30 SkDEBUGCODE(this->validate();) |
25 } | 31 } |
26 | 32 |
27 SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) :
fBW(bounds) { | 33 SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) { |
28 fForceConservativeRects = forceConservativeRects; | |
29 fIsBW = true; | 34 fIsBW = true; |
30 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute | 35 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute |
31 fIsRect = !fIsEmpty; | 36 fIsRect = !fIsEmpty; |
32 SkDEBUGCODE(this->validate();) | 37 SkDEBUGCODE(this->validate();) |
33 } | 38 } |
34 | 39 |
35 SkRasterClip::SkRasterClip(bool forceConservativeRects) { | |
36 fForceConservativeRects = forceConservativeRects; | |
37 fIsBW = true; | |
38 fIsEmpty = true; | |
39 fIsRect = false; | |
40 SkDEBUGCODE(this->validate();) | |
41 } | |
42 | |
43 SkRasterClip::~SkRasterClip() { | 40 SkRasterClip::~SkRasterClip() { |
44 SkDEBUGCODE(this->validate();) | 41 SkDEBUGCODE(this->validate();) |
45 } | 42 } |
46 | 43 |
47 bool SkRasterClip::isComplex() const { | 44 bool SkRasterClip::isComplex() const { |
48 return fIsBW ? fBW.isComplex() : !fAA.isEmpty(); | 45 return fIsBW ? fBW.isComplex() : !fAA.isEmpty(); |
49 } | 46 } |
50 | 47 |
51 const SkIRect& SkRasterClip::getBounds() const { | 48 const SkIRect& SkRasterClip::getBounds() const { |
52 return fIsBW ? fBW.getBounds() : fAA.getBounds(); | 49 return fIsBW ? fBW.getBounds() : fAA.getBounds(); |
(...skipping 13 matching lines...) Expand all Loading... |
66 bool SkRasterClip::setRect(const SkIRect& rect) { | 63 bool SkRasterClip::setRect(const SkIRect& rect) { |
67 AUTO_RASTERCLIP_VALIDATE(*this); | 64 AUTO_RASTERCLIP_VALIDATE(*this); |
68 | 65 |
69 fIsBW = true; | 66 fIsBW = true; |
70 fAA.setEmpty(); | 67 fAA.setEmpty(); |
71 fIsRect = fBW.setRect(rect); | 68 fIsRect = fBW.setRect(rect); |
72 fIsEmpty = !fIsRect; | 69 fIsEmpty = !fIsRect; |
73 return fIsRect; | 70 return fIsRect; |
74 } | 71 } |
75 | 72 |
76 ////////////////////////////////////////////////////////////////////////////////
///// | |
77 | |
78 bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bo
ol isInverse) { | |
79 SkIRect ir; | |
80 r.roundOut(&ir); | |
81 | |
82 SkRegion::Op op; | |
83 if (isInverse) { | |
84 op = SkRegion::kDifference_Op; | |
85 } else { | |
86 op = SkRegion::kIntersect_Op; | |
87 } | |
88 fBW.setRect(clipR); | |
89 fBW.op(ir, op); | |
90 return this->updateCacheAndReturnNonEmpty(); | |
91 } | |
92 | |
93 ////////////////////////////////////////////////////////////////////////////////
///// | |
94 | |
95 enum MutateResult { | |
96 kDoNothing_MutateResult, | |
97 kReplaceClippedAgainstGlobalBounds_MutateResult, | |
98 kContinue_MutateResult, | |
99 }; | |
100 | |
101 static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled)
{ | |
102 if (inverseFilled) { | |
103 switch (*op) { | |
104 case SkRegion::kIntersect_Op: | |
105 case SkRegion::kDifference_Op: | |
106 // These ops can only shrink the current clip. So leaving | |
107 // the clip unchanged conservatively respects the contract. | |
108 return kDoNothing_MutateResult; | |
109 case SkRegion::kUnion_Op: | |
110 case SkRegion::kReplace_Op: | |
111 case SkRegion::kReverseDifference_Op: | |
112 case SkRegion::kXOR_Op: { | |
113 // These ops can grow the current clip up to the extents of | |
114 // the input clip, which is inverse filled, so we just set | |
115 // the current clip to the device bounds. | |
116 *op = SkRegion::kReplace_Op; | |
117 return kReplaceClippedAgainstGlobalBounds_MutateResult; | |
118 } | |
119 } | |
120 } else { | |
121 // Not inverse filled | |
122 switch (*op) { | |
123 case SkRegion::kIntersect_Op: | |
124 case SkRegion::kUnion_Op: | |
125 case SkRegion::kReplace_Op: | |
126 return kContinue_MutateResult; | |
127 case SkRegion::kDifference_Op: | |
128 // Difference can only shrink the current clip. | |
129 // Leaving clip unchanged conservatively fullfills the contract. | |
130 return kDoNothing_MutateResult; | |
131 case SkRegion::kReverseDifference_Op: | |
132 // To reverse, we swap in the bounds with a replace op. | |
133 // As with difference, leave it unchanged. | |
134 *op = SkRegion::kReplace_Op; | |
135 return kContinue_MutateResult; | |
136 case SkRegion::kXOR_Op: | |
137 // Be conservative, based on (A XOR B) always included in (A uni
on B), | |
138 // which is always included in (bounds(A) union bounds(B)) | |
139 *op = SkRegion::kUnion_Op; | |
140 return kContinue_MutateResult; | |
141 } | |
142 } | |
143 SkFAIL("should not get here"); | |
144 return kDoNothing_MutateResult; | |
145 } | |
146 | |
147 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA)
{ | 73 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA)
{ |
148 AUTO_RASTERCLIP_VALIDATE(*this); | 74 AUTO_RASTERCLIP_VALIDATE(*this); |
149 | 75 |
150 if (fForceConservativeRects) { | |
151 return this->setConservativeRect(path.getBounds(), clip.getBounds(), pat
h.isInverseFillType()); | |
152 } | |
153 | |
154 if (this->isBW() && !doAA) { | 76 if (this->isBW() && !doAA) { |
155 (void)fBW.setPath(path, clip); | 77 (void)fBW.setPath(path, clip); |
156 } else { | 78 } else { |
157 // TODO: since we are going to over-write fAA completely (aren't we?) | 79 // TODO: since we are going to over-write fAA completely (aren't we?) |
158 // we should just clear our BW data (if any) and set fIsAA=true | 80 // we should just clear our BW data (if any) and set fIsAA=true |
159 if (this->isBW()) { | 81 if (this->isBW()) { |
160 this->convertToAA(); | 82 this->convertToAA(); |
161 } | 83 } |
162 (void)fAA.setPath(path, &clip, doAA); | 84 (void)fAA.setPath(path, &clip, doAA); |
163 } | 85 } |
164 return this->updateCacheAndReturnNonEmpty(); | 86 return this->updateCacheAndReturnNonEmpty(); |
165 } | 87 } |
166 | 88 |
167 bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op,
bool doAA) { | 89 bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op,
bool doAA) { |
168 // base is used to limit the size (and therefore memory allocation) of the | 90 // base is used to limit the size (and therefore memory allocation) of the |
169 // region that results from scan converting devPath. | 91 // region that results from scan converting devPath. |
170 SkRegion base; | 92 SkRegion base; |
171 | 93 |
172 if (fForceConservativeRects) { | |
173 SkIRect ir; | |
174 switch (mutate_conservative_op(&op, path.isInverseFillType())) { | |
175 case kDoNothing_MutateResult: | |
176 return !this->isEmpty(); | |
177 case kReplaceClippedAgainstGlobalBounds_MutateResult: | |
178 ir = SkIRect::MakeSize(size); | |
179 break; | |
180 case kContinue_MutateResult: | |
181 path.getBounds().roundOut(&ir); | |
182 break; | |
183 } | |
184 return this->op(ir, op); | |
185 } | |
186 | |
187 if (SkRegion::kIntersect_Op == op) { | 94 if (SkRegion::kIntersect_Op == op) { |
188 // since we are intersect, we can do better (tighter) with currRgn's | 95 // since we are intersect, we can do better (tighter) with currRgn's |
189 // bounds, than just using the device. However, if currRgn is complex, | 96 // bounds, than just using the device. However, if currRgn is complex, |
190 // our region blitter may hork, so we do that case in two steps. | 97 // our region blitter may hork, so we do that case in two steps. |
191 if (this->isRect()) { | 98 if (this->isRect()) { |
192 // FIXME: we should also be able to do this when this->isBW(), | 99 // FIXME: we should also be able to do this when this->isBW(), |
193 // but relaxing the test above triggers GM asserts in | 100 // but relaxing the test above triggers GM asserts in |
194 // SkRgnBuilder::blitH(). We need to investigate what's going on. | 101 // SkRgnBuilder::blitH(). We need to investigate what's going on. |
195 return this->setPath(path, this->bwRgn(), doAA); | 102 return this->setPath(path, this->bwRgn(), doAA); |
196 } else { | 103 } else { |
197 base.setRect(this->getBounds()); | 104 base.setRect(this->getBounds()); |
198 SkRasterClip clip(fForceConservativeRects); | 105 SkRasterClip clip; |
199 clip.setPath(path, base, doAA); | 106 clip.setPath(path, base, doAA); |
200 return this->op(clip, op); | 107 return this->op(clip, op); |
201 } | 108 } |
202 } else { | 109 } else { |
203 base.setRect(0, 0, size.width(), size.height()); | 110 base.setRect(0, 0, size.width(), size.height()); |
204 | 111 |
205 if (SkRegion::kReplace_Op == op) { | 112 if (SkRegion::kReplace_Op == op) { |
206 return this->setPath(path, base, doAA); | 113 return this->setPath(path, base, doAA); |
207 } else { | 114 } else { |
208 SkRasterClip clip(fForceConservativeRects); | 115 SkRasterClip clip; |
209 clip.setPath(path, base, doAA); | 116 clip.setPath(path, base, doAA); |
210 return this->op(clip, op); | 117 return this->op(clip, op); |
211 } | 118 } |
212 } | 119 } |
213 } | 120 } |
214 | 121 |
215 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) { | 122 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) { |
216 SkRegion tmp; | 123 SkRegion tmp; |
217 tmp.setRect(clip); | 124 tmp.setRect(clip); |
218 return this->setPath(path, tmp, doAA); | 125 return this->setPath(path, tmp, doAA); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 * from its nearest int by < half of that value (1.8 in this case). | 175 * from its nearest int by < half of that value (1.8 in this case). |
269 */ | 176 */ |
270 static bool nearly_integral(SkScalar x) { | 177 static bool nearly_integral(SkScalar x) { |
271 static const SkScalar domain = SK_Scalar1 / 4; | 178 static const SkScalar domain = SK_Scalar1 / 4; |
272 static const SkScalar halfDomain = domain / 2; | 179 static const SkScalar halfDomain = domain / 2; |
273 | 180 |
274 x += halfDomain; | 181 x += halfDomain; |
275 return x - SkScalarFloorToScalar(x) < domain; | 182 return x - SkScalarFloorToScalar(x) < domain; |
276 } | 183 } |
277 | 184 |
278 bool SkRasterClip::op(const SkRect& r, const SkISize& size, SkRegion::Op op, boo
l doAA) { | 185 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) { |
279 AUTO_RASTERCLIP_VALIDATE(*this); | 186 AUTO_RASTERCLIP_VALIDATE(*this); |
280 | 187 |
281 if (fForceConservativeRects) { | |
282 SkIRect ir; | |
283 switch (mutate_conservative_op(&op, false)) { | |
284 case kDoNothing_MutateResult: | |
285 return !this->isEmpty(); | |
286 case kReplaceClippedAgainstGlobalBounds_MutateResult: | |
287 ir = SkIRect::MakeSize(size); | |
288 break; | |
289 case kContinue_MutateResult: | |
290 r.roundOut(&ir); | |
291 break; | |
292 } | |
293 return this->op(ir, op); | |
294 } | |
295 | |
296 if (fIsBW && doAA) { | 188 if (fIsBW && doAA) { |
297 // check that the rect really needs aa, or is it close enought to | 189 // check that the rect really needs aa, or is it close enought to |
298 // integer boundaries that we can just treat it as a BW rect? | 190 // integer boundaries that we can just treat it as a BW rect? |
299 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) && | 191 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) && |
300 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) { | 192 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) { |
301 doAA = false; | 193 doAA = false; |
302 } | 194 } |
303 } | 195 } |
304 | 196 |
305 if (fIsBW && !doAA) { | 197 if (fIsBW && !doAA) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 AUTO_RASTERCLIP_VALIDATE(*this); | 244 AUTO_RASTERCLIP_VALIDATE(*this); |
353 | 245 |
354 if (!fIsBW) { | 246 if (!fIsBW) { |
355 fBW.setRect(fAA.getBounds()); | 247 fBW.setRect(fAA.getBounds()); |
356 } | 248 } |
357 return fBW; | 249 return fBW; |
358 } | 250 } |
359 | 251 |
360 void SkRasterClip::convertToAA() { | 252 void SkRasterClip::convertToAA() { |
361 AUTO_RASTERCLIP_VALIDATE(*this); | 253 AUTO_RASTERCLIP_VALIDATE(*this); |
362 | 254 |
363 SkASSERT(!fForceConservativeRects); | |
364 | |
365 SkASSERT(fIsBW); | 255 SkASSERT(fIsBW); |
366 fAA.setRegion(fBW); | 256 fAA.setRegion(fBW); |
367 fIsBW = false; | 257 fIsBW = false; |
368 | 258 |
369 // since we are being explicitly asked to convert-to-aa, we pass false so we
don't "optimize" | 259 // since we are being explicitly asked to convert-to-aa, we pass false so we
don't "optimize" |
370 // ourselves back to BW. | 260 // ourselves back to BW. |
371 (void)this->updateCacheAndReturnNonEmpty(false); | 261 (void)this->updateCacheAndReturnNonEmpty(false); |
372 } | 262 } |
373 | 263 |
374 #ifdef SK_DEBUG | 264 #ifdef SK_DEBUG |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 fBlitter = blitter; | 306 fBlitter = blitter; |
417 } else { | 307 } else { |
418 const SkAAClip& aaclip = clip.aaRgn(); | 308 const SkAAClip& aaclip = clip.aaRgn(); |
419 fBWRgn.setRect(aaclip.getBounds()); | 309 fBWRgn.setRect(aaclip.getBounds()); |
420 fAABlitter.init(blitter, &aaclip); | 310 fAABlitter.init(blitter, &aaclip); |
421 // now our return values | 311 // now our return values |
422 fClipRgn = &fBWRgn; | 312 fClipRgn = &fBWRgn; |
423 fBlitter = &fAABlitter; | 313 fBlitter = &fAABlitter; |
424 } | 314 } |
425 } | 315 } |
OLD | NEW |