SkRasterClip.cpp revision 1cab2921ab279367f8206cdadc9259d12e603548
1/*
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
15SkRasterClip::SkRasterClip(const SkRasterClip& src) {
16    AUTO_RASTERCLIP_VALIDATE(src);
17
18    fIsBW = src.fIsBW;
19    if (fIsBW) {
20        fBW = src.fBW;
21    } else {
22        fAA = src.fAA;
23    }
24}
25
26SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
27    fIsBW = true;
28}
29
30SkRasterClip::~SkRasterClip() {
31    AUTO_RASTERCLIP_VALIDATE(*this);
32}
33
34bool 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() {
51    AUTO_RASTERCLIP_VALIDATE(*this);
52
53    fIsBW = true;
54    fBW.setEmpty();
55    fAA.setEmpty();
56    return false;
57}
58
59bool SkRasterClip::setRect(const SkIRect& rect) {
60    AUTO_RASTERCLIP_VALIDATE(*this);
61
62    fIsBW = true;
63    fAA.setEmpty();
64    return fBW.setRect(rect);
65}
66
67bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
68    AUTO_RASTERCLIP_VALIDATE(*this);
69
70    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) {
101    AUTO_RASTERCLIP_VALIDATE(*this);
102
103    return fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
104}
105
106bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
107    AUTO_RASTERCLIP_VALIDATE(*this);
108
109    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
118bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
119    AUTO_RASTERCLIP_VALIDATE(*this);
120    clip.validate();
121
122    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
141// return true if x is nearly integral (within 1/16) since that is the highest
142// precision our aa code can have.
143static bool is_integral(SkScalar x) {
144    int ix = SkScalarRoundToInt(x);
145    SkScalar sx = SkIntToScalar(ix);
146    return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
147}
148
149bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
150    AUTO_RASTERCLIP_VALIDATE(*this);
151
152    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);
163        return fBW.op(ir, op);
164    } else {
165        if (fIsBW) {
166            this->convertToAA();
167        }
168        return fAA.op(r, op, doAA);
169    }
170}
171
172void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
173    if (NULL == dst) {
174        return;
175    }
176
177    AUTO_RASTERCLIP_VALIDATE(*this);
178
179    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
198bool SkRasterClip::quickContains(const SkIRect& ir) const {
199    return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
200}
201
202///////////////////////////////////////////////////////////////////////////////
203
204const SkRegion& SkRasterClip::forceGetBW() {
205    AUTO_RASTERCLIP_VALIDATE(*this);
206
207    if (!fIsBW) {
208        fBW.setRect(fAA.getBounds());
209    }
210    return fBW;
211}
212
213void SkRasterClip::convertToAA() {
214    AUTO_RASTERCLIP_VALIDATE(*this);
215
216    SkASSERT(fIsBW);
217    fAA.setRegion(fBW);
218    fIsBW = false;
219}
220
221#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
271