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