SkRasterClip.cpp revision fbfcd5602128ec010c82cb733c9cdc0a3254f9f3
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 11SkRasterClip::SkRasterClip() { 12 fIsBW = true; 13 fIsEmpty = true; 14 fIsRect = false; 15 SkDEBUGCODE(this->validate();) 16} 17 18SkRasterClip::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 33SkRasterClip::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 40SkRasterClip::~SkRasterClip() { 41 SkDEBUGCODE(this->validate();) 42} 43 44bool SkRasterClip::isComplex() const { 45 return fIsBW ? fBW.isComplex() : !fAA.isEmpty(); 46} 47 48const SkIRect& SkRasterClip::getBounds() const { 49 return fIsBW ? fBW.getBounds() : fAA.getBounds(); 50} 51 52bool 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 63bool 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 73bool 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 89bool 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 95bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip, 96 bool doAA) { 97 if (clip.isBW()) { 98 return this->setPath(path, clip.bwRgn(), doAA); 99 } else { 100 SkRegion tmp; 101 tmp.setRect(clip.getBounds()); 102 if (!this->setPath(path, clip, doAA)) { 103 return false; 104 } 105 return this->op(clip, SkRegion::kIntersect_Op); 106 } 107} 108 109bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) { 110 AUTO_RASTERCLIP_VALIDATE(*this); 111 112 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op); 113 return this->updateCacheAndReturnNonEmpty(); 114} 115 116bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) { 117 AUTO_RASTERCLIP_VALIDATE(*this); 118 119 if (fIsBW) { 120 (void)fBW.op(rgn, op); 121 } else { 122 SkAAClip tmp; 123 tmp.setRegion(rgn); 124 (void)fAA.op(tmp, op); 125 } 126 return this->updateCacheAndReturnNonEmpty(); 127} 128 129bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) { 130 AUTO_RASTERCLIP_VALIDATE(*this); 131 clip.validate(); 132 133 if (this->isBW() && clip.isBW()) { 134 (void)fBW.op(clip.fBW, op); 135 } else { 136 SkAAClip tmp; 137 const SkAAClip* other; 138 139 if (this->isBW()) { 140 this->convertToAA(); 141 } 142 if (clip.isBW()) { 143 tmp.setRegion(clip.bwRgn()); 144 other = &tmp; 145 } else { 146 other = &clip.aaRgn(); 147 } 148 (void)fAA.op(*other, op); 149 } 150 return this->updateCacheAndReturnNonEmpty(); 151} 152 153/** 154 * Our antialiasing currently has a granularity of 1/4 of a pixel along each 155 * axis. Thus we can treat an axis coordinate as an integer if it differs 156 * from its nearest int by < half of that value (1.8 in this case). 157 */ 158static bool nearly_integral(SkScalar x) { 159 static const SkScalar domain = SK_Scalar1 / 4; 160 static const SkScalar halfDomain = domain / 2; 161 162 x += halfDomain; 163 return x - SkScalarFloorToScalar(x) < domain; 164} 165 166bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) { 167 AUTO_RASTERCLIP_VALIDATE(*this); 168 169 if (fIsBW && doAA) { 170 // check that the rect really needs aa, or is it close enought to 171 // integer boundaries that we can just treat it as a BW rect? 172 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) && 173 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) { 174 doAA = false; 175 } 176 } 177 178 if (fIsBW && !doAA) { 179 SkIRect ir; 180 r.round(&ir); 181 (void)fBW.op(ir, op); 182 } else { 183 if (fIsBW) { 184 this->convertToAA(); 185 } 186 (void)fAA.op(r, op, doAA); 187 } 188 return this->updateCacheAndReturnNonEmpty(); 189} 190 191void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const { 192 if (NULL == dst) { 193 return; 194 } 195 196 AUTO_RASTERCLIP_VALIDATE(*this); 197 198 if (this->isEmpty()) { 199 dst->setEmpty(); 200 return; 201 } 202 if (0 == (dx | dy)) { 203 *dst = *this; 204 return; 205 } 206 207 dst->fIsBW = fIsBW; 208 if (fIsBW) { 209 fBW.translate(dx, dy, &dst->fBW); 210 dst->fAA.setEmpty(); 211 } else { 212 fAA.translate(dx, dy, &dst->fAA); 213 dst->fBW.setEmpty(); 214 } 215 dst->updateCacheAndReturnNonEmpty(); 216} 217 218bool SkRasterClip::quickContains(const SkIRect& ir) const { 219 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir); 220} 221 222/////////////////////////////////////////////////////////////////////////////// 223 224const SkRegion& SkRasterClip::forceGetBW() { 225 AUTO_RASTERCLIP_VALIDATE(*this); 226 227 if (!fIsBW) { 228 fBW.setRect(fAA.getBounds()); 229 } 230 return fBW; 231} 232 233void SkRasterClip::convertToAA() { 234 AUTO_RASTERCLIP_VALIDATE(*this); 235 236 SkASSERT(fIsBW); 237 fAA.setRegion(fBW); 238 fIsBW = false; 239 (void)this->updateCacheAndReturnNonEmpty(); 240} 241 242#ifdef SK_DEBUG 243void SkRasterClip::validate() const { 244 // can't ever assert that fBW is empty, since we may have called forceGetBW 245 if (fIsBW) { 246 SkASSERT(fAA.isEmpty()); 247 } 248 249 fBW.validate(); 250 fAA.validate(); 251 252 SkASSERT(this->computeIsEmpty() == fIsEmpty); 253 SkASSERT(this->computeIsRect() == fIsRect); 254} 255#endif 256 257/////////////////////////////////////////////////////////////////////////////// 258 259SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() { 260 SkDEBUGCODE(fClipRgn = NULL;) 261 SkDEBUGCODE(fBlitter = NULL;) 262} 263 264SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip, 265 SkBlitter* blitter) { 266 this->init(clip, blitter); 267} 268 269SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip, 270 SkBlitter* blitter) { 271 SkASSERT(blitter); 272 SkASSERT(aaclip); 273 fBWRgn.setRect(aaclip->getBounds()); 274 fAABlitter.init(blitter, aaclip); 275 // now our return values 276 fClipRgn = &fBWRgn; 277 fBlitter = &fAABlitter; 278} 279 280void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) { 281 SkASSERT(blitter); 282 if (clip.isBW()) { 283 fClipRgn = &clip.bwRgn(); 284 fBlitter = blitter; 285 } else { 286 const SkAAClip& aaclip = clip.aaRgn(); 287 fBWRgn.setRect(aaclip.getBounds()); 288 fAABlitter.init(blitter, &aaclip); 289 // now our return values 290 fClipRgn = &fBWRgn; 291 fBlitter = &fAABlitter; 292 } 293} 294 295