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