SkRasterClip.cpp revision fbfcd5602128ec010c82cb733c9cdc0a3254f9f3
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/**
154 *  Our antialiasing currently has a granularity of 1/4 of a pixel along each
155 *  axis. Thus we can treat an axis coordinate as an integer if it differs
156 *  from its nearest int by < half of that value (1.8 in this case).
157 */
158static bool nearly_integral(SkScalar x) {
159    static const SkScalar domain = SK_Scalar1 / 4;
160    static const SkScalar halfDomain = domain / 2;
161
162    x += halfDomain;
163    return x - SkScalarFloorToScalar(x) < domain;
164}
165
166bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
167    AUTO_RASTERCLIP_VALIDATE(*this);
168
169    if (fIsBW && doAA) {
170        // check that the rect really needs aa, or is it close enought to
171        // integer boundaries that we can just treat it as a BW rect?
172        if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
173            nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
174            doAA = false;
175        }
176    }
177
178    if (fIsBW && !doAA) {
179        SkIRect ir;
180        r.round(&ir);
181        (void)fBW.op(ir, op);
182    } else {
183        if (fIsBW) {
184            this->convertToAA();
185        }
186        (void)fAA.op(r, op, doAA);
187    }
188    return this->updateCacheAndReturnNonEmpty();
189}
190
191void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
192    if (NULL == dst) {
193        return;
194    }
195
196    AUTO_RASTERCLIP_VALIDATE(*this);
197
198    if (this->isEmpty()) {
199        dst->setEmpty();
200        return;
201    }
202    if (0 == (dx | dy)) {
203        *dst = *this;
204        return;
205    }
206
207    dst->fIsBW = fIsBW;
208    if (fIsBW) {
209        fBW.translate(dx, dy, &dst->fBW);
210        dst->fAA.setEmpty();
211    } else {
212        fAA.translate(dx, dy, &dst->fAA);
213        dst->fBW.setEmpty();
214    }
215    dst->updateCacheAndReturnNonEmpty();
216}
217
218bool SkRasterClip::quickContains(const SkIRect& ir) const {
219    return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
220}
221
222///////////////////////////////////////////////////////////////////////////////
223
224const SkRegion& SkRasterClip::forceGetBW() {
225    AUTO_RASTERCLIP_VALIDATE(*this);
226
227    if (!fIsBW) {
228        fBW.setRect(fAA.getBounds());
229    }
230    return fBW;
231}
232
233void SkRasterClip::convertToAA() {
234    AUTO_RASTERCLIP_VALIDATE(*this);
235
236    SkASSERT(fIsBW);
237    fAA.setRegion(fBW);
238    fIsBW = false;
239    (void)this->updateCacheAndReturnNonEmpty();
240}
241
242#ifdef SK_DEBUG
243void SkRasterClip::validate() const {
244    // can't ever assert that fBW is empty, since we may have called forceGetBW
245    if (fIsBW) {
246        SkASSERT(fAA.isEmpty());
247    }
248
249    fBW.validate();
250    fAA.validate();
251
252    SkASSERT(this->computeIsEmpty() == fIsEmpty);
253    SkASSERT(this->computeIsRect() == fIsRect);
254}
255#endif
256
257///////////////////////////////////////////////////////////////////////////////
258
259SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
260    SkDEBUGCODE(fClipRgn = NULL;)
261    SkDEBUGCODE(fBlitter = NULL;)
262}
263
264SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
265                                               SkBlitter* blitter) {
266    this->init(clip, blitter);
267}
268
269SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
270                                               SkBlitter* blitter) {
271    SkASSERT(blitter);
272    SkASSERT(aaclip);
273    fBWRgn.setRect(aaclip->getBounds());
274    fAABlitter.init(blitter, aaclip);
275    // now our return values
276    fClipRgn = &fBWRgn;
277    fBlitter = &fAABlitter;
278}
279
280void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
281    SkASSERT(blitter);
282    if (clip.isBW()) {
283        fClipRgn = &clip.bwRgn();
284        fBlitter = blitter;
285    } else {
286        const SkAAClip& aaclip = clip.aaRgn();
287        fBWRgn.setRect(aaclip.getBounds());
288        fAABlitter.init(blitter, &aaclip);
289        // now our return values
290        fClipRgn = &fBWRgn;
291        fBlitter = &fAABlitter;
292    }
293}
294
295