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