blob: f43d14e483578138af7f3179c895a20bd2d31ac7 [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
Mike Reeda1361362017-03-07 09:37:29 -050011enum MutateResult {
12 kDoNothing_MutateResult,
13 kReplaceClippedAgainstGlobalBounds_MutateResult,
14 kContinue_MutateResult,
15};
16
17static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
18 if (inverseFilled) {
19 switch (*op) {
20 case SkRegion::kIntersect_Op:
21 case SkRegion::kDifference_Op:
22 // These ops can only shrink the current clip. So leaving
23 // the clip unchanged conservatively respects the contract.
24 return kDoNothing_MutateResult;
25 case SkRegion::kUnion_Op:
26 case SkRegion::kReplace_Op:
27 case SkRegion::kReverseDifference_Op:
28 case SkRegion::kXOR_Op: {
29 // These ops can grow the current clip up to the extents of
30 // the input clip, which is inverse filled, so we just set
31 // the current clip to the device bounds.
32 *op = SkRegion::kReplace_Op;
33 return kReplaceClippedAgainstGlobalBounds_MutateResult;
34 }
35 }
36 } else {
37 // Not inverse filled
38 switch (*op) {
39 case SkRegion::kIntersect_Op:
40 case SkRegion::kUnion_Op:
41 case SkRegion::kReplace_Op:
42 return kContinue_MutateResult;
43 case SkRegion::kDifference_Op:
44 // Difference can only shrink the current clip.
45 // Leaving clip unchanged conservatively fullfills the contract.
46 return kDoNothing_MutateResult;
47 case SkRegion::kReverseDifference_Op:
48 // To reverse, we swap in the bounds with a replace op.
49 // As with difference, leave it unchanged.
50 *op = SkRegion::kReplace_Op;
51 return kContinue_MutateResult;
52 case SkRegion::kXOR_Op:
53 // Be conservative, based on (A XOR B) always included in (A union B),
54 // which is always included in (bounds(A) union bounds(B))
55 *op = SkRegion::kUnion_Op;
56 return kContinue_MutateResult;
57 }
58 }
59 SkFAIL("should not get here");
60 return kDoNothing_MutateResult;
61}
62
63void SkConservativeClip::op(const SkRect& localRect, const SkMatrix& ctm, const SkIRect& devBounds,
64 SkRegion::Op op, bool doAA) {
65 SkRect devRect;
66
67 SkIRect bounds(devBounds);
68 this->applyClipRestriction(op, &bounds);
69 SkIRect ir;
70 switch (mutate_conservative_op(&op, false)) {
71 case kDoNothing_MutateResult:
72 return;
73 case kReplaceClippedAgainstGlobalBounds_MutateResult:
74 ir = bounds;
75 break;
76 case kContinue_MutateResult:
77 ctm.mapRect(&devRect, localRect);
78 ir = doAA ? devRect.roundOut() : devRect.round();
79 break;
80 }
81 this->op(ir, op);
82}
83
84void SkConservativeClip::op(const SkRRect& rrect, const SkMatrix& ctm, const SkIRect& devBounds,
85 SkRegion::Op op, bool doAA) {
86 SkIRect bounds(devBounds);
87 this->applyClipRestriction(op, &bounds);
88 this->op(rrect.getBounds(), ctm, bounds, op, doAA);
89}
90
91void SkConservativeClip::op(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds,
92 SkRegion::Op op, bool doAA) {
93 SkIRect bounds(devBounds);
94 this->applyClipRestriction(op, &bounds);
95
96 SkIRect ir;
97 switch (mutate_conservative_op(&op, path.isInverseFillType())) {
98 case kDoNothing_MutateResult:
99 return;
100 case kReplaceClippedAgainstGlobalBounds_MutateResult:
101 ir = bounds;
102 break;
103 case kContinue_MutateResult: {
104 SkRect bounds = path.getBounds();
105 ctm.mapRect(&bounds);
106 ir = bounds.roundOut();
107 break;
108 }
109 }
110 return this->op(ir, op);
111}
112
113void SkConservativeClip::op(const SkRegion& rgn, SkRegion::Op op) {
114 this->op(rgn.getBounds(), op);
115}
116
117void SkConservativeClip::op(const SkIRect& devRect, SkRegion::Op op) {
118 // This may still create a complex region (which we would then take the bounds
119 // Perhaps we should inline the op-logic directly to never create the rgn...
120 SkRegion result;
121 result.op(SkRegion(fBounds), SkRegion(devRect), op);
122 fBounds = result.getBounds();
123}
124
125///////////////////////////////////////////////////////////////////////////////////////////////////
126
reed@google.com34f7e472011-10-13 15:11:59 +0000127SkRasterClip::SkRasterClip(const SkRasterClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000128 AUTO_RASTERCLIP_VALIDATE(src);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000129
reed@google.com34f7e472011-10-13 15:11:59 +0000130 fIsBW = src.fIsBW;
131 if (fIsBW) {
132 fBW = src.fBW;
133 } else {
134 fAA = src.fAA;
135 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000136
137 fIsEmpty = src.isEmpty();
138 fIsRect = src.isRect();
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500139 fClipRestrictionRect = src.fClipRestrictionRect;
reed@google.coma1c6ff42012-05-11 14:36:57 +0000140 SkDEBUGCODE(this->validate();)
reed@google.com34f7e472011-10-13 15:11:59 +0000141}
142
reed1e7f5e72016-04-27 07:49:17 -0700143SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
reed1e7f5e72016-04-27 07:49:17 -0700144 fIsBW = true;
145 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
146 fIsRect = !fIsEmpty;
147 SkDEBUGCODE(this->validate();)
148}
149
Mike Reeda1361362017-03-07 09:37:29 -0500150SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
reed@google.comba16da92011-10-11 13:15:03 +0000151 fIsBW = true;
reed@google.coma1c6ff42012-05-11 14:36:57 +0000152 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
153 fIsRect = !fIsEmpty;
154 SkDEBUGCODE(this->validate();)
reed@google.comba16da92011-10-11 13:15:03 +0000155}
156
Mike Reeda1361362017-03-07 09:37:29 -0500157SkRasterClip::SkRasterClip() {
reedd9544982014-09-09 18:46:22 -0700158 fIsBW = true;
159 fIsEmpty = true;
160 fIsRect = false;
161 SkDEBUGCODE(this->validate();)
162}
163
reed@google.com045e62d2011-10-24 12:19:46 +0000164SkRasterClip::~SkRasterClip() {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000165 SkDEBUGCODE(this->validate();)
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000166}
167
reed1e7f5e72016-04-27 07:49:17 -0700168bool SkRasterClip::operator==(const SkRasterClip& other) const {
reed1e7f5e72016-04-27 07:49:17 -0700169 if (fIsBW != other.fIsBW) {
170 return false;
171 }
172 bool isEqual = fIsBW ? fBW == other.fBW : fAA == other.fAA;
173#ifdef SK_DEBUG
174 if (isEqual) {
175 SkASSERT(fIsEmpty == other.fIsEmpty);
176 SkASSERT(fIsRect == other.fIsRect);
177 }
178#endif
179 return isEqual;
180}
181
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000182bool SkRasterClip::isComplex() const {
183 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
184}
185
186const SkIRect& SkRasterClip::getBounds() const {
187 return fIsBW ? fBW.getBounds() : fAA.getBounds();
188}
189
190bool SkRasterClip::setEmpty() {
reed@google.com045e62d2011-10-24 12:19:46 +0000191 AUTO_RASTERCLIP_VALIDATE(*this);
192
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000193 fIsBW = true;
194 fBW.setEmpty();
195 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000196 fIsEmpty = true;
197 fIsRect = false;
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000198 return false;
199}
200
reed@google.comba16da92011-10-11 13:15:03 +0000201bool SkRasterClip::setRect(const SkIRect& rect) {
reed@google.com045e62d2011-10-24 12:19:46 +0000202 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000203
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000204 fIsBW = true;
205 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000206 fIsRect = fBW.setRect(rect);
207 fIsEmpty = !fIsRect;
208 return fIsRect;
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000209}
210
reedd9544982014-09-09 18:46:22 -0700211/////////////////////////////////////////////////////////////////////////////////////
212
213bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
reedd9544982014-09-09 18:46:22 -0700214 SkRegion::Op op;
215 if (isInverse) {
216 op = SkRegion::kDifference_Op;
217 } else {
218 op = SkRegion::kIntersect_Op;
219 }
220 fBW.setRect(clipR);
reedb07a94f2014-11-19 05:03:18 -0800221 fBW.op(r.roundOut(), op);
reedd9544982014-09-09 18:46:22 -0700222 return this->updateCacheAndReturnNonEmpty();
223}
224
225/////////////////////////////////////////////////////////////////////////////////////
226
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000227bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000228 AUTO_RASTERCLIP_VALIDATE(*this);
229
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000230 if (this->isBW() && !doAA) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000231 (void)fBW.setPath(path, clip);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000232 } else {
reed@google.com897fc412012-02-16 17:11:25 +0000233 // TODO: since we are going to over-write fAA completely (aren't we?)
234 // we should just clear our BW data (if any) and set fIsAA=true
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000235 if (this->isBW()) {
236 this->convertToAA();
237 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000238 (void)fAA.setPath(path, &clip, doAA);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000239 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000240 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000241}
242
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500243bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400244 SkRegion::Op op, bool doAA) {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500245 SkIRect bounds(devBounds);
246 this->applyClipRestriction(op, &bounds);
robertphillips125f19a2015-11-23 09:00:05 -0800247
248 SkPath path;
249 path.addRRect(rrect);
250
Brian Salomona3b45d42016-10-03 11:36:16 -0400251 return this->op(path, matrix, bounds, op, doAA);
robertphillips125f19a2015-11-23 09:00:05 -0800252}
253
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500254bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400255 SkRegion::Op op, bool doAA) {
robertphillips125f19a2015-11-23 09:00:05 -0800256 AUTO_RASTERCLIP_VALIDATE(*this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500257 SkIRect bounds(devBounds);
258 this->applyClipRestriction(op, &bounds);
reedd9544982014-09-09 18:46:22 -0700259
robertphillips125f19a2015-11-23 09:00:05 -0800260 // base is used to limit the size (and therefore memory allocation) of the
261 // region that results from scan converting devPath.
262 SkRegion base;
263
Brian Salomona3b45d42016-10-03 11:36:16 -0400264 SkPath devPath;
265 if (matrix.isIdentity()) {
266 devPath = path;
267 } else {
268 path.transform(matrix, &devPath);
269 devPath.setIsVolatile(true);
270 }
reedd64c9482014-09-05 17:37:38 -0700271 if (SkRegion::kIntersect_Op == op) {
272 // since we are intersect, we can do better (tighter) with currRgn's
273 // bounds, than just using the device. However, if currRgn is complex,
274 // our region blitter may hork, so we do that case in two steps.
275 if (this->isRect()) {
276 // FIXME: we should also be able to do this when this->isBW(),
277 // but relaxing the test above triggers GM asserts in
278 // SkRgnBuilder::blitH(). We need to investigate what's going on.
Brian Salomona3b45d42016-10-03 11:36:16 -0400279 return this->setPath(devPath, this->bwRgn(), doAA);
reedd64c9482014-09-05 17:37:38 -0700280 } else {
281 base.setRect(this->getBounds());
Mike Reeda1361362017-03-07 09:37:29 -0500282 SkRasterClip clip;
Brian Salomona3b45d42016-10-03 11:36:16 -0400283 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700284 return this->op(clip, op);
285 }
286 } else {
senorblancoafc7cce2016-02-02 18:44:15 -0800287 base.setRect(bounds);
halcanary9d524f22016-03-29 09:03:52 -0700288
reedd64c9482014-09-05 17:37:38 -0700289 if (SkRegion::kReplace_Op == op) {
Brian Salomona3b45d42016-10-03 11:36:16 -0400290 return this->setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700291 } else {
Mike Reeda1361362017-03-07 09:37:29 -0500292 SkRasterClip clip;
Brian Salomona3b45d42016-10-03 11:36:16 -0400293 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700294 return this->op(clip, op);
295 }
296 }
297}
298
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000299bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
300 SkRegion tmp;
301 tmp.setRect(clip);
302 return this->setPath(path, tmp, doAA);
303}
304
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000305bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000306 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000307
reed@google.coma1c6ff42012-05-11 14:36:57 +0000308 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
309 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000310}
311
reed@google.comba16da92011-10-11 13:15:03 +0000312bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000313 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000314
reed@google.comba16da92011-10-11 13:15:03 +0000315 if (fIsBW) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000316 (void)fBW.op(rgn, op);
reed@google.comba16da92011-10-11 13:15:03 +0000317 } else {
318 SkAAClip tmp;
319 tmp.setRegion(rgn);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000320 (void)fAA.op(tmp, op);
reed@google.comba16da92011-10-11 13:15:03 +0000321 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000322 return this->updateCacheAndReturnNonEmpty();
reed@google.comba16da92011-10-11 13:15:03 +0000323}
324
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000325bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000326 AUTO_RASTERCLIP_VALIDATE(*this);
327 clip.validate();
328
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000329 if (this->isBW() && clip.isBW()) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000330 (void)fBW.op(clip.fBW, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000331 } else {
332 SkAAClip tmp;
333 const SkAAClip* other;
334
335 if (this->isBW()) {
336 this->convertToAA();
337 }
338 if (clip.isBW()) {
339 tmp.setRegion(clip.bwRgn());
340 other = &tmp;
341 } else {
342 other = &clip.aaRgn();
343 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000344 (void)fAA.op(*other, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000345 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000346 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000347}
348
reed@google.com18c464b2012-05-11 20:57:25 +0000349/**
350 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
351 * axis. Thus we can treat an axis coordinate as an integer if it differs
352 * from its nearest int by < half of that value (1.8 in this case).
353 */
354static bool nearly_integral(SkScalar x) {
355 static const SkScalar domain = SK_Scalar1 / 4;
356 static const SkScalar halfDomain = domain / 2;
357
358 x += halfDomain;
359 return x - SkScalarFloorToScalar(x) < domain;
reed@google.com00177082011-10-12 14:34:30 +0000360}
361
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500362bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400363 SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000364 AUTO_RASTERCLIP_VALIDATE(*this);
Brian Salomona3b45d42016-10-03 11:36:16 -0400365 SkRect devRect;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000366
Brian Salomona3b45d42016-10-03 11:36:16 -0400367 const bool isScaleTrans = matrix.isScaleTranslate();
368 if (!isScaleTrans) {
369 SkPath path;
370 path.addRect(localRect);
371 path.setIsVolatile(true);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500372 return this->op(path, matrix, devBounds, op, doAA);
Brian Salomona3b45d42016-10-03 11:36:16 -0400373 }
374
375 matrix.mapRect(&devRect, localRect);
halcanary9d524f22016-03-29 09:03:52 -0700376
reed@google.com420f74f2012-05-11 18:46:43 +0000377 if (fIsBW && doAA) {
reed@google.com18c464b2012-05-11 20:57:25 +0000378 // check that the rect really needs aa, or is it close enought to
379 // integer boundaries that we can just treat it as a BW rect?
Brian Salomona3b45d42016-10-03 11:36:16 -0400380 if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
381 nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
reed@google.com00177082011-10-12 14:34:30 +0000382 doAA = false;
383 }
384 }
385
386 if (fIsBW && !doAA) {
387 SkIRect ir;
Brian Salomona3b45d42016-10-03 11:36:16 -0400388 devRect.round(&ir);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500389 this->applyClipRestriction(op, &ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000390 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000391 } else {
392 if (fIsBW) {
393 this->convertToAA();
394 }
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500395 this->applyClipRestriction(op, &devRect);
Brian Salomona3b45d42016-10-03 11:36:16 -0400396 (void)fAA.op(devRect, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000397 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000398 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000399}
400
reed@google.com34f7e472011-10-13 15:11:59 +0000401void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 if (nullptr == dst) {
reed@google.com34f7e472011-10-13 15:11:59 +0000403 return;
404 }
405
reed@google.com045e62d2011-10-24 12:19:46 +0000406 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000407
reed@google.com34f7e472011-10-13 15:11:59 +0000408 if (this->isEmpty()) {
409 dst->setEmpty();
410 return;
411 }
412 if (0 == (dx | dy)) {
413 *dst = *this;
414 return;
415 }
416
417 dst->fIsBW = fIsBW;
418 if (fIsBW) {
419 fBW.translate(dx, dy, &dst->fBW);
420 dst->fAA.setEmpty();
421 } else {
422 fAA.translate(dx, dy, &dst->fAA);
423 dst->fBW.setEmpty();
424 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000425 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000426}
427
reed@google.com045e62d2011-10-24 12:19:46 +0000428bool SkRasterClip::quickContains(const SkIRect& ir) const {
429 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
430}
431
reed@google.com34f7e472011-10-13 15:11:59 +0000432///////////////////////////////////////////////////////////////////////////////
433
reed@google.comba16da92011-10-11 13:15:03 +0000434const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000435 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000436
reed@google.comba16da92011-10-11 13:15:03 +0000437 if (!fIsBW) {
438 fBW.setRect(fAA.getBounds());
439 }
440 return fBW;
441}
442
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000443void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000444 AUTO_RASTERCLIP_VALIDATE(*this);
halcanary9d524f22016-03-29 09:03:52 -0700445
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000446 SkASSERT(fIsBW);
447 fAA.setRegion(fBW);
448 fIsBW = false;
halcanary9d524f22016-03-29 09:03:52 -0700449
reed202ab2a2014-08-07 11:48:10 -0700450 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
451 // ourselves back to BW.
452 (void)this->updateCacheAndReturnNonEmpty(false);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000453}
454
reed@google.com045e62d2011-10-24 12:19:46 +0000455#ifdef SK_DEBUG
456void SkRasterClip::validate() const {
457 // can't ever assert that fBW is empty, since we may have called forceGetBW
458 if (fIsBW) {
459 SkASSERT(fAA.isEmpty());
460 }
461
462 fBW.validate();
463 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000464
465 SkASSERT(this->computeIsEmpty() == fIsEmpty);
466 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000467}
468#endif
469
470///////////////////////////////////////////////////////////////////////////////
471
472SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
halcanary96fcdcc2015-08-27 07:41:13 -0700473 SkDEBUGCODE(fClipRgn = nullptr;)
474 SkDEBUGCODE(fBlitter = nullptr;)
reed@google.com045e62d2011-10-24 12:19:46 +0000475}
476
477SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
478 SkBlitter* blitter) {
479 this->init(clip, blitter);
480}
481
482SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
483 SkBlitter* blitter) {
484 SkASSERT(blitter);
485 SkASSERT(aaclip);
486 fBWRgn.setRect(aaclip->getBounds());
487 fAABlitter.init(blitter, aaclip);
488 // now our return values
489 fClipRgn = &fBWRgn;
490 fBlitter = &fAABlitter;
491}
492
493void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
494 SkASSERT(blitter);
495 if (clip.isBW()) {
496 fClipRgn = &clip.bwRgn();
497 fBlitter = blitter;
498 } else {
499 const SkAAClip& aaclip = clip.aaRgn();
500 fBWRgn.setRect(aaclip.getBounds());
501 fAABlitter.init(blitter, &aaclip);
502 // now our return values
503 fClipRgn = &fBWRgn;
504 fBlitter = &fAABlitter;
505 }
506}