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