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 #include "SkPath.h" 10 11 SkRasterClip::SkRasterClip(const SkRasterClip& src) { 12 AUTO_RASTERCLIP_VALIDATE(src); 13 14 fForceConservativeRects = src.fForceConservativeRects; 15 fIsBW = src.fIsBW; 16 if (fIsBW) { 17 fBW = src.fBW; 18 } else { 19 fAA = src.fAA; 20 } 21 22 fIsEmpty = src.isEmpty(); 23 fIsRect = src.isRect(); 24 SkDEBUGCODE(this->validate();) 25 } 26 27 SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) { 28 fForceConservativeRects = forceConservativeRects; 29 fIsBW = true; 30 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute 31 fIsRect = !fIsEmpty; 32 SkDEBUGCODE(this->validate();) 33 } 34 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() { 44 SkDEBUGCODE(this->validate();) 45 } 46 47 bool SkRasterClip::isComplex() const { 48 return fIsBW ? fBW.isComplex() : !fAA.isEmpty(); 49 } 50 51 const SkIRect& SkRasterClip::getBounds() const { 52 return fIsBW ? fBW.getBounds() : fAA.getBounds(); 53 } 54 55 bool SkRasterClip::setEmpty() { 56 AUTO_RASTERCLIP_VALIDATE(*this); 57 58 fIsBW = true; 59 fBW.setEmpty(); 60 fAA.setEmpty(); 61 fIsEmpty = true; 62 fIsRect = false; 63 return false; 64 } 65 66 bool SkRasterClip::setRect(const SkIRect& rect) { 67 AUTO_RASTERCLIP_VALIDATE(*this); 68 69 fIsBW = true; 70 fAA.setEmpty(); 71 fIsRect = fBW.setRect(rect); 72 fIsEmpty = !fIsRect; 73 return fIsRect; 74 } 75 76 ///////////////////////////////////////////////////////////////////////////////////// 77 78 bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) { 79 SkRegion::Op op; 80 if (isInverse) { 81 op = SkRegion::kDifference_Op; 82 } else { 83 op = SkRegion::kIntersect_Op; 84 } 85 fBW.setRect(clipR); 86 fBW.op(r.roundOut(), op); 87 return this->updateCacheAndReturnNonEmpty(); 88 } 89 90 ///////////////////////////////////////////////////////////////////////////////////// 91 92 enum MutateResult { 93 kDoNothing_MutateResult, 94 kReplaceClippedAgainstGlobalBounds_MutateResult, 95 kContinue_MutateResult, 96 }; 97 98 static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) { 99 if (inverseFilled) { 100 switch (*op) { 101 case SkRegion::kIntersect_Op: 102 case SkRegion::kDifference_Op: 103 // These ops can only shrink the current clip. So leaving 104 // the clip unchanged conservatively respects the contract. 105 return kDoNothing_MutateResult; 106 case SkRegion::kUnion_Op: 107 case SkRegion::kReplace_Op: 108 case SkRegion::kReverseDifference_Op: 109 case SkRegion::kXOR_Op: { 110 // These ops can grow the current clip up to the extents of 111 // the input clip, which is inverse filled, so we just set 112 // the current clip to the device bounds. 113 *op = SkRegion::kReplace_Op; 114 return kReplaceClippedAgainstGlobalBounds_MutateResult; 115 } 116 } 117 } else { 118 // Not inverse filled 119 switch (*op) { 120 case SkRegion::kIntersect_Op: 121 case SkRegion::kUnion_Op: 122 case SkRegion::kReplace_Op: 123 return kContinue_MutateResult; 124 case SkRegion::kDifference_Op: 125 // Difference can only shrink the current clip. 126 // Leaving clip unchanged conservatively fullfills the contract. 127 return kDoNothing_MutateResult; 128 case SkRegion::kReverseDifference_Op: 129 // To reverse, we swap in the bounds with a replace op. 130 // As with difference, leave it unchanged. 131 *op = SkRegion::kReplace_Op; 132 return kContinue_MutateResult; 133 case SkRegion::kXOR_Op: 134 // Be conservative, based on (A XOR B) always included in (A union B), 135 // which is always included in (bounds(A) union bounds(B)) 136 *op = SkRegion::kUnion_Op; 137 return kContinue_MutateResult; 138 } 139 } 140 SkFAIL("should not get here"); 141 return kDoNothing_MutateResult; 142 } 143 144 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) { 145 AUTO_RASTERCLIP_VALIDATE(*this); 146 147 if (fForceConservativeRects) { 148 return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType()); 149 } 150 151 if (this->isBW() && !doAA) { 152 (void)fBW.setPath(path, clip); 153 } else { 154 // TODO: since we are going to over-write fAA completely (aren't we?) 155 // we should just clear our BW data (if any) and set fIsAA=true 156 if (this->isBW()) { 157 this->convertToAA(); 158 } 159 (void)fAA.setPath(path, &clip, doAA); 160 } 161 return this->updateCacheAndReturnNonEmpty(); 162 } 163 164 bool SkRasterClip::op(const SkRRect& rrect, const SkIRect& bounds, SkRegion::Op op, bool doAA) { 165 if (fForceConservativeRects) { 166 return this->op(rrect.getBounds(), bounds, op, doAA); 167 } 168 169 SkPath path; 170 path.addRRect(rrect); 171 172 return this->op(path, bounds, op, doAA); 173 } 174 175 bool SkRasterClip::op(const SkPath& path, const SkIRect& bounds, SkRegion::Op op, bool doAA) { 176 AUTO_RASTERCLIP_VALIDATE(*this); 177 178 if (fForceConservativeRects) { 179 SkIRect ir; 180 switch (mutate_conservative_op(&op, path.isInverseFillType())) { 181 case kDoNothing_MutateResult: 182 return !this->isEmpty(); 183 case kReplaceClippedAgainstGlobalBounds_MutateResult: 184 ir = bounds; 185 break; 186 case kContinue_MutateResult: 187 ir = path.getBounds().roundOut(); 188 break; 189 } 190 return this->op(ir, op); 191 } 192 193 // base is used to limit the size (and therefore memory allocation) of the 194 // region that results from scan converting devPath. 195 SkRegion base; 196 197 if (SkRegion::kIntersect_Op == op) { 198 // since we are intersect, we can do better (tighter) with currRgn's 199 // bounds, than just using the device. However, if currRgn is complex, 200 // our region blitter may hork, so we do that case in two steps. 201 if (this->isRect()) { 202 // FIXME: we should also be able to do this when this->isBW(), 203 // but relaxing the test above triggers GM asserts in 204 // SkRgnBuilder::blitH(). We need to investigate what's going on. 205 return this->setPath(path, this->bwRgn(), doAA); 206 } else { 207 base.setRect(this->getBounds()); 208 SkRasterClip clip(fForceConservativeRects); 209 clip.setPath(path, base, doAA); 210 return this->op(clip, op); 211 } 212 } else { 213 base.setRect(bounds); 214 215 if (SkRegion::kReplace_Op == op) { 216 return this->setPath(path, base, doAA); 217 } else { 218 SkRasterClip clip(fForceConservativeRects); 219 clip.setPath(path, base, doAA); 220 return this->op(clip, op); 221 } 222 } 223 } 224 225 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) { 226 SkRegion tmp; 227 tmp.setRect(clip); 228 return this->setPath(path, tmp, doAA); 229 } 230 231 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) { 232 AUTO_RASTERCLIP_VALIDATE(*this); 233 234 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op); 235 return this->updateCacheAndReturnNonEmpty(); 236 } 237 238 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) { 239 AUTO_RASTERCLIP_VALIDATE(*this); 240 241 if (fIsBW) { 242 (void)fBW.op(rgn, op); 243 } else { 244 SkAAClip tmp; 245 tmp.setRegion(rgn); 246 (void)fAA.op(tmp, op); 247 } 248 return this->updateCacheAndReturnNonEmpty(); 249 } 250 251 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) { 252 AUTO_RASTERCLIP_VALIDATE(*this); 253 clip.validate(); 254 255 if (this->isBW() && clip.isBW()) { 256 (void)fBW.op(clip.fBW, op); 257 } else { 258 SkAAClip tmp; 259 const SkAAClip* other; 260 261 if (this->isBW()) { 262 this->convertToAA(); 263 } 264 if (clip.isBW()) { 265 tmp.setRegion(clip.bwRgn()); 266 other = &tmp; 267 } else { 268 other = &clip.aaRgn(); 269 } 270 (void)fAA.op(*other, op); 271 } 272 return this->updateCacheAndReturnNonEmpty(); 273 } 274 275 /** 276 * Our antialiasing currently has a granularity of 1/4 of a pixel along each 277 * axis. Thus we can treat an axis coordinate as an integer if it differs 278 * from its nearest int by < half of that value (1.8 in this case). 279 */ 280 static bool nearly_integral(SkScalar x) { 281 static const SkScalar domain = SK_Scalar1 / 4; 282 static const SkScalar halfDomain = domain / 2; 283 284 x += halfDomain; 285 return x - SkScalarFloorToScalar(x) < domain; 286 } 287 288 bool SkRasterClip::op(const SkRect& r, const SkIRect& bounds, SkRegion::Op op, bool doAA) { 289 AUTO_RASTERCLIP_VALIDATE(*this); 290 291 if (fForceConservativeRects) { 292 SkIRect ir; 293 switch (mutate_conservative_op(&op, false)) { 294 case kDoNothing_MutateResult: 295 return !this->isEmpty(); 296 case kReplaceClippedAgainstGlobalBounds_MutateResult: 297 ir = bounds; 298 break; 299 case kContinue_MutateResult: 300 ir = r.roundOut(); 301 break; 302 } 303 return this->op(ir, op); 304 } 305 306 if (fIsBW && doAA) { 307 // check that the rect really needs aa, or is it close enought to 308 // integer boundaries that we can just treat it as a BW rect? 309 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) && 310 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) { 311 doAA = false; 312 } 313 } 314 315 if (fIsBW && !doAA) { 316 SkIRect ir; 317 r.round(&ir); 318 (void)fBW.op(ir, op); 319 } else { 320 if (fIsBW) { 321 this->convertToAA(); 322 } 323 (void)fAA.op(r, op, doAA); 324 } 325 return this->updateCacheAndReturnNonEmpty(); 326 } 327 328 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const { 329 if (nullptr == dst) { 330 return; 331 } 332 333 AUTO_RASTERCLIP_VALIDATE(*this); 334 335 if (this->isEmpty()) { 336 dst->setEmpty(); 337 return; 338 } 339 if (0 == (dx | dy)) { 340 *dst = *this; 341 return; 342 } 343 344 dst->fIsBW = fIsBW; 345 if (fIsBW) { 346 fBW.translate(dx, dy, &dst->fBW); 347 dst->fAA.setEmpty(); 348 } else { 349 fAA.translate(dx, dy, &dst->fAA); 350 dst->fBW.setEmpty(); 351 } 352 dst->updateCacheAndReturnNonEmpty(); 353 } 354 355 bool SkRasterClip::quickContains(const SkIRect& ir) const { 356 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir); 357 } 358 359 /////////////////////////////////////////////////////////////////////////////// 360 361 const SkRegion& SkRasterClip::forceGetBW() { 362 AUTO_RASTERCLIP_VALIDATE(*this); 363 364 if (!fIsBW) { 365 fBW.setRect(fAA.getBounds()); 366 } 367 return fBW; 368 } 369 370 void SkRasterClip::convertToAA() { 371 AUTO_RASTERCLIP_VALIDATE(*this); 372 373 SkASSERT(!fForceConservativeRects); 374 375 SkASSERT(fIsBW); 376 fAA.setRegion(fBW); 377 fIsBW = false; 378 379 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize" 380 // ourselves back to BW. 381 (void)this->updateCacheAndReturnNonEmpty(false); 382 } 383 384 #ifdef SK_DEBUG 385 void SkRasterClip::validate() const { 386 // can't ever assert that fBW is empty, since we may have called forceGetBW 387 if (fIsBW) { 388 SkASSERT(fAA.isEmpty()); 389 } 390 391 fBW.validate(); 392 fAA.validate(); 393 394 SkASSERT(this->computeIsEmpty() == fIsEmpty); 395 SkASSERT(this->computeIsRect() == fIsRect); 396 } 397 #endif 398 399 /////////////////////////////////////////////////////////////////////////////// 400 401 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() { 402 SkDEBUGCODE(fClipRgn = nullptr;) 403 SkDEBUGCODE(fBlitter = nullptr;) 404 } 405 406 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip, 407 SkBlitter* blitter) { 408 this->init(clip, blitter); 409 } 410 411 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip, 412 SkBlitter* blitter) { 413 SkASSERT(blitter); 414 SkASSERT(aaclip); 415 fBWRgn.setRect(aaclip->getBounds()); 416 fAABlitter.init(blitter, aaclip); 417 // now our return values 418 fClipRgn = &fBWRgn; 419 fBlitter = &fAABlitter; 420 } 421 422 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) { 423 SkASSERT(blitter); 424 if (clip.isBW()) { 425 fClipRgn = &clip.bwRgn(); 426 fBlitter = blitter; 427 } else { 428 const SkAAClip& aaclip = clip.aaRgn(); 429 fBWRgn.setRect(aaclip.getBounds()); 430 fAABlitter.init(blitter, &aaclip); 431 // now our return values 432 fClipRgn = &fBWRgn; 433 fBlitter = &fAABlitter; 434 } 435 } 436