blob: 88bfbafc365da153e2ffb88898f1eb8abd22c9ab [file] [log] [blame]
reed@google.comd1e3c5f2011-10-10 19:36:25 +00001/*
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"
reedd9544982014-09-09 18:46:22 -07009#include "SkPath.h"
reed@google.comd1e3c5f2011-10-10 19:36:25 +000010
reed@google.com34f7e472011-10-13 15:11:59 +000011SkRasterClip::SkRasterClip(const SkRasterClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +000012 AUTO_RASTERCLIP_VALIDATE(src);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000013
reedd9544982014-09-09 18:46:22 -070014 fForceConservativeRects = src.fForceConservativeRects;
reed@google.com34f7e472011-10-13 15:11:59 +000015 fIsBW = src.fIsBW;
16 if (fIsBW) {
17 fBW = src.fBW;
18 } else {
19 fAA = src.fAA;
20 }
reed@google.coma1c6ff42012-05-11 14:36:57 +000021
22 fIsEmpty = src.isEmpty();
23 fIsRect = src.isRect();
24 SkDEBUGCODE(this->validate();)
reed@google.com34f7e472011-10-13 15:11:59 +000025}
26
reed1e7f5e72016-04-27 07:49:17 -070027SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
28 fForceConservativeRects = false;
29 fIsBW = true;
30 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
31 fIsRect = !fIsEmpty;
32 SkDEBUGCODE(this->validate();)
33}
34
reedd9544982014-09-09 18:46:22 -070035SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) {
36 fForceConservativeRects = forceConservativeRects;
reed@google.comba16da92011-10-11 13:15:03 +000037 fIsBW = true;
reed@google.coma1c6ff42012-05-11 14:36:57 +000038 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
39 fIsRect = !fIsEmpty;
40 SkDEBUGCODE(this->validate();)
reed@google.comba16da92011-10-11 13:15:03 +000041}
42
reedd9544982014-09-09 18:46:22 -070043SkRasterClip::SkRasterClip(bool forceConservativeRects) {
44 fForceConservativeRects = forceConservativeRects;
45 fIsBW = true;
46 fIsEmpty = true;
47 fIsRect = false;
48 SkDEBUGCODE(this->validate();)
49}
50
reed@google.com045e62d2011-10-24 12:19:46 +000051SkRasterClip::~SkRasterClip() {
reed@google.coma1c6ff42012-05-11 14:36:57 +000052 SkDEBUGCODE(this->validate();)
reed@google.comd1e3c5f2011-10-10 19:36:25 +000053}
54
reed1e7f5e72016-04-27 07:49:17 -070055bool SkRasterClip::operator==(const SkRasterClip& other) const {
56 // This impl doesn't care if fForceConservativeRects is the same in both, only the current state
57
58 if (fIsBW != other.fIsBW) {
59 return false;
60 }
61 bool isEqual = fIsBW ? fBW == other.fBW : fAA == other.fAA;
62#ifdef SK_DEBUG
63 if (isEqual) {
64 SkASSERT(fIsEmpty == other.fIsEmpty);
65 SkASSERT(fIsRect == other.fIsRect);
66 }
67#endif
68 return isEqual;
69}
70
reed@google.comd1e3c5f2011-10-10 19:36:25 +000071bool SkRasterClip::isComplex() const {
72 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
73}
74
75const SkIRect& SkRasterClip::getBounds() const {
76 return fIsBW ? fBW.getBounds() : fAA.getBounds();
77}
78
79bool SkRasterClip::setEmpty() {
reed@google.com045e62d2011-10-24 12:19:46 +000080 AUTO_RASTERCLIP_VALIDATE(*this);
81
reed@google.comd1e3c5f2011-10-10 19:36:25 +000082 fIsBW = true;
83 fBW.setEmpty();
84 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +000085 fIsEmpty = true;
86 fIsRect = false;
reed@google.comd1e3c5f2011-10-10 19:36:25 +000087 return false;
88}
89
reed@google.comba16da92011-10-11 13:15:03 +000090bool SkRasterClip::setRect(const SkIRect& rect) {
reed@google.com045e62d2011-10-24 12:19:46 +000091 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000092
reed@google.comd1e3c5f2011-10-10 19:36:25 +000093 fIsBW = true;
94 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +000095 fIsRect = fBW.setRect(rect);
96 fIsEmpty = !fIsRect;
97 return fIsRect;
reed@google.comd1e3c5f2011-10-10 19:36:25 +000098}
99
reedd9544982014-09-09 18:46:22 -0700100/////////////////////////////////////////////////////////////////////////////////////
101
102bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
reedd9544982014-09-09 18:46:22 -0700103 SkRegion::Op op;
104 if (isInverse) {
105 op = SkRegion::kDifference_Op;
106 } else {
107 op = SkRegion::kIntersect_Op;
108 }
109 fBW.setRect(clipR);
reedb07a94f2014-11-19 05:03:18 -0800110 fBW.op(r.roundOut(), op);
reedd9544982014-09-09 18:46:22 -0700111 return this->updateCacheAndReturnNonEmpty();
112}
113
114/////////////////////////////////////////////////////////////////////////////////////
115
116enum MutateResult {
117 kDoNothing_MutateResult,
118 kReplaceClippedAgainstGlobalBounds_MutateResult,
119 kContinue_MutateResult,
120};
121
122static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
123 if (inverseFilled) {
124 switch (*op) {
125 case SkRegion::kIntersect_Op:
126 case SkRegion::kDifference_Op:
127 // These ops can only shrink the current clip. So leaving
128 // the clip unchanged conservatively respects the contract.
129 return kDoNothing_MutateResult;
130 case SkRegion::kUnion_Op:
131 case SkRegion::kReplace_Op:
132 case SkRegion::kReverseDifference_Op:
133 case SkRegion::kXOR_Op: {
134 // These ops can grow the current clip up to the extents of
135 // the input clip, which is inverse filled, so we just set
136 // the current clip to the device bounds.
137 *op = SkRegion::kReplace_Op;
138 return kReplaceClippedAgainstGlobalBounds_MutateResult;
139 }
140 }
141 } else {
142 // Not inverse filled
143 switch (*op) {
144 case SkRegion::kIntersect_Op:
145 case SkRegion::kUnion_Op:
146 case SkRegion::kReplace_Op:
147 return kContinue_MutateResult;
148 case SkRegion::kDifference_Op:
149 // Difference can only shrink the current clip.
150 // Leaving clip unchanged conservatively fullfills the contract.
151 return kDoNothing_MutateResult;
152 case SkRegion::kReverseDifference_Op:
153 // To reverse, we swap in the bounds with a replace op.
154 // As with difference, leave it unchanged.
155 *op = SkRegion::kReplace_Op;
156 return kContinue_MutateResult;
157 case SkRegion::kXOR_Op:
158 // Be conservative, based on (A XOR B) always included in (A union B),
159 // which is always included in (bounds(A) union bounds(B))
160 *op = SkRegion::kUnion_Op;
161 return kContinue_MutateResult;
162 }
163 }
164 SkFAIL("should not get here");
165 return kDoNothing_MutateResult;
166}
167
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000168bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000169 AUTO_RASTERCLIP_VALIDATE(*this);
170
reedd9544982014-09-09 18:46:22 -0700171 if (fForceConservativeRects) {
172 return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType());
173 }
174
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000175 if (this->isBW() && !doAA) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000176 (void)fBW.setPath(path, clip);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000177 } else {
reed@google.com897fc412012-02-16 17:11:25 +0000178 // TODO: since we are going to over-write fAA completely (aren't we?)
179 // we should just clear our BW data (if any) and set fIsAA=true
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000180 if (this->isBW()) {
181 this->convertToAA();
182 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000183 (void)fAA.setPath(path, &clip, doAA);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000184 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000185 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000186}
187
senorblancoafc7cce2016-02-02 18:44:15 -0800188bool SkRasterClip::op(const SkRRect& rrect, const SkIRect& bounds, SkRegion::Op op, bool doAA) {
robertphillips125f19a2015-11-23 09:00:05 -0800189 if (fForceConservativeRects) {
senorblancoafc7cce2016-02-02 18:44:15 -0800190 return this->op(rrect.getBounds(), bounds, op, doAA);
robertphillips125f19a2015-11-23 09:00:05 -0800191 }
192
193 SkPath path;
194 path.addRRect(rrect);
195
senorblancoafc7cce2016-02-02 18:44:15 -0800196 return this->op(path, bounds, op, doAA);
robertphillips125f19a2015-11-23 09:00:05 -0800197}
198
senorblancoafc7cce2016-02-02 18:44:15 -0800199bool SkRasterClip::op(const SkPath& path, const SkIRect& bounds, SkRegion::Op op, bool doAA) {
robertphillips125f19a2015-11-23 09:00:05 -0800200 AUTO_RASTERCLIP_VALIDATE(*this);
reedd9544982014-09-09 18:46:22 -0700201
202 if (fForceConservativeRects) {
203 SkIRect ir;
204 switch (mutate_conservative_op(&op, path.isInverseFillType())) {
205 case kDoNothing_MutateResult:
206 return !this->isEmpty();
207 case kReplaceClippedAgainstGlobalBounds_MutateResult:
senorblancoafc7cce2016-02-02 18:44:15 -0800208 ir = bounds;
reedd9544982014-09-09 18:46:22 -0700209 break;
210 case kContinue_MutateResult:
reedb07a94f2014-11-19 05:03:18 -0800211 ir = path.getBounds().roundOut();
reedd9544982014-09-09 18:46:22 -0700212 break;
213 }
214 return this->op(ir, op);
215 }
216
robertphillips125f19a2015-11-23 09:00:05 -0800217 // base is used to limit the size (and therefore memory allocation) of the
218 // region that results from scan converting devPath.
219 SkRegion base;
220
reedd64c9482014-09-05 17:37:38 -0700221 if (SkRegion::kIntersect_Op == op) {
222 // since we are intersect, we can do better (tighter) with currRgn's
223 // bounds, than just using the device. However, if currRgn is complex,
224 // our region blitter may hork, so we do that case in two steps.
225 if (this->isRect()) {
226 // FIXME: we should also be able to do this when this->isBW(),
227 // but relaxing the test above triggers GM asserts in
228 // SkRgnBuilder::blitH(). We need to investigate what's going on.
229 return this->setPath(path, this->bwRgn(), doAA);
230 } else {
231 base.setRect(this->getBounds());
reedd9544982014-09-09 18:46:22 -0700232 SkRasterClip clip(fForceConservativeRects);
reedd64c9482014-09-05 17:37:38 -0700233 clip.setPath(path, base, doAA);
234 return this->op(clip, op);
235 }
236 } else {
senorblancoafc7cce2016-02-02 18:44:15 -0800237 base.setRect(bounds);
halcanary9d524f22016-03-29 09:03:52 -0700238
reedd64c9482014-09-05 17:37:38 -0700239 if (SkRegion::kReplace_Op == op) {
240 return this->setPath(path, base, doAA);
241 } else {
reedd9544982014-09-09 18:46:22 -0700242 SkRasterClip clip(fForceConservativeRects);
reedd64c9482014-09-05 17:37:38 -0700243 clip.setPath(path, base, doAA);
244 return this->op(clip, op);
245 }
246 }
247}
248
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000249bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
250 SkRegion tmp;
251 tmp.setRect(clip);
252 return this->setPath(path, tmp, doAA);
253}
254
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000255bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000256 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000257
reed@google.coma1c6ff42012-05-11 14:36:57 +0000258 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
259 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000260}
261
reed@google.comba16da92011-10-11 13:15:03 +0000262bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000263 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000264
reed@google.comba16da92011-10-11 13:15:03 +0000265 if (fIsBW) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000266 (void)fBW.op(rgn, op);
reed@google.comba16da92011-10-11 13:15:03 +0000267 } else {
268 SkAAClip tmp;
269 tmp.setRegion(rgn);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000270 (void)fAA.op(tmp, op);
reed@google.comba16da92011-10-11 13:15:03 +0000271 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000272 return this->updateCacheAndReturnNonEmpty();
reed@google.comba16da92011-10-11 13:15:03 +0000273}
274
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000275bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000276 AUTO_RASTERCLIP_VALIDATE(*this);
277 clip.validate();
278
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000279 if (this->isBW() && clip.isBW()) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000280 (void)fBW.op(clip.fBW, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000281 } else {
282 SkAAClip tmp;
283 const SkAAClip* other;
284
285 if (this->isBW()) {
286 this->convertToAA();
287 }
288 if (clip.isBW()) {
289 tmp.setRegion(clip.bwRgn());
290 other = &tmp;
291 } else {
292 other = &clip.aaRgn();
293 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000294 (void)fAA.op(*other, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000295 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000296 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000297}
298
reed@google.com18c464b2012-05-11 20:57:25 +0000299/**
300 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
301 * axis. Thus we can treat an axis coordinate as an integer if it differs
302 * from its nearest int by < half of that value (1.8 in this case).
303 */
304static bool nearly_integral(SkScalar x) {
305 static const SkScalar domain = SK_Scalar1 / 4;
306 static const SkScalar halfDomain = domain / 2;
307
308 x += halfDomain;
309 return x - SkScalarFloorToScalar(x) < domain;
reed@google.com00177082011-10-12 14:34:30 +0000310}
311
senorblancoafc7cce2016-02-02 18:44:15 -0800312bool SkRasterClip::op(const SkRect& r, const SkIRect& bounds, SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000313 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000314
reedd9544982014-09-09 18:46:22 -0700315 if (fForceConservativeRects) {
316 SkIRect ir;
317 switch (mutate_conservative_op(&op, false)) {
318 case kDoNothing_MutateResult:
319 return !this->isEmpty();
320 case kReplaceClippedAgainstGlobalBounds_MutateResult:
senorblancoafc7cce2016-02-02 18:44:15 -0800321 ir = bounds;
reedd9544982014-09-09 18:46:22 -0700322 break;
323 case kContinue_MutateResult:
reedb07a94f2014-11-19 05:03:18 -0800324 ir = r.roundOut();
reedd9544982014-09-09 18:46:22 -0700325 break;
326 }
327 return this->op(ir, op);
328 }
halcanary9d524f22016-03-29 09:03:52 -0700329
reed@google.com420f74f2012-05-11 18:46:43 +0000330 if (fIsBW && doAA) {
reed@google.com18c464b2012-05-11 20:57:25 +0000331 // check that the rect really needs aa, or is it close enought to
332 // integer boundaries that we can just treat it as a BW rect?
333 if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
334 nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
reed@google.com00177082011-10-12 14:34:30 +0000335 doAA = false;
336 }
337 }
338
339 if (fIsBW && !doAA) {
340 SkIRect ir;
341 r.round(&ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000342 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000343 } else {
344 if (fIsBW) {
345 this->convertToAA();
346 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000347 (void)fAA.op(r, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000348 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000349 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000350}
351
reed@google.com34f7e472011-10-13 15:11:59 +0000352void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700353 if (nullptr == dst) {
reed@google.com34f7e472011-10-13 15:11:59 +0000354 return;
355 }
356
reed@google.com045e62d2011-10-24 12:19:46 +0000357 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000358
reed@google.com34f7e472011-10-13 15:11:59 +0000359 if (this->isEmpty()) {
360 dst->setEmpty();
361 return;
362 }
363 if (0 == (dx | dy)) {
364 *dst = *this;
365 return;
366 }
367
368 dst->fIsBW = fIsBW;
369 if (fIsBW) {
370 fBW.translate(dx, dy, &dst->fBW);
371 dst->fAA.setEmpty();
372 } else {
373 fAA.translate(dx, dy, &dst->fAA);
374 dst->fBW.setEmpty();
375 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000376 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000377}
378
reed@google.com045e62d2011-10-24 12:19:46 +0000379bool SkRasterClip::quickContains(const SkIRect& ir) const {
380 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
381}
382
reed@google.com34f7e472011-10-13 15:11:59 +0000383///////////////////////////////////////////////////////////////////////////////
384
reed@google.comba16da92011-10-11 13:15:03 +0000385const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000386 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000387
reed@google.comba16da92011-10-11 13:15:03 +0000388 if (!fIsBW) {
389 fBW.setRect(fAA.getBounds());
390 }
391 return fBW;
392}
393
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000394void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000395 AUTO_RASTERCLIP_VALIDATE(*this);
halcanary9d524f22016-03-29 09:03:52 -0700396
reedd9544982014-09-09 18:46:22 -0700397 SkASSERT(!fForceConservativeRects);
halcanary9d524f22016-03-29 09:03:52 -0700398
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000399 SkASSERT(fIsBW);
400 fAA.setRegion(fBW);
401 fIsBW = false;
halcanary9d524f22016-03-29 09:03:52 -0700402
reed202ab2a2014-08-07 11:48:10 -0700403 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
404 // ourselves back to BW.
405 (void)this->updateCacheAndReturnNonEmpty(false);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000406}
407
reed@google.com045e62d2011-10-24 12:19:46 +0000408#ifdef SK_DEBUG
409void SkRasterClip::validate() const {
410 // can't ever assert that fBW is empty, since we may have called forceGetBW
411 if (fIsBW) {
412 SkASSERT(fAA.isEmpty());
413 }
414
415 fBW.validate();
416 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000417
418 SkASSERT(this->computeIsEmpty() == fIsEmpty);
419 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000420}
421#endif
422
423///////////////////////////////////////////////////////////////////////////////
424
425SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
halcanary96fcdcc2015-08-27 07:41:13 -0700426 SkDEBUGCODE(fClipRgn = nullptr;)
427 SkDEBUGCODE(fBlitter = nullptr;)
reed@google.com045e62d2011-10-24 12:19:46 +0000428}
429
430SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
431 SkBlitter* blitter) {
432 this->init(clip, blitter);
433}
434
435SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
436 SkBlitter* blitter) {
437 SkASSERT(blitter);
438 SkASSERT(aaclip);
439 fBWRgn.setRect(aaclip->getBounds());
440 fAABlitter.init(blitter, aaclip);
441 // now our return values
442 fClipRgn = &fBWRgn;
443 fBlitter = &fAABlitter;
444}
445
446void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
447 SkASSERT(blitter);
448 if (clip.isBW()) {
449 fClipRgn = &clip.bwRgn();
450 fBlitter = blitter;
451 } else {
452 const SkAAClip& aaclip = clip.aaRgn();
453 fBWRgn.setRect(aaclip.getBounds());
454 fAABlitter.init(blitter, &aaclip);
455 // now our return values
456 fClipRgn = &fBWRgn;
457 fBlitter = &fAABlitter;
458 }
459}