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 #ifndef SkRasterClip_DEFINED 9 #define SkRasterClip_DEFINED 10 11 #include "include/core/SkRegion.h" 12 #include "include/core/SkShader.h" 13 #include "include/private/SkMacros.h" 14 #include "src/core/SkAAClip.h" 15 16 class SkRRect; 17 18 class SkConservativeClip { 19 SkIRect fBounds = SkIRect::MakeEmpty(); 20 bool fIsRect = true; 21 bool fAA = false; 22 23 const SkIRect* fClipRestrictionRect = nullptr; 24 applyClipRestriction(SkRegion::Op op,SkIRect * bounds)25 inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) { 26 if (op >= SkRegion::kUnion_Op && fClipRestrictionRect 27 && !fClipRestrictionRect->isEmpty()) { 28 if (!bounds->intersect(*fClipRestrictionRect)) { 29 bounds->setEmpty(); 30 } 31 } 32 } 33 34 enum class ClipAA : bool { kNo = false, kYes = true }; 35 enum class IsRect : bool { kNo = false, kYes = true }; 36 applyOpParams(SkRegion::Op op,ClipAA aa,IsRect rect)37 inline void applyOpParams(SkRegion::Op op, ClipAA aa, IsRect rect) { 38 fAA |= (bool) aa; 39 fIsRect &= (op == SkRegion::kIntersect_Op && (bool) rect); 40 } 41 42 public: isEmpty()43 bool isEmpty() const { return fBounds.isEmpty(); } isRect()44 bool isRect() const { return fIsRect; } isAA()45 bool isAA() const { return fAA; } getBounds()46 const SkIRect& getBounds() const { return fBounds; } 47 setEmpty()48 void setEmpty() { this->setRect(SkIRect::MakeEmpty()); } setRect(const SkIRect & r)49 void setRect(const SkIRect& r) { 50 fBounds = r; 51 fIsRect = true; 52 fAA = false; 53 } setDeviceClipRestriction(const SkIRect * rect)54 void setDeviceClipRestriction(const SkIRect* rect) { 55 fClipRestrictionRect = rect; 56 } 57 opShader(sk_sp<SkShader>)58 void opShader(sk_sp<SkShader>) { 59 fIsRect = false; 60 } 61 void opRect(const SkRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA); 62 void opRRect(const SkRRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA); 63 void opPath(const SkPath&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA); 64 void opRegion(const SkRegion&, SkRegion::Op); 65 void opIRect(const SkIRect&, SkRegion::Op); 66 }; 67 68 /** 69 * Wraps a SkRegion and SkAAClip, so we have a single object that can represent either our 70 * BW or antialiased clips. 71 * 72 * This class is optimized for the raster backend of canvas, but can be expense to keep up2date, 73 * so it supports a runtime option (force-conservative-rects) to turn it into a super-fast 74 * rect-only tracker. The gpu backend uses this since it does not need the result (it uses 75 * SkClipStack instead). 76 */ 77 class SkRasterClip { 78 public: 79 SkRasterClip(); 80 SkRasterClip(const SkIRect&); 81 SkRasterClip(const SkRegion&); 82 SkRasterClip(const SkRasterClip&); 83 SkRasterClip& operator=(const SkRasterClip&); 84 ~SkRasterClip(); 85 86 // Only compares the current state. Does not compare isForceConservativeRects(), so that field 87 // could be different but this could still return true. 88 bool operator==(const SkRasterClip&) const; 89 bool operator!=(const SkRasterClip& other) const { 90 return !(*this == other); 91 } 92 isBW()93 bool isBW() const { return fIsBW; } isAA()94 bool isAA() const { return !fIsBW; } bwRgn()95 const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; } aaRgn()96 const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; } 97 isEmpty()98 bool isEmpty() const { 99 SkASSERT(this->computeIsEmpty() == fIsEmpty); 100 return fIsEmpty; 101 } 102 isRect()103 bool isRect() const { 104 SkASSERT(this->computeIsRect() == fIsRect); 105 return fIsRect; 106 } 107 108 bool isComplex() const; 109 const SkIRect& getBounds() const; 110 111 bool setEmpty(); 112 bool setRect(const SkIRect&); 113 114 bool op(const SkIRect&, SkRegion::Op); 115 bool op(const SkRegion&, SkRegion::Op); 116 bool op(const SkRect&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA); 117 bool op(const SkRRect&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA); 118 bool op(const SkPath&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA); 119 bool op(sk_sp<SkShader>); 120 121 void translate(int dx, int dy, SkRasterClip* dst) const; translate(int dx,int dy)122 void translate(int dx, int dy) { 123 this->translate(dx, dy, this); 124 } 125 126 bool quickContains(const SkIRect& rect) const; quickContains(int left,int top,int right,int bottom)127 bool quickContains(int left, int top, int right, int bottom) const { 128 return quickContains(SkIRect::MakeLTRB(left, top, right, bottom)); 129 } 130 131 /** 132 * Return true if this region is empty, or if the specified rectangle does 133 * not intersect the region. Returning false is not a guarantee that they 134 * intersect, but returning true is a guarantee that they do not. 135 */ quickReject(const SkIRect & rect)136 bool quickReject(const SkIRect& rect) const { 137 return !SkIRect::Intersects(this->getBounds(), rect); 138 } 139 140 // hack for SkCanvas::getTotalClip 141 const SkRegion& forceGetBW(); 142 143 #ifdef SK_DEBUG 144 void validate() const; 145 #else validate()146 void validate() const {} 147 #endif 148 setDeviceClipRestriction(const SkIRect * rect)149 void setDeviceClipRestriction(const SkIRect* rect) { 150 fClipRestrictionRect = rect; 151 } 152 clipShader()153 sk_sp<SkShader> clipShader() const { return fShader; } 154 155 private: 156 SkRegion fBW; 157 SkAAClip fAA; 158 bool fIsBW; 159 // these 2 are caches based on querying the right obj based on fIsBW 160 bool fIsEmpty; 161 bool fIsRect; 162 const SkIRect* fClipRestrictionRect = nullptr; 163 // if present, this augments the clip, not replaces it 164 sk_sp<SkShader> fShader; 165 computeIsEmpty()166 bool computeIsEmpty() const { 167 return fIsBW ? fBW.isEmpty() : fAA.isEmpty(); 168 } 169 computeIsRect()170 bool computeIsRect() const { 171 return fIsBW ? fBW.isRect() : fAA.isRect(); 172 } 173 174 bool updateCacheAndReturnNonEmpty(bool detectAARect = true) { 175 fIsEmpty = this->computeIsEmpty(); 176 177 // detect that our computed AA is really just a (hard-edged) rect 178 if (detectAARect && !fIsEmpty && !fIsBW && fAA.isRect()) { 179 fBW.setRect(fAA.getBounds()); 180 fAA.setEmpty(); // don't need this anymore 181 fIsBW = true; 182 } 183 184 fIsRect = this->computeIsRect(); 185 return !fIsEmpty; 186 } 187 188 void convertToAA(); 189 190 bool setPath(const SkPath& path, const SkRegion& clip, bool doAA); 191 bool setPath(const SkPath& path, const SkIRect& clip, bool doAA); 192 bool op(const SkRasterClip&, SkRegion::Op); 193 bool setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse); 194 applyClipRestriction(SkRegion::Op op,SkIRect * bounds)195 inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) { 196 if (op >= SkRegion::kUnion_Op && fClipRestrictionRect 197 && !fClipRestrictionRect->isEmpty()) { 198 if (!bounds->intersect(*fClipRestrictionRect)) { 199 bounds->setEmpty(); 200 } 201 } 202 } 203 applyClipRestriction(SkRegion::Op op,SkRect * bounds)204 inline void applyClipRestriction(SkRegion::Op op, SkRect* bounds) { 205 if (op >= SkRegion::kUnion_Op && fClipRestrictionRect 206 && !fClipRestrictionRect->isEmpty()) { 207 if (!bounds->intersect(SkRect::Make(*fClipRestrictionRect))) { 208 bounds->setEmpty(); 209 } 210 } 211 } 212 }; 213 214 class SkAutoRasterClipValidate : SkNoncopyable { 215 public: SkAutoRasterClipValidate(const SkRasterClip & rc)216 SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) { 217 fRC.validate(); 218 } ~SkAutoRasterClipValidate()219 ~SkAutoRasterClipValidate() { 220 fRC.validate(); 221 } 222 private: 223 const SkRasterClip& fRC; 224 }; 225 226 #ifdef SK_DEBUG 227 #define AUTO_RASTERCLIP_VALIDATE(rc) SkAutoRasterClipValidate arcv(rc) 228 #else 229 #define AUTO_RASTERCLIP_VALIDATE(rc) 230 #endif 231 232 /////////////////////////////////////////////////////////////////////////////// 233 234 /** 235 * Encapsulates the logic of deciding if we need to change/wrap the blitter 236 * for aaclipping. If so, getRgn and getBlitter return modified values. If 237 * not, they return the raw blitter and (bw) clip region. 238 * 239 * We need to keep the constructor/destructor cost as small as possible, so we 240 * can freely put this on the stack, and not pay too much for the case when 241 * we're really BW anyways. 242 */ 243 class SkAAClipBlitterWrapper { 244 public: 245 SkAAClipBlitterWrapper(); 246 SkAAClipBlitterWrapper(const SkRasterClip&, SkBlitter*); 247 SkAAClipBlitterWrapper(const SkAAClip*, SkBlitter*); 248 249 void init(const SkRasterClip&, SkBlitter*); 250 getBounds()251 const SkIRect& getBounds() const { 252 SkASSERT(fClipRgn); 253 return fClipRgn->getBounds(); 254 } getRgn()255 const SkRegion& getRgn() const { 256 SkASSERT(fClipRgn); 257 return *fClipRgn; 258 } getBlitter()259 SkBlitter* getBlitter() { 260 SkASSERT(fBlitter); 261 return fBlitter; 262 } 263 264 private: 265 SkRegion fBWRgn; 266 SkAAClipBlitter fAABlitter; 267 // what we return 268 const SkRegion* fClipRgn; 269 SkBlitter* fBlitter; 270 }; 271 272 #endif 273