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::op(const SkIRect& rect, SkRegion::Op op) {
96    AUTO_RASTERCLIP_VALIDATE(*this);
97
98    fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
99    return this->updateCacheAndReturnNonEmpty();
100}
101
102bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
103    AUTO_RASTERCLIP_VALIDATE(*this);
104
105    if (fIsBW) {
106        (void)fBW.op(rgn, op);
107    } else {
108        SkAAClip tmp;
109        tmp.setRegion(rgn);
110        (void)fAA.op(tmp, op);
111    }
112    return this->updateCacheAndReturnNonEmpty();
113}
114
115bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
116    AUTO_RASTERCLIP_VALIDATE(*this);
117    clip.validate();
118
119    if (this->isBW() && clip.isBW()) {
120        (void)fBW.op(clip.fBW, op);
121    } else {
122        SkAAClip tmp;
123        const SkAAClip* other;
124
125        if (this->isBW()) {
126            this->convertToAA();
127        }
128        if (clip.isBW()) {
129            tmp.setRegion(clip.bwRgn());
130            other = &tmp;
131        } else {
132            other = &clip.aaRgn();
133        }
134        (void)fAA.op(*other, op);
135    }
136    return this->updateCacheAndReturnNonEmpty();
137}
138
139/**
140 *  Our antialiasing currently has a granularity of 1/4 of a pixel along each
141 *  axis. Thus we can treat an axis coordinate as an integer if it differs
142 *  from its nearest int by < half of that value (1.8 in this case).
143 */
144static bool nearly_integral(SkScalar x) {
145    static const SkScalar domain = SK_Scalar1 / 4;
146    static const SkScalar halfDomain = domain / 2;
147
148    x += halfDomain;
149    return x - SkScalarFloorToScalar(x) < domain;
150}
151
152bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
153    AUTO_RASTERCLIP_VALIDATE(*this);
154
155    if (fIsBW && doAA) {
156        // check that the rect really needs aa, or is it close enought to
157        // integer boundaries that we can just treat it as a BW rect?
158        if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
159            nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
160            doAA = false;
161        }
162    }
163
164    if (fIsBW && !doAA) {
165        SkIRect ir;
166        r.round(&ir);
167        (void)fBW.op(ir, op);
168    } else {
169        if (fIsBW) {
170            this->convertToAA();
171        }
172        (void)fAA.op(r, op, doAA);
173    }
174    return this->updateCacheAndReturnNonEmpty();
175}
176
177void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
178    if (NULL == dst) {
179        return;
180    }
181
182    AUTO_RASTERCLIP_VALIDATE(*this);
183
184    if (this->isEmpty()) {
185        dst->setEmpty();
186        return;
187    }
188    if (0 == (dx | dy)) {
189        *dst = *this;
190        return;
191    }
192
193    dst->fIsBW = fIsBW;
194    if (fIsBW) {
195        fBW.translate(dx, dy, &dst->fBW);
196        dst->fAA.setEmpty();
197    } else {
198        fAA.translate(dx, dy, &dst->fAA);
199        dst->fBW.setEmpty();
200    }
201    dst->updateCacheAndReturnNonEmpty();
202}
203
204bool SkRasterClip::quickContains(const SkIRect& ir) const {
205    return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
206}
207
208///////////////////////////////////////////////////////////////////////////////
209
210const SkRegion& SkRasterClip::forceGetBW() {
211    AUTO_RASTERCLIP_VALIDATE(*this);
212
213    if (!fIsBW) {
214        fBW.setRect(fAA.getBounds());
215    }
216    return fBW;
217}
218
219void SkRasterClip::convertToAA() {
220    AUTO_RASTERCLIP_VALIDATE(*this);
221
222    SkASSERT(fIsBW);
223    fAA.setRegion(fBW);
224    fIsBW = false;
225    (void)this->updateCacheAndReturnNonEmpty();
226}
227
228#ifdef SK_DEBUG
229void SkRasterClip::validate() const {
230    // can't ever assert that fBW is empty, since we may have called forceGetBW
231    if (fIsBW) {
232        SkASSERT(fAA.isEmpty());
233    }
234
235    fBW.validate();
236    fAA.validate();
237
238    SkASSERT(this->computeIsEmpty() == fIsEmpty);
239    SkASSERT(this->computeIsRect() == fIsRect);
240}
241#endif
242
243///////////////////////////////////////////////////////////////////////////////
244
245SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
246    SkDEBUGCODE(fClipRgn = NULL;)
247    SkDEBUGCODE(fBlitter = NULL;)
248}
249
250SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
251                                               SkBlitter* blitter) {
252    this->init(clip, blitter);
253}
254
255SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
256                                               SkBlitter* blitter) {
257    SkASSERT(blitter);
258    SkASSERT(aaclip);
259    fBWRgn.setRect(aaclip->getBounds());
260    fAABlitter.init(blitter, aaclip);
261    // now our return values
262    fClipRgn = &fBWRgn;
263    fBlitter = &fAABlitter;
264}
265
266void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
267    SkASSERT(blitter);
268    if (clip.isBW()) {
269        fClipRgn = &clip.bwRgn();
270        fBlitter = blitter;
271    } else {
272        const SkAAClip& aaclip = clip.aaRgn();
273        fBWRgn.setRect(aaclip.getBounds());
274        fAABlitter.init(blitter, &aaclip);
275        // now our return values
276        fClipRgn = &fBWRgn;
277        fBlitter = &fAABlitter;
278    }
279}
280