SkRasterClip.cpp revision 420f74fa720272b1164eae55d7b6c10e07d41601
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    fIsEmpty = true;
14    fIsRect = false;
15    SkDEBUGCODE(this->validate();)
16}
17
18SkRasterClip::SkRasterClip(const SkRasterClip& src) {
19    AUTO_RASTERCLIP_VALIDATE(src);
20
21    fIsBW = src.fIsBW;
22    if (fIsBW) {
23        fBW = src.fBW;
24    } else {
25        fAA = src.fAA;
26    }
27
28    fIsEmpty = src.isEmpty();
29    fIsRect = src.isRect();
30    SkDEBUGCODE(this->validate();)
31}
32
33SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
34    fIsBW = true;
35    fIsEmpty = this->computeIsEmpty();  // bounds might be empty, so compute
36    fIsRect = !fIsEmpty;
37    SkDEBUGCODE(this->validate();)
38}
39
40SkRasterClip::~SkRasterClip() {
41    SkDEBUGCODE(this->validate();)
42}
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() {
53    AUTO_RASTERCLIP_VALIDATE(*this);
54
55    fIsBW = true;
56    fBW.setEmpty();
57    fAA.setEmpty();
58    fIsEmpty = true;
59    fIsRect = false;
60    return false;
61}
62
63bool SkRasterClip::setRect(const SkIRect& rect) {
64    AUTO_RASTERCLIP_VALIDATE(*this);
65
66    fIsBW = true;
67    fAA.setEmpty();
68    fIsRect = fBW.setRect(rect);
69    fIsEmpty = !fIsRect;
70    return fIsRect;
71}
72
73bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
74    AUTO_RASTERCLIP_VALIDATE(*this);
75
76    if (this->isBW() && !doAA) {
77        (void)fBW.setPath(path, clip);
78    } else {
79        // 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
81        if (this->isBW()) {
82            this->convertToAA();
83        }
84        (void)fAA.setPath(path, &clip, doAA);
85    }
86    return this->updateCacheAndReturnNonEmpty();
87}
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) {
110    AUTO_RASTERCLIP_VALIDATE(*this);
111
112    fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
113    return this->updateCacheAndReturnNonEmpty();
114}
115
116bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
117    AUTO_RASTERCLIP_VALIDATE(*this);
118
119    if (fIsBW) {
120        (void)fBW.op(rgn, op);
121    } else {
122        SkAAClip tmp;
123        tmp.setRegion(rgn);
124        (void)fAA.op(tmp, op);
125    }
126    return this->updateCacheAndReturnNonEmpty();
127}
128
129bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
130    AUTO_RASTERCLIP_VALIDATE(*this);
131    clip.validate();
132
133    if (this->isBW() && clip.isBW()) {
134        (void)fBW.op(clip.fBW, op);
135    } 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        }
148        (void)fAA.op(*other, op);
149    }
150    return this->updateCacheAndReturnNonEmpty();
151}
152
153// return true if x is nearly integral (within 1/16) since that is the highest
154// precision our aa code can have.
155static bool is_integral(SkScalar x) {
156    int ix = SkScalarRoundToInt(x);
157    SkScalar sx = SkIntToScalar(ix);
158    return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
159}
160
161bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
162    AUTO_RASTERCLIP_VALIDATE(*this);
163
164    if (fIsBW && doAA) {
165        // check that the rect really needs aa
166        if (is_integral(r.fLeft) && is_integral(r.fTop) &&
167            is_integral(r.fRight) && is_integral(r.fBottom)) {
168            doAA = false;
169        }
170    }
171
172    if (fIsBW && !doAA) {
173        SkIRect ir;
174        r.round(&ir);
175        (void)fBW.op(ir, op);
176    } else {
177        if (fIsBW) {
178            this->convertToAA();
179        }
180        (void)fAA.op(r, op, doAA);
181    }
182    return this->updateCacheAndReturnNonEmpty();
183}
184
185void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
186    if (NULL == dst) {
187        return;
188    }
189
190    AUTO_RASTERCLIP_VALIDATE(*this);
191
192    if (this->isEmpty()) {
193        dst->setEmpty();
194        return;
195    }
196    if (0 == (dx | dy)) {
197        *dst = *this;
198        return;
199    }
200
201    dst->fIsBW = fIsBW;
202    if (fIsBW) {
203        fBW.translate(dx, dy, &dst->fBW);
204        dst->fAA.setEmpty();
205    } else {
206        fAA.translate(dx, dy, &dst->fAA);
207        dst->fBW.setEmpty();
208    }
209    dst->updateCacheAndReturnNonEmpty();
210}
211
212bool SkRasterClip::quickContains(const SkIRect& ir) const {
213    return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
214}
215
216///////////////////////////////////////////////////////////////////////////////
217
218const SkRegion& SkRasterClip::forceGetBW() {
219    AUTO_RASTERCLIP_VALIDATE(*this);
220
221    if (!fIsBW) {
222        fBW.setRect(fAA.getBounds());
223    }
224    return fBW;
225}
226
227void SkRasterClip::convertToAA() {
228    AUTO_RASTERCLIP_VALIDATE(*this);
229
230    SkASSERT(fIsBW);
231    fAA.setRegion(fBW);
232    fIsBW = false;
233    (void)this->updateCacheAndReturnNonEmpty();
234}
235
236#ifdef SK_DEBUG
237void SkRasterClip::validate() const {
238    // can't ever assert that fBW is empty, since we may have called forceGetBW
239    if (fIsBW) {
240        SkASSERT(fAA.isEmpty());
241    }
242
243    fBW.validate();
244    fAA.validate();
245
246    SkASSERT(this->computeIsEmpty() == fIsEmpty);
247    SkASSERT(this->computeIsRect() == fIsRect);
248}
249#endif
250
251///////////////////////////////////////////////////////////////////////////////
252
253SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
254    SkDEBUGCODE(fClipRgn = NULL;)
255    SkDEBUGCODE(fBlitter = NULL;)
256}
257
258SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
259                                               SkBlitter* blitter) {
260    this->init(clip, blitter);
261}
262
263SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
264                                               SkBlitter* blitter) {
265    SkASSERT(blitter);
266    SkASSERT(aaclip);
267    fBWRgn.setRect(aaclip->getBounds());
268    fAABlitter.init(blitter, aaclip);
269    // now our return values
270    fClipRgn = &fBWRgn;
271    fBlitter = &fAABlitter;
272}
273
274void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
275    SkASSERT(blitter);
276    if (clip.isBW()) {
277        fClipRgn = &clip.bwRgn();
278        fBlitter = blitter;
279    } else {
280        const SkAAClip& aaclip = clip.aaRgn();
281        fBWRgn.setRect(aaclip.getBounds());
282        fAABlitter.init(blitter, &aaclip);
283        // now our return values
284        fClipRgn = &fBWRgn;
285        fBlitter = &fAABlitter;
286    }
287}
288
289