• 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 #include "SkRasterClip.h"
9 
10 
SkRasterClip()11 SkRasterClip::SkRasterClip() {
12     fIsBW = true;
13     fIsEmpty = true;
14     fIsRect = false;
15     SkDEBUGCODE(this->validate();)
16 }
17 
SkRasterClip(const SkRasterClip & src)18 SkRasterClip::SkRasterClip(const SkRasterClip& src) {
19     AUTO_RASTERCLIP_VALIDATE(src);
20 
21     fIsBW = src.fIsBW;
22     if (fIsBW) {
23         fBW = src.fBW;
24     } else {
25         fAA = src.fAA;
26     }
27 
28     fIsEmpty = src.isEmpty();
29     fIsRect = src.isRect();
30     SkDEBUGCODE(this->validate();)
31 }
32 
SkRasterClip(const SkIRect & bounds)33 SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
34     fIsBW = true;
35     fIsEmpty = this->computeIsEmpty();  // bounds might be empty, so compute
36     fIsRect = !fIsEmpty;
37     SkDEBUGCODE(this->validate();)
38 }
39 
~SkRasterClip()40 SkRasterClip::~SkRasterClip() {
41     SkDEBUGCODE(this->validate();)
42 }
43 
isComplex() const44 bool SkRasterClip::isComplex() const {
45     return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
46 }
47 
getBounds() const48 const SkIRect& SkRasterClip::getBounds() const {
49     return fIsBW ? fBW.getBounds() : fAA.getBounds();
50 }
51 
setEmpty()52 bool SkRasterClip::setEmpty() {
53     AUTO_RASTERCLIP_VALIDATE(*this);
54 
55     fIsBW = true;
56     fBW.setEmpty();
57     fAA.setEmpty();
58     fIsEmpty = true;
59     fIsRect = false;
60     return false;
61 }
62 
setRect(const SkIRect & rect)63 bool SkRasterClip::setRect(const SkIRect& rect) {
64     AUTO_RASTERCLIP_VALIDATE(*this);
65 
66     fIsBW = true;
67     fAA.setEmpty();
68     fIsRect = fBW.setRect(rect);
69     fIsEmpty = !fIsRect;
70     return fIsRect;
71 }
72 
setPath(const SkPath & path,const SkRegion & clip,bool doAA)73 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
74     AUTO_RASTERCLIP_VALIDATE(*this);
75 
76     if (this->isBW() && !doAA) {
77         (void)fBW.setPath(path, clip);
78     } else {
79         // TODO: since we are going to over-write fAA completely (aren't we?)
80         // we should just clear our BW data (if any) and set fIsAA=true
81         if (this->isBW()) {
82             this->convertToAA();
83         }
84         (void)fAA.setPath(path, &clip, doAA);
85     }
86     return this->updateCacheAndReturnNonEmpty();
87 }
88 
setPath(const SkPath & path,const SkIRect & clip,bool doAA)89 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
90     SkRegion tmp;
91     tmp.setRect(clip);
92     return this->setPath(path, tmp, doAA);
93 }
94 
op(const SkIRect & rect,SkRegion::Op op)95 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
96     AUTO_RASTERCLIP_VALIDATE(*this);
97 
98     fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
99     return this->updateCacheAndReturnNonEmpty();
100 }
101 
op(const SkRegion & rgn,SkRegion::Op op)102 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
103     AUTO_RASTERCLIP_VALIDATE(*this);
104 
105     if (fIsBW) {
106         (void)fBW.op(rgn, op);
107     } else {
108         SkAAClip tmp;
109         tmp.setRegion(rgn);
110         (void)fAA.op(tmp, op);
111     }
112     return this->updateCacheAndReturnNonEmpty();
113 }
114 
op(const SkRasterClip & clip,SkRegion::Op op)115 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
116     AUTO_RASTERCLIP_VALIDATE(*this);
117     clip.validate();
118 
119     if (this->isBW() && clip.isBW()) {
120         (void)fBW.op(clip.fBW, op);
121     } else {
122         SkAAClip tmp;
123         const SkAAClip* other;
124 
125         if (this->isBW()) {
126             this->convertToAA();
127         }
128         if (clip.isBW()) {
129             tmp.setRegion(clip.bwRgn());
130             other = &tmp;
131         } else {
132             other = &clip.aaRgn();
133         }
134         (void)fAA.op(*other, op);
135     }
136     return this->updateCacheAndReturnNonEmpty();
137 }
138 
139 /**
140  *  Our antialiasing currently has a granularity of 1/4 of a pixel along each
141  *  axis. Thus we can treat an axis coordinate as an integer if it differs
142  *  from its nearest int by < half of that value (1.8 in this case).
143  */
nearly_integral(SkScalar x)144 static bool nearly_integral(SkScalar x) {
145     static const SkScalar domain = SK_Scalar1 / 4;
146     static const SkScalar halfDomain = domain / 2;
147 
148     x += halfDomain;
149     return x - SkScalarFloorToScalar(x) < domain;
150 }
151 
op(const SkRect & r,SkRegion::Op op,bool doAA)152 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
153     AUTO_RASTERCLIP_VALIDATE(*this);
154 
155     if (fIsBW && doAA) {
156         // check that the rect really needs aa, or is it close enought to
157         // integer boundaries that we can just treat it as a BW rect?
158         if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
159             nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
160             doAA = false;
161         }
162     }
163 
164     if (fIsBW && !doAA) {
165         SkIRect ir;
166         r.round(&ir);
167         (void)fBW.op(ir, op);
168     } else {
169         if (fIsBW) {
170             this->convertToAA();
171         }
172         (void)fAA.op(r, op, doAA);
173     }
174     return this->updateCacheAndReturnNonEmpty();
175 }
176 
translate(int dx,int dy,SkRasterClip * dst) const177 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
178     if (NULL == dst) {
179         return;
180     }
181 
182     AUTO_RASTERCLIP_VALIDATE(*this);
183 
184     if (this->isEmpty()) {
185         dst->setEmpty();
186         return;
187     }
188     if (0 == (dx | dy)) {
189         *dst = *this;
190         return;
191     }
192 
193     dst->fIsBW = fIsBW;
194     if (fIsBW) {
195         fBW.translate(dx, dy, &dst->fBW);
196         dst->fAA.setEmpty();
197     } else {
198         fAA.translate(dx, dy, &dst->fAA);
199         dst->fBW.setEmpty();
200     }
201     dst->updateCacheAndReturnNonEmpty();
202 }
203 
quickContains(const SkIRect & ir) const204 bool SkRasterClip::quickContains(const SkIRect& ir) const {
205     return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
206 }
207 
208 ///////////////////////////////////////////////////////////////////////////////
209 
forceGetBW()210 const SkRegion& SkRasterClip::forceGetBW() {
211     AUTO_RASTERCLIP_VALIDATE(*this);
212 
213     if (!fIsBW) {
214         fBW.setRect(fAA.getBounds());
215     }
216     return fBW;
217 }
218 
convertToAA()219 void SkRasterClip::convertToAA() {
220     AUTO_RASTERCLIP_VALIDATE(*this);
221 
222     SkASSERT(fIsBW);
223     fAA.setRegion(fBW);
224     fIsBW = false;
225     (void)this->updateCacheAndReturnNonEmpty();
226 }
227 
228 #ifdef SK_DEBUG
validate() const229 void SkRasterClip::validate() const {
230     // can't ever assert that fBW is empty, since we may have called forceGetBW
231     if (fIsBW) {
232         SkASSERT(fAA.isEmpty());
233     }
234 
235     fBW.validate();
236     fAA.validate();
237 
238     SkASSERT(this->computeIsEmpty() == fIsEmpty);
239     SkASSERT(this->computeIsRect() == fIsRect);
240 }
241 #endif
242 
243 ///////////////////////////////////////////////////////////////////////////////
244 
SkAAClipBlitterWrapper()245 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
246     SkDEBUGCODE(fClipRgn = NULL;)
247     SkDEBUGCODE(fBlitter = NULL;)
248 }
249 
SkAAClipBlitterWrapper(const SkRasterClip & clip,SkBlitter * blitter)250 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
251                                                SkBlitter* blitter) {
252     this->init(clip, blitter);
253 }
254 
SkAAClipBlitterWrapper(const SkAAClip * aaclip,SkBlitter * blitter)255 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
256                                                SkBlitter* blitter) {
257     SkASSERT(blitter);
258     SkASSERT(aaclip);
259     fBWRgn.setRect(aaclip->getBounds());
260     fAABlitter.init(blitter, aaclip);
261     // now our return values
262     fClipRgn = &fBWRgn;
263     fBlitter = &fAABlitter;
264 }
265 
init(const SkRasterClip & clip,SkBlitter * blitter)266 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
267     SkASSERT(blitter);
268     if (clip.isBW()) {
269         fClipRgn = &clip.bwRgn();
270         fBlitter = blitter;
271     } else {
272         const SkAAClip& aaclip = clip.aaRgn();
273         fBWRgn.setRect(aaclip.getBounds());
274         fAABlitter.init(blitter, &aaclip);
275         // now our return values
276         fClipRgn = &fBWRgn;
277         fBlitter = &fAABlitter;
278     }
279 }
280