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