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