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