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