blob: d1615a3445f6348fef5e3cf7cdd3d3a916fa8aa0 [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
reed@google.comd1e3c5f2011-10-10 19:36:25 +000095bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +000096 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000097
reed@google.coma1c6ff42012-05-11 14:36:57 +000098 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
99 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000100}
101
reed@google.comba16da92011-10-11 13:15:03 +0000102bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000103 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000104
reed@google.comba16da92011-10-11 13:15:03 +0000105 if (fIsBW) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000106 (void)fBW.op(rgn, op);
reed@google.comba16da92011-10-11 13:15:03 +0000107 } else {
108 SkAAClip tmp;
109 tmp.setRegion(rgn);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000110 (void)fAA.op(tmp, op);
reed@google.comba16da92011-10-11 13:15:03 +0000111 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000112 return this->updateCacheAndReturnNonEmpty();
reed@google.comba16da92011-10-11 13:15:03 +0000113}
114
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000115bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000116 AUTO_RASTERCLIP_VALIDATE(*this);
117 clip.validate();
118
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000119 if (this->isBW() && clip.isBW()) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000120 (void)fBW.op(clip.fBW, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000121 } 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 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000134 (void)fAA.op(*other, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000135 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000136 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000137}
138
reed@google.com18c464b2012-05-11 20:57:25 +0000139/**
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 */
144static 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;
reed@google.com00177082011-10-12 14:34:30 +0000150}
151
152bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000153 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000154
reed@google.com420f74f2012-05-11 18:46:43 +0000155 if (fIsBW && doAA) {
reed@google.com18c464b2012-05-11 20:57:25 +0000156 // 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)) {
reed@google.com00177082011-10-12 14:34:30 +0000160 doAA = false;
161 }
162 }
163
164 if (fIsBW && !doAA) {
165 SkIRect ir;
166 r.round(&ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000167 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000168 } else {
169 if (fIsBW) {
170 this->convertToAA();
171 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000172 (void)fAA.op(r, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000173 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000174 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000175}
176
reed@google.com34f7e472011-10-13 15:11:59 +0000177void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
178 if (NULL == dst) {
179 return;
180 }
181
reed@google.com045e62d2011-10-24 12:19:46 +0000182 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000183
reed@google.com34f7e472011-10-13 15:11:59 +0000184 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 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000201 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000202}
203
reed@google.com045e62d2011-10-24 12:19:46 +0000204bool SkRasterClip::quickContains(const SkIRect& ir) const {
205 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
206}
207
reed@google.com34f7e472011-10-13 15:11:59 +0000208///////////////////////////////////////////////////////////////////////////////
209
reed@google.comba16da92011-10-11 13:15:03 +0000210const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000211 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000212
reed@google.comba16da92011-10-11 13:15:03 +0000213 if (!fIsBW) {
214 fBW.setRect(fAA.getBounds());
215 }
216 return fBW;
217}
218
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000219void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000220 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000221
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000222 SkASSERT(fIsBW);
223 fAA.setRegion(fBW);
224 fIsBW = false;
reed202ab2a2014-08-07 11:48:10 -0700225
226 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
227 // ourselves back to BW.
228 (void)this->updateCacheAndReturnNonEmpty(false);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000229}
230
reed@google.com045e62d2011-10-24 12:19:46 +0000231#ifdef SK_DEBUG
232void SkRasterClip::validate() const {
233 // can't ever assert that fBW is empty, since we may have called forceGetBW
234 if (fIsBW) {
235 SkASSERT(fAA.isEmpty());
236 }
237
238 fBW.validate();
239 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000240
241 SkASSERT(this->computeIsEmpty() == fIsEmpty);
242 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000243}
244#endif
245
246///////////////////////////////////////////////////////////////////////////////
247
248SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
249 SkDEBUGCODE(fClipRgn = NULL;)
250 SkDEBUGCODE(fBlitter = NULL;)
251}
252
253SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
254 SkBlitter* blitter) {
255 this->init(clip, blitter);
256}
257
258SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
259 SkBlitter* blitter) {
260 SkASSERT(blitter);
261 SkASSERT(aaclip);
262 fBWRgn.setRect(aaclip->getBounds());
263 fAABlitter.init(blitter, aaclip);
264 // now our return values
265 fClipRgn = &fBWRgn;
266 fBlitter = &fAABlitter;
267}
268
269void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
270 SkASSERT(blitter);
271 if (clip.isBW()) {
272 fClipRgn = &clip.bwRgn();
273 fBlitter = blitter;
274 } else {
275 const SkAAClip& aaclip = clip.aaRgn();
276 fBWRgn.setRect(aaclip.getBounds());
277 fAABlitter.init(blitter, &aaclip);
278 // now our return values
279 fClipRgn = &fBWRgn;
280 fBlitter = &fAABlitter;
281 }
282}