blob: 09da0f7bab4935f2fccbec62648310eb21aa28a3 [file] [log] [blame]
reed@google.comd1e3c5f2011-10-10 19:36:25 +00001/*
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
11SkRasterClip::SkRasterClip() {
12 fIsBW = true;
reed@google.coma1c6ff42012-05-11 14:36:57 +000013 fIsEmpty = true;
14 fIsRect = false;
15 SkDEBUGCODE(this->validate();)
reed@google.comd1e3c5f2011-10-10 19:36:25 +000016}
17
reed@google.com34f7e472011-10-13 15:11:59 +000018SkRasterClip::SkRasterClip(const SkRasterClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +000019 AUTO_RASTERCLIP_VALIDATE(src);
20
reed@google.com34f7e472011-10-13 15:11:59 +000021 fIsBW = src.fIsBW;
22 if (fIsBW) {
23 fBW = src.fBW;
24 } else {
25 fAA = src.fAA;
26 }
reed@google.coma1c6ff42012-05-11 14:36:57 +000027
28 fIsEmpty = src.isEmpty();
29 fIsRect = src.isRect();
30 SkDEBUGCODE(this->validate();)
reed@google.com34f7e472011-10-13 15:11:59 +000031}
32
reed@google.comba16da92011-10-11 13:15:03 +000033SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
34 fIsBW = true;
reed@google.coma1c6ff42012-05-11 14:36:57 +000035 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
36 fIsRect = !fIsEmpty;
37 SkDEBUGCODE(this->validate();)
reed@google.comba16da92011-10-11 13:15:03 +000038}
39
reed@google.com045e62d2011-10-24 12:19:46 +000040SkRasterClip::~SkRasterClip() {
reed@google.coma1c6ff42012-05-11 14:36:57 +000041 SkDEBUGCODE(this->validate();)
reed@google.comd1e3c5f2011-10-10 19:36:25 +000042}
43
44bool SkRasterClip::isComplex() const {
45 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
46}
47
48const SkIRect& SkRasterClip::getBounds() const {
49 return fIsBW ? fBW.getBounds() : fAA.getBounds();
50}
51
52bool SkRasterClip::setEmpty() {
reed@google.com045e62d2011-10-24 12:19:46 +000053 AUTO_RASTERCLIP_VALIDATE(*this);
54
reed@google.comd1e3c5f2011-10-10 19:36:25 +000055 fIsBW = true;
56 fBW.setEmpty();
57 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +000058 fIsEmpty = true;
59 fIsRect = false;
reed@google.comd1e3c5f2011-10-10 19:36:25 +000060 return false;
61}
62
reed@google.comba16da92011-10-11 13:15:03 +000063bool SkRasterClip::setRect(const SkIRect& rect) {
reed@google.com045e62d2011-10-24 12:19:46 +000064 AUTO_RASTERCLIP_VALIDATE(*this);
65
reed@google.comd1e3c5f2011-10-10 19:36:25 +000066 fIsBW = true;
67 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +000068 fIsRect = fBW.setRect(rect);
69 fIsEmpty = !fIsRect;
70 return fIsRect;
reed@google.comd1e3c5f2011-10-10 19:36:25 +000071}
72
73bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +000074 AUTO_RASTERCLIP_VALIDATE(*this);
75
reed@google.comd1e3c5f2011-10-10 19:36:25 +000076 if (this->isBW() && !doAA) {
reed@google.coma1c6ff42012-05-11 14:36:57 +000077 (void)fBW.setPath(path, clip);
reed@google.comd1e3c5f2011-10-10 19:36:25 +000078 } else {
reed@google.com897fc412012-02-16 17:11:25 +000079 // 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
reed@google.comd1e3c5f2011-10-10 19:36:25 +000081 if (this->isBW()) {
82 this->convertToAA();
83 }
reed@google.coma1c6ff42012-05-11 14:36:57 +000084 (void)fAA.setPath(path, &clip, doAA);
reed@google.comd1e3c5f2011-10-10 19:36:25 +000085 }
reed@google.coma1c6ff42012-05-11 14:36:57 +000086 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +000087}
88
89bool 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
95bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip,
96 bool doAA) {
97 if (clip.isBW()) {
98 return this->setPath(path, clip.bwRgn(), doAA);
99 } else {
100 SkRegion tmp;
101 tmp.setRect(clip.getBounds());
102 if (!this->setPath(path, clip, doAA)) {
103 return false;
104 }
105 return this->op(clip, SkRegion::kIntersect_Op);
106 }
107}
108
109bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000110 AUTO_RASTERCLIP_VALIDATE(*this);
111
reed@google.coma1c6ff42012-05-11 14:36:57 +0000112 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
113 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000114}
115
reed@google.comba16da92011-10-11 13:15:03 +0000116bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000117 AUTO_RASTERCLIP_VALIDATE(*this);
118
reed@google.comba16da92011-10-11 13:15:03 +0000119 if (fIsBW) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000120 (void)fBW.op(rgn, op);
reed@google.comba16da92011-10-11 13:15:03 +0000121 } else {
122 SkAAClip tmp;
123 tmp.setRegion(rgn);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000124 (void)fAA.op(tmp, op);
reed@google.comba16da92011-10-11 13:15:03 +0000125 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000126 return this->updateCacheAndReturnNonEmpty();
reed@google.comba16da92011-10-11 13:15:03 +0000127}
128
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000129bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000130 AUTO_RASTERCLIP_VALIDATE(*this);
131 clip.validate();
132
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000133 if (this->isBW() && clip.isBW()) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000134 (void)fBW.op(clip.fBW, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000135 } else {
136 SkAAClip tmp;
137 const SkAAClip* other;
138
139 if (this->isBW()) {
140 this->convertToAA();
141 }
142 if (clip.isBW()) {
143 tmp.setRegion(clip.bwRgn());
144 other = &tmp;
145 } else {
146 other = &clip.aaRgn();
147 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000148 (void)fAA.op(*other, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000149 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000150 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000151}
152
reed@google.com045e62d2011-10-24 12:19:46 +0000153// return true if x is nearly integral (within 1/16) since that is the highest
reed@google.com00177082011-10-12 14:34:30 +0000154// precision our aa code can have.
155static bool is_integral(SkScalar x) {
156 int ix = SkScalarRoundToInt(x);
157 SkScalar sx = SkIntToScalar(ix);
reed@google.com045e62d2011-10-24 12:19:46 +0000158 return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
reed@google.com00177082011-10-12 14:34:30 +0000159}
160
161bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000162 AUTO_RASTERCLIP_VALIDATE(*this);
163
reed@google.com00177082011-10-12 14:34:30 +0000164 if (doAA) {
165 // check that the rect really needs aa
166 if (is_integral(r.fLeft) && is_integral(r.fTop) &&
167 is_integral(r.fRight) && is_integral(r.fBottom)) {
168 doAA = false;
169 }
170 }
171
172 if (fIsBW && !doAA) {
173 SkIRect ir;
174 r.round(&ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000175 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000176 } else {
177 if (fIsBW) {
178 this->convertToAA();
179 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000180 (void)fAA.op(r, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000181 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000182 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000183}
184
reed@google.com34f7e472011-10-13 15:11:59 +0000185void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
186 if (NULL == dst) {
187 return;
188 }
189
reed@google.com045e62d2011-10-24 12:19:46 +0000190 AUTO_RASTERCLIP_VALIDATE(*this);
191
reed@google.com34f7e472011-10-13 15:11:59 +0000192 if (this->isEmpty()) {
193 dst->setEmpty();
194 return;
195 }
196 if (0 == (dx | dy)) {
197 *dst = *this;
198 return;
199 }
200
201 dst->fIsBW = fIsBW;
202 if (fIsBW) {
203 fBW.translate(dx, dy, &dst->fBW);
204 dst->fAA.setEmpty();
205 } else {
206 fAA.translate(dx, dy, &dst->fAA);
207 dst->fBW.setEmpty();
208 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000209 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000210}
211
reed@google.com045e62d2011-10-24 12:19:46 +0000212bool SkRasterClip::quickContains(const SkIRect& ir) const {
213 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
214}
215
reed@google.com34f7e472011-10-13 15:11:59 +0000216///////////////////////////////////////////////////////////////////////////////
217
reed@google.comba16da92011-10-11 13:15:03 +0000218const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000219 AUTO_RASTERCLIP_VALIDATE(*this);
220
reed@google.comba16da92011-10-11 13:15:03 +0000221 if (!fIsBW) {
222 fBW.setRect(fAA.getBounds());
223 }
224 return fBW;
225}
226
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000227void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000228 AUTO_RASTERCLIP_VALIDATE(*this);
229
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000230 SkASSERT(fIsBW);
231 fAA.setRegion(fBW);
232 fIsBW = false;
reed@google.coma1c6ff42012-05-11 14:36:57 +0000233 (void)this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000234}
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236#ifdef SK_DEBUG
237void SkRasterClip::validate() const {
238 // can't ever assert that fBW is empty, since we may have called forceGetBW
239 if (fIsBW) {
240 SkASSERT(fAA.isEmpty());
241 }
242
243 fBW.validate();
244 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000245
246 SkASSERT(this->computeIsEmpty() == fIsEmpty);
247 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000248}
249#endif
250
251///////////////////////////////////////////////////////////////////////////////
252
253SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
254 SkDEBUGCODE(fClipRgn = NULL;)
255 SkDEBUGCODE(fBlitter = NULL;)
256}
257
258SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
259 SkBlitter* blitter) {
260 this->init(clip, blitter);
261}
262
263SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
264 SkBlitter* blitter) {
265 SkASSERT(blitter);
266 SkASSERT(aaclip);
267 fBWRgn.setRect(aaclip->getBounds());
268 fAABlitter.init(blitter, aaclip);
269 // now our return values
270 fClipRgn = &fBWRgn;
271 fBlitter = &fAABlitter;
272}
273
274void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
275 SkASSERT(blitter);
276 if (clip.isBW()) {
277 fClipRgn = &clip.bwRgn();
278 fBlitter = blitter;
279 } else {
280 const SkAAClip& aaclip = clip.aaRgn();
281 fBWRgn.setRect(aaclip.getBounds());
282 fAABlitter.init(blitter, &aaclip);
283 // now our return values
284 fClipRgn = &fBWRgn;
285 fBlitter = &fAABlitter;
286 }
287}
288