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