| 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 |  | 
|---|
| 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: | 
|---|
| 32 | SkConservativeClip() : fBounds(SkIRect::MakeEmpty()), fClipRestrictionRect(nullptr) {} | 
|---|
| 33 |  | 
|---|
| 34 | bool isEmpty() const { return fBounds.isEmpty(); } | 
|---|
| 35 | bool isRect() const { return true; } | 
|---|
| 36 | const SkIRect& getBounds() const { return fBounds; } | 
|---|
| 37 |  | 
|---|
| 38 | void setEmpty() { fBounds.setEmpty(); } | 
|---|
| 39 | void setRect(const SkIRect& r) { fBounds = r; } | 
|---|
| 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 |  | 
|---|
| 76 | bool isBW() const { return fIsBW; } | 
|---|
| 77 | bool isAA() const { return !fIsBW; } | 
|---|
| 78 | const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; } | 
|---|
| 79 | const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; } | 
|---|
| 80 |  | 
|---|
| 81 | bool isEmpty() const { | 
|---|
| 82 | SkASSERT(this->computeIsEmpty() == fIsEmpty); | 
|---|
| 83 | return fIsEmpty; | 
|---|
| 84 | } | 
|---|
| 85 |  | 
|---|
| 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; | 
|---|
| 105 | void translate(int dx, int dy) { | 
|---|
| 106 | this->translate(dx, dy, this); | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | bool quickContains(const SkIRect& rect) const; | 
|---|
| 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 | */ | 
|---|
| 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 | 
|---|
| 129 | void validate() const {} | 
|---|
| 130 | #endif | 
|---|
| 131 |  | 
|---|
| 132 | void setDeviceClipRestriction(const SkIRect* rect) { | 
|---|
| 133 | fClipRestrictionRect = rect; | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 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 |  | 
|---|
| 149 | bool computeIsEmpty() const { | 
|---|
| 150 | return fIsBW ? fBW.isEmpty() : fAA.isEmpty(); | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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: | 
|---|
| 199 | SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) { | 
|---|
| 200 | fRC.validate(); | 
|---|
| 201 | } | 
|---|
| 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 |  | 
|---|
| 234 | const SkIRect& getBounds() const { | 
|---|
| 235 | SkASSERT(fClipRgn); | 
|---|
| 236 | return fClipRgn->getBounds(); | 
|---|
| 237 | } | 
|---|
| 238 | const SkRegion& getRgn() const { | 
|---|
| 239 | SkASSERT(fClipRgn); | 
|---|
| 240 | return *fClipRgn; | 
|---|
| 241 | } | 
|---|
| 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 |  | 
|---|