2 * Copyright 2010 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkRasterClip.h"
11 SkRasterClip::SkRasterClip(const SkRasterClip& src) {
12 AUTO_RASTERCLIP_VALIDATE(src);
14 fForceConservativeRects = src.fForceConservativeRects;
22 fIsEmpty = src.isEmpty();
23 fIsRect = src.isRect();
24 SkDEBUGCODE(this->validate();)
27 SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) {
28 fForceConservativeRects = forceConservativeRects;
30 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
32 SkDEBUGCODE(this->validate();)
35 SkRasterClip::SkRasterClip(bool forceConservativeRects) {
36 fForceConservativeRects = forceConservativeRects;
40 SkDEBUGCODE(this->validate();)
43 SkRasterClip::~SkRasterClip() {
44 SkDEBUGCODE(this->validate();)
47 bool SkRasterClip::isComplex() const {
48 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
51 const SkIRect& SkRasterClip::getBounds() const {
52 return fIsBW ? fBW.getBounds() : fAA.getBounds();
55 bool SkRasterClip::setEmpty() {
56 AUTO_RASTERCLIP_VALIDATE(*this);
66 bool SkRasterClip::setRect(const SkIRect& rect) {
67 AUTO_RASTERCLIP_VALIDATE(*this);
71 fIsRect = fBW.setRect(rect);
76 /////////////////////////////////////////////////////////////////////////////////////
78 bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
84 op = SkRegion::kDifference_Op;
86 op = SkRegion::kIntersect_Op;
90 return this->updateCacheAndReturnNonEmpty();
93 /////////////////////////////////////////////////////////////////////////////////////
96 kDoNothing_MutateResult,
97 kReplaceClippedAgainstGlobalBounds_MutateResult,
98 kContinue_MutateResult,
101 static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
104 case SkRegion::kIntersect_Op:
105 case SkRegion::kDifference_Op:
106 // These ops can only shrink the current clip. So leaving
107 // the clip unchanged conservatively respects the contract.
108 return kDoNothing_MutateResult;
109 case SkRegion::kUnion_Op:
110 case SkRegion::kReplace_Op:
111 case SkRegion::kReverseDifference_Op:
112 case SkRegion::kXOR_Op: {
113 // These ops can grow the current clip up to the extents of
114 // the input clip, which is inverse filled, so we just set
115 // the current clip to the device bounds.
116 *op = SkRegion::kReplace_Op;
117 return kReplaceClippedAgainstGlobalBounds_MutateResult;
121 // Not inverse filled
123 case SkRegion::kIntersect_Op:
124 case SkRegion::kUnion_Op:
125 case SkRegion::kReplace_Op:
126 return kContinue_MutateResult;
127 case SkRegion::kDifference_Op:
128 // Difference can only shrink the current clip.
129 // Leaving clip unchanged conservatively fullfills the contract.
130 return kDoNothing_MutateResult;
131 case SkRegion::kReverseDifference_Op:
132 // To reverse, we swap in the bounds with a replace op.
133 // As with difference, leave it unchanged.
134 *op = SkRegion::kReplace_Op;
135 return kContinue_MutateResult;
136 case SkRegion::kXOR_Op:
137 // Be conservative, based on (A XOR B) always included in (A union B),
138 // which is always included in (bounds(A) union bounds(B))
139 *op = SkRegion::kUnion_Op;
140 return kContinue_MutateResult;
143 SkFAIL("should not get here");
144 return kDoNothing_MutateResult;
147 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
148 AUTO_RASTERCLIP_VALIDATE(*this);
150 if (fForceConservativeRects) {
151 return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType());
154 if (this->isBW() && !doAA) {
155 (void)fBW.setPath(path, clip);
157 // TODO: since we are going to over-write fAA completely (aren't we?)
158 // we should just clear our BW data (if any) and set fIsAA=true
162 (void)fAA.setPath(path, &clip, doAA);
164 return this->updateCacheAndReturnNonEmpty();
167 bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, bool doAA) {
168 // base is used to limit the size (and therefore memory allocation) of the
169 // region that results from scan converting devPath.
172 if (fForceConservativeRects) {
174 switch (mutate_conservative_op(&op, path.isInverseFillType())) {
175 case kDoNothing_MutateResult:
176 return !this->isEmpty();
177 case kReplaceClippedAgainstGlobalBounds_MutateResult:
178 ir = SkIRect::MakeSize(size);
180 case kContinue_MutateResult:
181 path.getBounds().roundOut(&ir);
184 return this->op(ir, op);
187 if (SkRegion::kIntersect_Op == op) {
188 // since we are intersect, we can do better (tighter) with currRgn's
189 // bounds, than just using the device. However, if currRgn is complex,
190 // our region blitter may hork, so we do that case in two steps.
191 if (this->isRect()) {
192 // FIXME: we should also be able to do this when this->isBW(),
193 // but relaxing the test above triggers GM asserts in
194 // SkRgnBuilder::blitH(). We need to investigate what's going on.
195 return this->setPath(path, this->bwRgn(), doAA);
197 base.setRect(this->getBounds());
198 SkRasterClip clip(fForceConservativeRects);
199 clip.setPath(path, base, doAA);
200 return this->op(clip, op);
203 base.setRect(0, 0, size.width(), size.height());
205 if (SkRegion::kReplace_Op == op) {
206 return this->setPath(path, base, doAA);
208 SkRasterClip clip(fForceConservativeRects);
209 clip.setPath(path, base, doAA);
210 return this->op(clip, op);
215 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
218 return this->setPath(path, tmp, doAA);
221 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
222 AUTO_RASTERCLIP_VALIDATE(*this);
224 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
225 return this->updateCacheAndReturnNonEmpty();
228 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
229 AUTO_RASTERCLIP_VALIDATE(*this);
232 (void)fBW.op(rgn, op);
236 (void)fAA.op(tmp, op);
238 return this->updateCacheAndReturnNonEmpty();
241 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
242 AUTO_RASTERCLIP_VALIDATE(*this);
245 if (this->isBW() && clip.isBW()) {
246 (void)fBW.op(clip.fBW, op);
249 const SkAAClip* other;
255 tmp.setRegion(clip.bwRgn());
258 other = &clip.aaRgn();
260 (void)fAA.op(*other, op);
262 return this->updateCacheAndReturnNonEmpty();
266 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
267 * axis. Thus we can treat an axis coordinate as an integer if it differs
268 * from its nearest int by < half of that value (1.8 in this case).
270 static bool nearly_integral(SkScalar x) {
271 static const SkScalar domain = SK_Scalar1 / 4;
272 static const SkScalar halfDomain = domain / 2;
275 return x - SkScalarFloorToScalar(x) < domain;
278 bool SkRasterClip::op(const SkRect& r, const SkISize& size, SkRegion::Op op, bool doAA) {
279 AUTO_RASTERCLIP_VALIDATE(*this);
281 if (fForceConservativeRects) {
283 switch (mutate_conservative_op(&op, false)) {
284 case kDoNothing_MutateResult:
285 return !this->isEmpty();
286 case kReplaceClippedAgainstGlobalBounds_MutateResult:
287 ir = SkIRect::MakeSize(size);
289 case kContinue_MutateResult:
293 return this->op(ir, op);
297 // check that the rect really needs aa, or is it close enought to
298 // integer boundaries that we can just treat it as a BW rect?
299 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
300 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
305 if (fIsBW && !doAA) {
308 (void)fBW.op(ir, op);
313 (void)fAA.op(r, op, doAA);
315 return this->updateCacheAndReturnNonEmpty();
318 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
323 AUTO_RASTERCLIP_VALIDATE(*this);
325 if (this->isEmpty()) {
329 if (0 == (dx | dy)) {
336 fBW.translate(dx, dy, &dst->fBW);
339 fAA.translate(dx, dy, &dst->fAA);
342 dst->updateCacheAndReturnNonEmpty();
345 bool SkRasterClip::quickContains(const SkIRect& ir) const {
346 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
349 ///////////////////////////////////////////////////////////////////////////////
351 const SkRegion& SkRasterClip::forceGetBW() {
352 AUTO_RASTERCLIP_VALIDATE(*this);
355 fBW.setRect(fAA.getBounds());
360 void SkRasterClip::convertToAA() {
361 AUTO_RASTERCLIP_VALIDATE(*this);
363 SkASSERT(!fForceConservativeRects);
369 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
370 // ourselves back to BW.
371 (void)this->updateCacheAndReturnNonEmpty(false);
375 void SkRasterClip::validate() const {
376 // can't ever assert that fBW is empty, since we may have called forceGetBW
378 SkASSERT(fAA.isEmpty());
384 SkASSERT(this->computeIsEmpty() == fIsEmpty);
385 SkASSERT(this->computeIsRect() == fIsRect);
389 ///////////////////////////////////////////////////////////////////////////////
391 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
392 SkDEBUGCODE(fClipRgn = NULL;)
393 SkDEBUGCODE(fBlitter = NULL;)
396 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
397 SkBlitter* blitter) {
398 this->init(clip, blitter);
401 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
402 SkBlitter* blitter) {
405 fBWRgn.setRect(aaclip->getBounds());
406 fAABlitter.init(blitter, aaclip);
407 // now our return values
409 fBlitter = &fAABlitter;
412 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
415 fClipRgn = &clip.bwRgn();
418 const SkAAClip& aaclip = clip.aaRgn();
419 fBWRgn.setRect(aaclip.getBounds());
420 fAABlitter.init(blitter, &aaclip);
421 // now our return values
423 fBlitter = &fAABlitter;