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