blob: 5a2447dae96276beee5c1bda8e1fe2d621f516a8 [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;
13}
14
reed@google.com34f7e472011-10-13 15:11:59 +000015SkRasterClip::SkRasterClip(const SkRasterClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +000016 AUTO_RASTERCLIP_VALIDATE(src);
17
reed@google.com34f7e472011-10-13 15:11:59 +000018 fIsBW = src.fIsBW;
19 if (fIsBW) {
20 fBW = src.fBW;
21 } else {
22 fAA = src.fAA;
23 }
24}
25
reed@google.comba16da92011-10-11 13:15:03 +000026SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
27 fIsBW = true;
28}
29
reed@google.com045e62d2011-10-24 12:19:46 +000030SkRasterClip::~SkRasterClip() {
31 AUTO_RASTERCLIP_VALIDATE(*this);
32}
reed@google.comba16da92011-10-11 13:15:03 +000033
reed@google.comd1e3c5f2011-10-10 19:36:25 +000034bool SkRasterClip::isEmpty() const {
35 return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
36}
37
38bool SkRasterClip::isRect() const {
39 return fIsBW ? fBW.isRect() : false;
40}
41
42bool SkRasterClip::isComplex() const {
43 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
44}
45
46const SkIRect& SkRasterClip::getBounds() const {
47 return fIsBW ? fBW.getBounds() : fAA.getBounds();
48}
49
50bool SkRasterClip::setEmpty() {
reed@google.com045e62d2011-10-24 12:19:46 +000051 AUTO_RASTERCLIP_VALIDATE(*this);
52
reed@google.comd1e3c5f2011-10-10 19:36:25 +000053 fIsBW = true;
54 fBW.setEmpty();
55 fAA.setEmpty();
56 return false;
57}
58
reed@google.comba16da92011-10-11 13:15:03 +000059bool SkRasterClip::setRect(const SkIRect& rect) {
reed@google.com045e62d2011-10-24 12:19:46 +000060 AUTO_RASTERCLIP_VALIDATE(*this);
61
reed@google.comd1e3c5f2011-10-10 19:36:25 +000062 fIsBW = true;
63 fAA.setEmpty();
64 return fBW.setRect(rect);
65}
66
67bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +000068 AUTO_RASTERCLIP_VALIDATE(*this);
69
reed@google.comd1e3c5f2011-10-10 19:36:25 +000070 if (this->isBW() && !doAA) {
71 return fBW.setPath(path, clip);
72 } else {
reed@google.com897fc412012-02-16 17:11:25 +000073 // 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
reed@google.comd1e3c5f2011-10-10 19:36:25 +000075 if (this->isBW()) {
76 this->convertToAA();
77 }
78 return fAA.setPath(path, &clip, doAA);
79 }
80}
81
82bool 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
88bool 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
102bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000103 AUTO_RASTERCLIP_VALIDATE(*this);
104
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000105 return fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
106}
107
reed@google.comba16da92011-10-11 13:15:03 +0000108bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000109 AUTO_RASTERCLIP_VALIDATE(*this);
110
reed@google.comba16da92011-10-11 13:15:03 +0000111 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
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000120bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000121 AUTO_RASTERCLIP_VALIDATE(*this);
122 clip.validate();
123
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000124 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
reed@google.com045e62d2011-10-24 12:19:46 +0000143// return true if x is nearly integral (within 1/16) since that is the highest
reed@google.com00177082011-10-12 14:34:30 +0000144// precision our aa code can have.
145static bool is_integral(SkScalar x) {
146 int ix = SkScalarRoundToInt(x);
147 SkScalar sx = SkIntToScalar(ix);
reed@google.com045e62d2011-10-24 12:19:46 +0000148 return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
reed@google.com00177082011-10-12 14:34:30 +0000149}
150
151bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000152 AUTO_RASTERCLIP_VALIDATE(*this);
153
reed@google.com00177082011-10-12 14:34:30 +0000154 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);
reed@google.com56074222011-10-12 15:11:14 +0000165 return fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000166 } else {
167 if (fIsBW) {
168 this->convertToAA();
169 }
reed@google.com56074222011-10-12 15:11:14 +0000170 return fAA.op(r, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000171 }
172}
173
reed@google.com34f7e472011-10-13 15:11:59 +0000174void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
175 if (NULL == dst) {
176 return;
177 }
178
reed@google.com045e62d2011-10-24 12:19:46 +0000179 AUTO_RASTERCLIP_VALIDATE(*this);
180
reed@google.com34f7e472011-10-13 15:11:59 +0000181 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
reed@google.com045e62d2011-10-24 12:19:46 +0000200bool SkRasterClip::quickContains(const SkIRect& ir) const {
201 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
202}
203
reed@google.com34f7e472011-10-13 15:11:59 +0000204///////////////////////////////////////////////////////////////////////////////
205
reed@google.comba16da92011-10-11 13:15:03 +0000206const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000207 AUTO_RASTERCLIP_VALIDATE(*this);
208
reed@google.comba16da92011-10-11 13:15:03 +0000209 if (!fIsBW) {
210 fBW.setRect(fAA.getBounds());
211 }
212 return fBW;
213}
214
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000215void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000216 AUTO_RASTERCLIP_VALIDATE(*this);
217
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000218 SkASSERT(fIsBW);
219 fAA.setRegion(fBW);
220 fIsBW = false;
221}
222
reed@google.com045e62d2011-10-24 12:19:46 +0000223#ifdef SK_DEBUG
224void 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
237SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
238 SkDEBUGCODE(fClipRgn = NULL;)
239 SkDEBUGCODE(fBlitter = NULL;)
240}
241
242SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
243 SkBlitter* blitter) {
244 this->init(clip, blitter);
245}
246
247SkAAClipBlitterWrapper::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
258void 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