blob: 4312717a4491e1a668f399e6b96f50dadec133a5 [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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000020
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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000065
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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000111
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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000118
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.com18c464b2012-05-11 20:57:25 +0000153/**
154 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
155 * axis. Thus we can treat an axis coordinate as an integer if it differs
156 * from its nearest int by < half of that value (1.8 in this case).
157 */
158static bool nearly_integral(SkScalar x) {
159 static const SkScalar domain = SK_Scalar1 / 4;
160 static const SkScalar halfDomain = domain / 2;
161
162 x += halfDomain;
163 return x - SkScalarFloorToScalar(x) < domain;
reed@google.com00177082011-10-12 14:34:30 +0000164}
165
166bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000167 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000168
reed@google.com420f74f2012-05-11 18:46:43 +0000169 if (fIsBW && doAA) {
reed@google.com18c464b2012-05-11 20:57:25 +0000170 // check that the rect really needs aa, or is it close enought to
171 // integer boundaries that we can just treat it as a BW rect?
172 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
173 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
reed@google.com00177082011-10-12 14:34:30 +0000174 doAA = false;
175 }
176 }
177
178 if (fIsBW && !doAA) {
179 SkIRect ir;
180 r.round(&ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000181 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000182 } else {
183 if (fIsBW) {
184 this->convertToAA();
185 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000186 (void)fAA.op(r, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000187 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000188 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000189}
190
reed@google.com34f7e472011-10-13 15:11:59 +0000191void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
192 if (NULL == dst) {
193 return;
194 }
195
reed@google.com045e62d2011-10-24 12:19:46 +0000196 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000197
reed@google.com34f7e472011-10-13 15:11:59 +0000198 if (this->isEmpty()) {
199 dst->setEmpty();
200 return;
201 }
202 if (0 == (dx | dy)) {
203 *dst = *this;
204 return;
205 }
206
207 dst->fIsBW = fIsBW;
208 if (fIsBW) {
209 fBW.translate(dx, dy, &dst->fBW);
210 dst->fAA.setEmpty();
211 } else {
212 fAA.translate(dx, dy, &dst->fAA);
213 dst->fBW.setEmpty();
214 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000215 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000216}
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218bool SkRasterClip::quickContains(const SkIRect& ir) const {
219 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
220}
221
reed@google.com34f7e472011-10-13 15:11:59 +0000222///////////////////////////////////////////////////////////////////////////////
223
reed@google.comba16da92011-10-11 13:15:03 +0000224const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000225 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000226
reed@google.comba16da92011-10-11 13:15:03 +0000227 if (!fIsBW) {
228 fBW.setRect(fAA.getBounds());
229 }
230 return fBW;
231}
232
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000233void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000234 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000235
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000236 SkASSERT(fIsBW);
237 fAA.setRegion(fBW);
238 fIsBW = false;
reed@google.coma1c6ff42012-05-11 14:36:57 +0000239 (void)this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000240}
241
reed@google.com045e62d2011-10-24 12:19:46 +0000242#ifdef SK_DEBUG
243void SkRasterClip::validate() const {
244 // can't ever assert that fBW is empty, since we may have called forceGetBW
245 if (fIsBW) {
246 SkASSERT(fAA.isEmpty());
247 }
248
249 fBW.validate();
250 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000251
252 SkASSERT(this->computeIsEmpty() == fIsEmpty);
253 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000254}
255#endif
256
257///////////////////////////////////////////////////////////////////////////////
258
259SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
260 SkDEBUGCODE(fClipRgn = NULL;)
261 SkDEBUGCODE(fBlitter = NULL;)
262}
263
264SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
265 SkBlitter* blitter) {
266 this->init(clip, blitter);
267}
268
269SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
270 SkBlitter* blitter) {
271 SkASSERT(blitter);
272 SkASSERT(aaclip);
273 fBWRgn.setRect(aaclip->getBounds());
274 fAABlitter.init(blitter, aaclip);
275 // now our return values
276 fClipRgn = &fBWRgn;
277 fBlitter = &fAABlitter;
278}
279
280void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
281 SkASSERT(blitter);
282 if (clip.isBW()) {
283 fClipRgn = &clip.bwRgn();
284 fBlitter = blitter;
285 } else {
286 const SkAAClip& aaclip = clip.aaRgn();
287 fBWRgn.setRect(aaclip.getBounds());
288 fAABlitter.init(blitter, &aaclip);
289 // now our return values
290 fClipRgn = &fBWRgn;
291 fBlitter = &fAABlitter;
292 }
293}
294