• 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 "SkRegion.h"
12 #include "SkAAClip.h"
13 
14 class SkRRect;
15 
16 class SkConservativeClip {
17     SkIRect         fBounds;
18     const SkIRect*  fClipRestrictionRect;
19 
applyClipRestriction(SkRegion::Op op,SkIRect * bounds)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:
SkConservativeClip()30     SkConservativeClip() : fBounds(SkIRect::MakeEmpty()), fClipRestrictionRect(nullptr) {}
31 
isEmpty()32     bool isEmpty() const { return fBounds.isEmpty(); }
isRect()33     bool isRect() const { return true; }
getBounds()34     const SkIRect& getBounds() const { return fBounds; }
35 
setEmpty()36     void setEmpty() { fBounds.setEmpty(); }
setRect(const SkIRect & r)37     void setRect(const SkIRect& r) { fBounds = r; }
setDeviceClipRestriction(const SkIRect * rect)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 
isBW()73     bool isBW() const { return fIsBW; }
isAA()74     bool isAA() const { return !fIsBW; }
bwRgn()75     const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
aaRgn()76     const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; }
77 
isEmpty()78     bool isEmpty() const {
79         SkASSERT(this->computeIsEmpty() == fIsEmpty);
80         return fIsEmpty;
81     }
82 
isRect()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;
translate(int dx,int dy)101     void translate(int dx, int dy) {
102         this->translate(dx, dy, this);
103     }
104 
105     bool quickContains(const SkIRect& rect) const;
quickContains(int left,int top,int right,int bottom)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      */
quickReject(const SkIRect & rect)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
validate()125     void validate() const {}
126 #endif
127 
setDeviceClipRestriction(const SkIRect * rect)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 
computeIsEmpty()141     bool computeIsEmpty() const {
142         return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
143     }
144 
computeIsRect()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 
applyClipRestriction(SkRegion::Op op,SkIRect * bounds)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 
applyClipRestriction(SkRegion::Op op,SkRect * bounds)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:
SkAutoRasterClipValidate(const SkRasterClip & rc)191     SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) {
192         fRC.validate();
193     }
~SkAutoRasterClipValidate()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 
getBounds()227     const SkIRect& getBounds() const {
228         SkASSERT(fClipRgn);
229         return fClipRgn->getBounds();
230     }
getRgn()231     const SkRegion& getRgn() const {
232         SkASSERT(fClipRgn);
233         return *fClipRgn;
234     }
getBlitter()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