blob: 9bf39faa74253c455e539b864d0ab547876fa317 [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 {
73 if (this->isBW()) {
74 this->convertToAA();
75 }
76 return fAA.setPath(path, &clip, doAA);
77 }
78}
79
80bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
81 SkRegion tmp;
82 tmp.setRect(clip);
83 return this->setPath(path, tmp, doAA);
84}
85
86bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip,
87 bool doAA) {
88 if (clip.isBW()) {
89 return this->setPath(path, clip.bwRgn(), doAA);
90 } else {
91 SkRegion tmp;
92 tmp.setRect(clip.getBounds());
93 if (!this->setPath(path, clip, doAA)) {
94 return false;
95 }
96 return this->op(clip, SkRegion::kIntersect_Op);
97 }
98}
99
100bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000101 AUTO_RASTERCLIP_VALIDATE(*this);
102
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000103 return fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
104}
105
reed@google.comba16da92011-10-11 13:15:03 +0000106bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000107 AUTO_RASTERCLIP_VALIDATE(*this);
108
reed@google.comba16da92011-10-11 13:15:03 +0000109 if (fIsBW) {
110 return fBW.op(rgn, op);
111 } else {
112 SkAAClip tmp;
113 tmp.setRegion(rgn);
114 return fAA.op(tmp, op);
115 }
116}
117
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000118bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000119 AUTO_RASTERCLIP_VALIDATE(*this);
120 clip.validate();
121
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000122 if (this->isBW() && clip.isBW()) {
123 return fBW.op(clip.fBW, op);
124 } else {
125 SkAAClip tmp;
126 const SkAAClip* other;
127
128 if (this->isBW()) {
129 this->convertToAA();
130 }
131 if (clip.isBW()) {
132 tmp.setRegion(clip.bwRgn());
133 other = &tmp;
134 } else {
135 other = &clip.aaRgn();
136 }
137 return fAA.op(*other, op);
138 }
139}
140
reed@google.com045e62d2011-10-24 12:19:46 +0000141// return true if x is nearly integral (within 1/16) since that is the highest
reed@google.com00177082011-10-12 14:34:30 +0000142// precision our aa code can have.
143static bool is_integral(SkScalar x) {
144 int ix = SkScalarRoundToInt(x);
145 SkScalar sx = SkIntToScalar(ix);
reed@google.com045e62d2011-10-24 12:19:46 +0000146 return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
reed@google.com00177082011-10-12 14:34:30 +0000147}
148
149bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000150 AUTO_RASTERCLIP_VALIDATE(*this);
151
reed@google.com00177082011-10-12 14:34:30 +0000152 if (doAA) {
153 // check that the rect really needs aa
154 if (is_integral(r.fLeft) && is_integral(r.fTop) &&
155 is_integral(r.fRight) && is_integral(r.fBottom)) {
156 doAA = false;
157 }
158 }
159
160 if (fIsBW && !doAA) {
161 SkIRect ir;
162 r.round(&ir);
reed@google.com56074222011-10-12 15:11:14 +0000163 return fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000164 } else {
165 if (fIsBW) {
166 this->convertToAA();
167 }
reed@google.com56074222011-10-12 15:11:14 +0000168 return fAA.op(r, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000169 }
170}
171
reed@google.com34f7e472011-10-13 15:11:59 +0000172void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
173 if (NULL == dst) {
174 return;
175 }
176
reed@google.com045e62d2011-10-24 12:19:46 +0000177 AUTO_RASTERCLIP_VALIDATE(*this);
178
reed@google.com34f7e472011-10-13 15:11:59 +0000179 if (this->isEmpty()) {
180 dst->setEmpty();
181 return;
182 }
183 if (0 == (dx | dy)) {
184 *dst = *this;
185 return;
186 }
187
188 dst->fIsBW = fIsBW;
189 if (fIsBW) {
190 fBW.translate(dx, dy, &dst->fBW);
191 dst->fAA.setEmpty();
192 } else {
193 fAA.translate(dx, dy, &dst->fAA);
194 dst->fBW.setEmpty();
195 }
196}
197
reed@google.com045e62d2011-10-24 12:19:46 +0000198bool SkRasterClip::quickContains(const SkIRect& ir) const {
199 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
200}
201
reed@google.com34f7e472011-10-13 15:11:59 +0000202///////////////////////////////////////////////////////////////////////////////
203
reed@google.comba16da92011-10-11 13:15:03 +0000204const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000205 AUTO_RASTERCLIP_VALIDATE(*this);
206
reed@google.comba16da92011-10-11 13:15:03 +0000207 if (!fIsBW) {
208 fBW.setRect(fAA.getBounds());
209 }
210 return fBW;
211}
212
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000213void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000214 AUTO_RASTERCLIP_VALIDATE(*this);
215
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000216 SkASSERT(fIsBW);
217 fAA.setRegion(fBW);
218 fIsBW = false;
219}
220
reed@google.com045e62d2011-10-24 12:19:46 +0000221#ifdef SK_DEBUG
222void SkRasterClip::validate() const {
223 // can't ever assert that fBW is empty, since we may have called forceGetBW
224 if (fIsBW) {
225 SkASSERT(fAA.isEmpty());
226 }
227
228 fBW.validate();
229 fAA.validate();
230}
231#endif
232
233///////////////////////////////////////////////////////////////////////////////
234
235SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
236 SkDEBUGCODE(fClipRgn = NULL;)
237 SkDEBUGCODE(fBlitter = NULL;)
238}
239
240SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
241 SkBlitter* blitter) {
242 this->init(clip, blitter);
243}
244
245SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
246 SkBlitter* blitter) {
247 SkASSERT(blitter);
248 SkASSERT(aaclip);
249 fBWRgn.setRect(aaclip->getBounds());
250 fAABlitter.init(blitter, aaclip);
251 // now our return values
252 fClipRgn = &fBWRgn;
253 fBlitter = &fAABlitter;
254}
255
256void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
257 SkASSERT(blitter);
258 if (clip.isBW()) {
259 fClipRgn = &clip.bwRgn();
260 fBlitter = blitter;
261 } else {
262 const SkAAClip& aaclip = clip.aaRgn();
263 fBWRgn.setRect(aaclip.getBounds());
264 fAABlitter.init(blitter, &aaclip);
265 // now our return values
266 fClipRgn = &fBWRgn;
267 fBlitter = &fAABlitter;
268 }
269}
270