• 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 }
14 
SkRasterClip(const SkRasterClip & src)15 SkRasterClip::SkRasterClip(const SkRasterClip& src) {
16     AUTO_RASTERCLIP_VALIDATE(src);
17 
18     fIsBW = src.fIsBW;
19     if (fIsBW) {
20         fBW = src.fBW;
21     } else {
22         fAA = src.fAA;
23     }
24 }
25 
SkRasterClip(const SkIRect & bounds)26 SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
27     fIsBW = true;
28 }
29 
~SkRasterClip()30 SkRasterClip::~SkRasterClip() {
31     AUTO_RASTERCLIP_VALIDATE(*this);
32 }
33 
isEmpty() const34 bool SkRasterClip::isEmpty() const {
35     return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
36 }
37 
isRect() const38 bool SkRasterClip::isRect() const {
39     return fIsBW ? fBW.isRect() : false;
40 }
41 
isComplex() const42 bool SkRasterClip::isComplex() const {
43     return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
44 }
45 
getBounds() const46 const SkIRect& SkRasterClip::getBounds() const {
47     return fIsBW ? fBW.getBounds() : fAA.getBounds();
48 }
49 
setEmpty()50 bool SkRasterClip::setEmpty() {
51     AUTO_RASTERCLIP_VALIDATE(*this);
52 
53     fIsBW = true;
54     fBW.setEmpty();
55     fAA.setEmpty();
56     return false;
57 }
58 
setRect(const SkIRect & rect)59 bool SkRasterClip::setRect(const SkIRect& rect) {
60     AUTO_RASTERCLIP_VALIDATE(*this);
61 
62     fIsBW = true;
63     fAA.setEmpty();
64     return fBW.setRect(rect);
65 }
66 
setPath(const SkPath & path,const SkRegion & clip,bool doAA)67 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
68     AUTO_RASTERCLIP_VALIDATE(*this);
69 
70     if (this->isBW() && !doAA) {
71         return fBW.setPath(path, clip);
72     } else {
73         // TODO: since we are going to over-write fAA completely (aren't we?)
74         // we should just clear our BW data (if any) and set fIsAA=true
75         if (this->isBW()) {
76             this->convertToAA();
77         }
78         return fAA.setPath(path, &clip, doAA);
79     }
80 }
81 
setPath(const SkPath & path,const SkIRect & clip,bool doAA)82 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
83     SkRegion tmp;
84     tmp.setRect(clip);
85     return this->setPath(path, tmp, doAA);
86 }
87 
setPath(const SkPath & path,const SkRasterClip & clip,bool doAA)88 bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip,
89                            bool doAA) {
90     if (clip.isBW()) {
91         return this->setPath(path, clip.bwRgn(), doAA);
92     } else {
93         SkRegion tmp;
94         tmp.setRect(clip.getBounds());
95         if (!this->setPath(path, clip, doAA)) {
96             return false;
97         }
98         return this->op(clip, SkRegion::kIntersect_Op);
99     }
100 }
101 
op(const SkIRect & rect,SkRegion::Op op)102 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
103     AUTO_RASTERCLIP_VALIDATE(*this);
104 
105     return fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
106 }
107 
op(const SkRegion & rgn,SkRegion::Op op)108 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
109     AUTO_RASTERCLIP_VALIDATE(*this);
110 
111     if (fIsBW) {
112         return fBW.op(rgn, op);
113     } else {
114         SkAAClip tmp;
115         tmp.setRegion(rgn);
116         return fAA.op(tmp, op);
117     }
118 }
119 
op(const SkRasterClip & clip,SkRegion::Op op)120 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
121     AUTO_RASTERCLIP_VALIDATE(*this);
122     clip.validate();
123 
124     if (this->isBW() && clip.isBW()) {
125         return fBW.op(clip.fBW, op);
126     } else {
127         SkAAClip tmp;
128         const SkAAClip* other;
129 
130         if (this->isBW()) {
131             this->convertToAA();
132         }
133         if (clip.isBW()) {
134             tmp.setRegion(clip.bwRgn());
135             other = &tmp;
136         } else {
137             other = &clip.aaRgn();
138         }
139         return fAA.op(*other, op);
140     }
141 }
142 
143 // return true if x is nearly integral (within 1/16) since that is the highest
144 // precision our aa code can have.
is_integral(SkScalar x)145 static bool is_integral(SkScalar x) {
146     int ix = SkScalarRoundToInt(x);
147     SkScalar sx = SkIntToScalar(ix);
148     return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
149 }
150 
op(const SkRect & r,SkRegion::Op op,bool doAA)151 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
152     AUTO_RASTERCLIP_VALIDATE(*this);
153 
154     if (doAA) {
155         // check that the rect really needs aa
156         if (is_integral(r.fLeft) && is_integral(r.fTop) &&
157             is_integral(r.fRight) && is_integral(r.fBottom)) {
158             doAA = false;
159         }
160     }
161 
162     if (fIsBW && !doAA) {
163         SkIRect ir;
164         r.round(&ir);
165         return fBW.op(ir, op);
166     } else {
167         if (fIsBW) {
168             this->convertToAA();
169         }
170         return fAA.op(r, op, doAA);
171     }
172 }
173 
translate(int dx,int dy,SkRasterClip * dst) const174 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
175     if (NULL == dst) {
176         return;
177     }
178 
179     AUTO_RASTERCLIP_VALIDATE(*this);
180 
181     if (this->isEmpty()) {
182         dst->setEmpty();
183         return;
184     }
185     if (0 == (dx | dy)) {
186         *dst = *this;
187         return;
188     }
189 
190     dst->fIsBW = fIsBW;
191     if (fIsBW) {
192         fBW.translate(dx, dy, &dst->fBW);
193         dst->fAA.setEmpty();
194     } else {
195         fAA.translate(dx, dy, &dst->fAA);
196         dst->fBW.setEmpty();
197     }
198 }
199 
quickContains(const SkIRect & ir) const200 bool SkRasterClip::quickContains(const SkIRect& ir) const {
201     return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
202 }
203 
204 ///////////////////////////////////////////////////////////////////////////////
205 
forceGetBW()206 const SkRegion& SkRasterClip::forceGetBW() {
207     AUTO_RASTERCLIP_VALIDATE(*this);
208 
209     if (!fIsBW) {
210         fBW.setRect(fAA.getBounds());
211     }
212     return fBW;
213 }
214 
convertToAA()215 void SkRasterClip::convertToAA() {
216     AUTO_RASTERCLIP_VALIDATE(*this);
217 
218     SkASSERT(fIsBW);
219     fAA.setRegion(fBW);
220     fIsBW = false;
221 }
222 
223 #ifdef SK_DEBUG
validate() const224 void SkRasterClip::validate() const {
225     // can't ever assert that fBW is empty, since we may have called forceGetBW
226     if (fIsBW) {
227         SkASSERT(fAA.isEmpty());
228     }
229 
230     fBW.validate();
231     fAA.validate();
232 }
233 #endif
234 
235 ///////////////////////////////////////////////////////////////////////////////
236 
SkAAClipBlitterWrapper()237 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
238     SkDEBUGCODE(fClipRgn = NULL;)
239     SkDEBUGCODE(fBlitter = NULL;)
240 }
241 
SkAAClipBlitterWrapper(const SkRasterClip & clip,SkBlitter * blitter)242 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
243                                                SkBlitter* blitter) {
244     this->init(clip, blitter);
245 }
246 
SkAAClipBlitterWrapper(const SkAAClip * aaclip,SkBlitter * blitter)247 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
248                                                SkBlitter* blitter) {
249     SkASSERT(blitter);
250     SkASSERT(aaclip);
251     fBWRgn.setRect(aaclip->getBounds());
252     fAABlitter.init(blitter, aaclip);
253     // now our return values
254     fClipRgn = &fBWRgn;
255     fBlitter = &fAABlitter;
256 }
257 
init(const SkRasterClip & clip,SkBlitter * blitter)258 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
259     SkASSERT(blitter);
260     if (clip.isBW()) {
261         fClipRgn = &clip.bwRgn();
262         fBlitter = blitter;
263     } else {
264         const SkAAClip& aaclip = clip.aaRgn();
265         fBWRgn.setRect(aaclip.getBounds());
266         fAABlitter.init(blitter, &aaclip);
267         // now our return values
268         fClipRgn = &fBWRgn;
269         fBlitter = &fAABlitter;
270     }
271 }
272 
273