Chromium Code Reviews| 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 *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 | |
| 73 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) { | 147 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) { |
| 74 AUTO_RASTERCLIP_VALIDATE(*this); | 148 AUTO_RASTERCLIP_VALIDATE(*this); |
| 75 | 149 |
| 150 if (fForceConservativeRects) { | |
| 151 return this->setConservativeRect(path.getBounds(), clip.getBounds(), pat h.isInverseFillType()); | |
| 152 } | |
| 153 | |
| 76 if (this->isBW() && !doAA) { | 154 if (this->isBW() && !doAA) { |
| 77 (void)fBW.setPath(path, clip); | 155 (void)fBW.setPath(path, clip); |
| 78 } else { | 156 } else { |
| 79 // TODO: since we are going to over-write fAA completely (aren't we?) | 157 // 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 | 158 // we should just clear our BW data (if any) and set fIsAA=true |
| 81 if (this->isBW()) { | 159 if (this->isBW()) { |
| 82 this->convertToAA(); | 160 this->convertToAA(); |
| 83 } | 161 } |
| 84 (void)fAA.setPath(path, &clip, doAA); | 162 (void)fAA.setPath(path, &clip, doAA); |
| 85 } | 163 } |
| 86 return this->updateCacheAndReturnNonEmpty(); | 164 return this->updateCacheAndReturnNonEmpty(); |
| 87 } | 165 } |
| 88 | 166 |
| 89 bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, bool doAA) { | 167 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 | 168 // base is used to limit the size (and therefore memory allocation) of the |
| 91 // region that results from scan converting devPath. | 169 // region that results from scan converting devPath. |
| 92 SkRegion base; | 170 SkRegion base; |
| 93 | 171 |
|
robertphillips
2014/09/10 14:44:23
Subroutine for this and the version in SkRasterCli
| |
| 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 | |
| 94 if (SkRegion::kIntersect_Op == op) { | 187 if (SkRegion::kIntersect_Op == op) { |
| 95 // since we are intersect, we can do better (tighter) with currRgn's | 188 // since we are intersect, we can do better (tighter) with currRgn's |
| 96 // bounds, than just using the device. However, if currRgn is complex, | 189 // 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. | 190 // our region blitter may hork, so we do that case in two steps. |
| 98 if (this->isRect()) { | 191 if (this->isRect()) { |
| 99 // FIXME: we should also be able to do this when this->isBW(), | 192 // FIXME: we should also be able to do this when this->isBW(), |
| 100 // but relaxing the test above triggers GM asserts in | 193 // but relaxing the test above triggers GM asserts in |
| 101 // SkRgnBuilder::blitH(). We need to investigate what's going on. | 194 // SkRgnBuilder::blitH(). We need to investigate what's going on. |
| 102 return this->setPath(path, this->bwRgn(), doAA); | 195 return this->setPath(path, this->bwRgn(), doAA); |
| 103 } else { | 196 } else { |
| 104 base.setRect(this->getBounds()); | 197 base.setRect(this->getBounds()); |
| 105 SkRasterClip clip; | 198 SkRasterClip clip(fForceConservativeRects); |
| 106 clip.setPath(path, base, doAA); | 199 clip.setPath(path, base, doAA); |
| 107 return this->op(clip, op); | 200 return this->op(clip, op); |
| 108 } | 201 } |
| 109 } else { | 202 } else { |
| 110 base.setRect(0, 0, size.width(), size.height()); | 203 base.setRect(0, 0, size.width(), size.height()); |
| 111 | 204 |
| 112 if (SkRegion::kReplace_Op == op) { | 205 if (SkRegion::kReplace_Op == op) { |
| 113 return this->setPath(path, base, doAA); | 206 return this->setPath(path, base, doAA); |
| 114 } else { | 207 } else { |
| 115 SkRasterClip clip; | 208 SkRasterClip clip(fForceConservativeRects); |
| 116 clip.setPath(path, base, doAA); | 209 clip.setPath(path, base, doAA); |
| 117 return this->op(clip, op); | 210 return this->op(clip, op); |
| 118 } | 211 } |
| 119 } | 212 } |
| 120 } | 213 } |
| 121 | 214 |
| 122 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) { | 215 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) { |
| 123 SkRegion tmp; | 216 SkRegion tmp; |
| 124 tmp.setRect(clip); | 217 tmp.setRect(clip); |
| 125 return this->setPath(path, tmp, doAA); | 218 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). | 268 * from its nearest int by < half of that value (1.8 in this case). |
| 176 */ | 269 */ |
| 177 static bool nearly_integral(SkScalar x) { | 270 static bool nearly_integral(SkScalar x) { |
| 178 static const SkScalar domain = SK_Scalar1 / 4; | 271 static const SkScalar domain = SK_Scalar1 / 4; |
| 179 static const SkScalar halfDomain = domain / 2; | 272 static const SkScalar halfDomain = domain / 2; |
| 180 | 273 |
| 181 x += halfDomain; | 274 x += halfDomain; |
| 182 return x - SkScalarFloorToScalar(x) < domain; | 275 return x - SkScalarFloorToScalar(x) < domain; |
| 183 } | 276 } |
| 184 | 277 |
| 185 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) { | 278 bool SkRasterClip::op(const SkRect& r, const SkISize& size, SkRegion::Op op, boo l doAA) { |
| 186 AUTO_RASTERCLIP_VALIDATE(*this); | 279 AUTO_RASTERCLIP_VALIDATE(*this); |
| 187 | 280 |
| 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 | |
| 188 if (fIsBW && doAA) { | 296 if (fIsBW && doAA) { |
| 189 // check that the rect really needs aa, or is it close enought to | 297 // 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? | 298 // integer boundaries that we can just treat it as a BW rect? |
| 191 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) && | 299 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) && |
| 192 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) { | 300 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) { |
| 193 doAA = false; | 301 doAA = false; |
| 194 } | 302 } |
| 195 } | 303 } |
| 196 | 304 |
| 197 if (fIsBW && !doAA) { | 305 if (fIsBW && !doAA) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 AUTO_RASTERCLIP_VALIDATE(*this); | 352 AUTO_RASTERCLIP_VALIDATE(*this); |
| 245 | 353 |
| 246 if (!fIsBW) { | 354 if (!fIsBW) { |
| 247 fBW.setRect(fAA.getBounds()); | 355 fBW.setRect(fAA.getBounds()); |
| 248 } | 356 } |
| 249 return fBW; | 357 return fBW; |
| 250 } | 358 } |
| 251 | 359 |
| 252 void SkRasterClip::convertToAA() { | 360 void SkRasterClip::convertToAA() { |
| 253 AUTO_RASTERCLIP_VALIDATE(*this); | 361 AUTO_RASTERCLIP_VALIDATE(*this); |
| 254 | 362 |
| 363 SkASSERT(!fForceConservativeRects); | |
| 364 | |
| 255 SkASSERT(fIsBW); | 365 SkASSERT(fIsBW); |
| 256 fAA.setRegion(fBW); | 366 fAA.setRegion(fBW); |
| 257 fIsBW = false; | 367 fIsBW = false; |
| 258 | 368 |
| 259 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize" | 369 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize" |
| 260 // ourselves back to BW. | 370 // ourselves back to BW. |
| 261 (void)this->updateCacheAndReturnNonEmpty(false); | 371 (void)this->updateCacheAndReturnNonEmpty(false); |
| 262 } | 372 } |
| 263 | 373 |
| 264 #ifdef SK_DEBUG | 374 #ifdef SK_DEBUG |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 306 fBlitter = blitter; | 416 fBlitter = blitter; |
| 307 } else { | 417 } else { |
| 308 const SkAAClip& aaclip = clip.aaRgn(); | 418 const SkAAClip& aaclip = clip.aaRgn(); |
| 309 fBWRgn.setRect(aaclip.getBounds()); | 419 fBWRgn.setRect(aaclip.getBounds()); |
| 310 fAABlitter.init(blitter, &aaclip); | 420 fAABlitter.init(blitter, &aaclip); |
| 311 // now our return values | 421 // now our return values |
| 312 fClipRgn = &fBWRgn; | 422 fClipRgn = &fBWRgn; |
| 313 fBlitter = &fAABlitter; | 423 fBlitter = &fAABlitter; |
| 314 } | 424 } |
| 315 } | 425 } |
| OLD | NEW |