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 } 14 15 SkRasterClip::SkRasterClip(const SkRasterClip& src) { 16 AUTO_RASTERCLIP_VALIDATE(src); 17 18 fIsBW = src.fIsBW; 19 if (fIsBW) { 20 fBW = src.fBW; 21 } else { 22 fAA = src.fAA; 23 } 24 } 25 26 SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) { 27 fIsBW = true; 28 } 29 30 SkRasterClip::~SkRasterClip() { 31 AUTO_RASTERCLIP_VALIDATE(*this); 32 } 33 34 bool SkRasterClip::isEmpty() const { 35 return fIsBW ? fBW.isEmpty() : fAA.isEmpty(); 36 } 37 38 bool SkRasterClip::isRect() const { 39 return fIsBW ? fBW.isRect() : false; 40 } 41 42 bool SkRasterClip::isComplex() const { 43 return fIsBW ? fBW.isComplex() : !fAA.isEmpty(); 44 } 45 46 const SkIRect& SkRasterClip::getBounds() const { 47 return fIsBW ? fBW.getBounds() : fAA.getBounds(); 48 } 49 50 bool SkRasterClip::setEmpty() { 51 AUTO_RASTERCLIP_VALIDATE(*this); 52 53 fIsBW = true; 54 fBW.setEmpty(); 55 fAA.setEmpty(); 56 return false; 57 } 58 59 bool SkRasterClip::setRect(const SkIRect& rect) { 60 AUTO_RASTERCLIP_VALIDATE(*this); 61 62 fIsBW = true; 63 fAA.setEmpty(); 64 return fBW.setRect(rect); 65 } 66 67 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) { 68 AUTO_RASTERCLIP_VALIDATE(*this); 69 70 if (this->isBW() && !doAA) { 71 return fBW.setPath(path, clip); 72 } else { 73 // TODO: since we are going to over-write fAA completely (aren't we?) 74 // we should just clear our BW data (if any) and set fIsAA=true 75 if (this->isBW()) { 76 this->convertToAA(); 77 } 78 return fAA.setPath(path, &clip, doAA); 79 } 80 } 81 82 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) { 83 SkRegion tmp; 84 tmp.setRect(clip); 85 return this->setPath(path, tmp, doAA); 86 } 87 88 bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip, 89 bool doAA) { 90 if (clip.isBW()) { 91 return this->setPath(path, clip.bwRgn(), doAA); 92 } else { 93 SkRegion tmp; 94 tmp.setRect(clip.getBounds()); 95 if (!this->setPath(path, clip, doAA)) { 96 return false; 97 } 98 return this->op(clip, SkRegion::kIntersect_Op); 99 } 100 } 101 102 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) { 103 AUTO_RASTERCLIP_VALIDATE(*this); 104 105 return fIsBW ? fBW.op(rect, op) : fAA.op(rect, op); 106 } 107 108 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) { 109 AUTO_RASTERCLIP_VALIDATE(*this); 110 111 if (fIsBW) { 112 return fBW.op(rgn, op); 113 } else { 114 SkAAClip tmp; 115 tmp.setRegion(rgn); 116 return fAA.op(tmp, op); 117 } 118 } 119 120 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) { 121 AUTO_RASTERCLIP_VALIDATE(*this); 122 clip.validate(); 123 124 if (this->isBW() && clip.isBW()) { 125 return fBW.op(clip.fBW, op); 126 } else { 127 SkAAClip tmp; 128 const SkAAClip* other; 129 130 if (this->isBW()) { 131 this->convertToAA(); 132 } 133 if (clip.isBW()) { 134 tmp.setRegion(clip.bwRgn()); 135 other = &tmp; 136 } else { 137 other = &clip.aaRgn(); 138 } 139 return fAA.op(*other, op); 140 } 141 } 142 143 // return true if x is nearly integral (within 1/16) since that is the highest 144 // precision our aa code can have. 145 static bool is_integral(SkScalar x) { 146 int ix = SkScalarRoundToInt(x); 147 SkScalar sx = SkIntToScalar(ix); 148 return SkScalarAbs(sx - x) < (SK_Scalar1 / 16); 149 } 150 151 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) { 152 AUTO_RASTERCLIP_VALIDATE(*this); 153 154 if (doAA) { 155 // check that the rect really needs aa 156 if (is_integral(r.fLeft) && is_integral(r.fTop) && 157 is_integral(r.fRight) && is_integral(r.fBottom)) { 158 doAA = false; 159 } 160 } 161 162 if (fIsBW && !doAA) { 163 SkIRect ir; 164 r.round(&ir); 165 return fBW.op(ir, op); 166 } else { 167 if (fIsBW) { 168 this->convertToAA(); 169 } 170 return fAA.op(r, op, doAA); 171 } 172 } 173 174 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const { 175 if (NULL == dst) { 176 return; 177 } 178 179 AUTO_RASTERCLIP_VALIDATE(*this); 180 181 if (this->isEmpty()) { 182 dst->setEmpty(); 183 return; 184 } 185 if (0 == (dx | dy)) { 186 *dst = *this; 187 return; 188 } 189 190 dst->fIsBW = fIsBW; 191 if (fIsBW) { 192 fBW.translate(dx, dy, &dst->fBW); 193 dst->fAA.setEmpty(); 194 } else { 195 fAA.translate(dx, dy, &dst->fAA); 196 dst->fBW.setEmpty(); 197 } 198 } 199 200 bool SkRasterClip::quickContains(const SkIRect& ir) const { 201 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir); 202 } 203 204 /////////////////////////////////////////////////////////////////////////////// 205 206 const SkRegion& SkRasterClip::forceGetBW() { 207 AUTO_RASTERCLIP_VALIDATE(*this); 208 209 if (!fIsBW) { 210 fBW.setRect(fAA.getBounds()); 211 } 212 return fBW; 213 } 214 215 void SkRasterClip::convertToAA() { 216 AUTO_RASTERCLIP_VALIDATE(*this); 217 218 SkASSERT(fIsBW); 219 fAA.setRegion(fBW); 220 fIsBW = false; 221 } 222 223 #ifdef SK_DEBUG 224 void SkRasterClip::validate() const { 225 // can't ever assert that fBW is empty, since we may have called forceGetBW 226 if (fIsBW) { 227 SkASSERT(fAA.isEmpty()); 228 } 229 230 fBW.validate(); 231 fAA.validate(); 232 } 233 #endif 234 235 /////////////////////////////////////////////////////////////////////////////// 236 237 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() { 238 SkDEBUGCODE(fClipRgn = NULL;) 239 SkDEBUGCODE(fBlitter = NULL;) 240 } 241 242 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip, 243 SkBlitter* blitter) { 244 this->init(clip, blitter); 245 } 246 247 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip, 248 SkBlitter* blitter) { 249 SkASSERT(blitter); 250 SkASSERT(aaclip); 251 fBWRgn.setRect(aaclip->getBounds()); 252 fAABlitter.init(blitter, aaclip); 253 // now our return values 254 fClipRgn = &fBWRgn; 255 fBlitter = &fAABlitter; 256 } 257 258 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) { 259 SkASSERT(blitter); 260 if (clip.isBW()) { 261 fClipRgn = &clip.bwRgn(); 262 fBlitter = blitter; 263 } else { 264 const SkAAClip& aaclip = clip.aaRgn(); 265 fBWRgn.setRect(aaclip.getBounds()); 266 fAABlitter.init(blitter, &aaclip); 267 // now our return values 268 fClipRgn = &fBWRgn; 269 fBlitter = &fAABlitter; 270 } 271 } 272 273