blob: a9e043f84fe63569f91924fa2ba8413cfde2e621 [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();
Stan Iliev5f1bb0a2016-12-12 17:39:55 -050024 fClipRestrictionRect = src.fClipRestrictionRect;
reed@google.coma1c6ff42012-05-11 14:36:57 +000025 SkDEBUGCODE(this->validate();)
reed@google.com34f7e472011-10-13 15:11:59 +000026}
27
reed1e7f5e72016-04-27 07:49:17 -070028SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
29 fForceConservativeRects = false;
30 fIsBW = true;
31 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
32 fIsRect = !fIsEmpty;
33 SkDEBUGCODE(this->validate();)
34}
35
reedd9544982014-09-09 18:46:22 -070036SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) {
37 fForceConservativeRects = forceConservativeRects;
reed@google.comba16da92011-10-11 13:15:03 +000038 fIsBW = true;
reed@google.coma1c6ff42012-05-11 14:36:57 +000039 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
40 fIsRect = !fIsEmpty;
41 SkDEBUGCODE(this->validate();)
reed@google.comba16da92011-10-11 13:15:03 +000042}
43
reedd9544982014-09-09 18:46:22 -070044SkRasterClip::SkRasterClip(bool forceConservativeRects) {
45 fForceConservativeRects = forceConservativeRects;
46 fIsBW = true;
47 fIsEmpty = true;
48 fIsRect = false;
49 SkDEBUGCODE(this->validate();)
50}
51
reed@google.com045e62d2011-10-24 12:19:46 +000052SkRasterClip::~SkRasterClip() {
reed@google.coma1c6ff42012-05-11 14:36:57 +000053 SkDEBUGCODE(this->validate();)
reed@google.comd1e3c5f2011-10-10 19:36:25 +000054}
55
reed1e7f5e72016-04-27 07:49:17 -070056bool SkRasterClip::operator==(const SkRasterClip& other) const {
57 // This impl doesn't care if fForceConservativeRects is the same in both, only the current state
58
59 if (fIsBW != other.fIsBW) {
60 return false;
61 }
62 bool isEqual = fIsBW ? fBW == other.fBW : fAA == other.fAA;
63#ifdef SK_DEBUG
64 if (isEqual) {
65 SkASSERT(fIsEmpty == other.fIsEmpty);
66 SkASSERT(fIsRect == other.fIsRect);
67 }
68#endif
69 return isEqual;
70}
71
reed@google.comd1e3c5f2011-10-10 19:36:25 +000072bool SkRasterClip::isComplex() const {
73 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
74}
75
76const SkIRect& SkRasterClip::getBounds() const {
77 return fIsBW ? fBW.getBounds() : fAA.getBounds();
78}
79
80bool SkRasterClip::setEmpty() {
reed@google.com045e62d2011-10-24 12:19:46 +000081 AUTO_RASTERCLIP_VALIDATE(*this);
82
reed@google.comd1e3c5f2011-10-10 19:36:25 +000083 fIsBW = true;
84 fBW.setEmpty();
85 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +000086 fIsEmpty = true;
87 fIsRect = false;
reed@google.comd1e3c5f2011-10-10 19:36:25 +000088 return false;
89}
90
reed@google.comba16da92011-10-11 13:15:03 +000091bool SkRasterClip::setRect(const SkIRect& rect) {
reed@google.com045e62d2011-10-24 12:19:46 +000092 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000093
reed@google.comd1e3c5f2011-10-10 19:36:25 +000094 fIsBW = true;
95 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +000096 fIsRect = fBW.setRect(rect);
97 fIsEmpty = !fIsRect;
98 return fIsRect;
reed@google.comd1e3c5f2011-10-10 19:36:25 +000099}
100
reedd9544982014-09-09 18:46:22 -0700101/////////////////////////////////////////////////////////////////////////////////////
102
103bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
reedd9544982014-09-09 18:46:22 -0700104 SkRegion::Op op;
105 if (isInverse) {
106 op = SkRegion::kDifference_Op;
107 } else {
108 op = SkRegion::kIntersect_Op;
109 }
110 fBW.setRect(clipR);
reedb07a94f2014-11-19 05:03:18 -0800111 fBW.op(r.roundOut(), op);
reedd9544982014-09-09 18:46:22 -0700112 return this->updateCacheAndReturnNonEmpty();
113}
114
115/////////////////////////////////////////////////////////////////////////////////////
116
117enum MutateResult {
118 kDoNothing_MutateResult,
119 kReplaceClippedAgainstGlobalBounds_MutateResult,
120 kContinue_MutateResult,
121};
122
123static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
124 if (inverseFilled) {
125 switch (*op) {
126 case SkRegion::kIntersect_Op:
127 case SkRegion::kDifference_Op:
128 // These ops can only shrink the current clip. So leaving
129 // the clip unchanged conservatively respects the contract.
130 return kDoNothing_MutateResult;
131 case SkRegion::kUnion_Op:
132 case SkRegion::kReplace_Op:
133 case SkRegion::kReverseDifference_Op:
134 case SkRegion::kXOR_Op: {
135 // These ops can grow the current clip up to the extents of
136 // the input clip, which is inverse filled, so we just set
137 // the current clip to the device bounds.
138 *op = SkRegion::kReplace_Op;
139 return kReplaceClippedAgainstGlobalBounds_MutateResult;
140 }
141 }
142 } else {
143 // Not inverse filled
144 switch (*op) {
145 case SkRegion::kIntersect_Op:
146 case SkRegion::kUnion_Op:
147 case SkRegion::kReplace_Op:
148 return kContinue_MutateResult;
149 case SkRegion::kDifference_Op:
150 // Difference can only shrink the current clip.
151 // Leaving clip unchanged conservatively fullfills the contract.
152 return kDoNothing_MutateResult;
153 case SkRegion::kReverseDifference_Op:
154 // To reverse, we swap in the bounds with a replace op.
155 // As with difference, leave it unchanged.
156 *op = SkRegion::kReplace_Op;
157 return kContinue_MutateResult;
158 case SkRegion::kXOR_Op:
159 // Be conservative, based on (A XOR B) always included in (A union B),
160 // which is always included in (bounds(A) union bounds(B))
161 *op = SkRegion::kUnion_Op;
162 return kContinue_MutateResult;
163 }
164 }
165 SkFAIL("should not get here");
166 return kDoNothing_MutateResult;
167}
168
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000169bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000170 AUTO_RASTERCLIP_VALIDATE(*this);
171
reedd9544982014-09-09 18:46:22 -0700172 if (fForceConservativeRects) {
173 return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType());
174 }
175
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000176 if (this->isBW() && !doAA) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000177 (void)fBW.setPath(path, clip);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000178 } else {
reed@google.com897fc412012-02-16 17:11:25 +0000179 // TODO: since we are going to over-write fAA completely (aren't we?)
180 // we should just clear our BW data (if any) and set fIsAA=true
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000181 if (this->isBW()) {
182 this->convertToAA();
183 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000184 (void)fAA.setPath(path, &clip, doAA);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000185 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000186 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000187}
188
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500189bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400190 SkRegion::Op op, bool doAA) {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500191 SkIRect bounds(devBounds);
192 this->applyClipRestriction(op, &bounds);
robertphillips125f19a2015-11-23 09:00:05 -0800193 if (fForceConservativeRects) {
Brian Salomona3b45d42016-10-03 11:36:16 -0400194 return this->op(rrect.getBounds(), matrix, bounds, op, doAA);
robertphillips125f19a2015-11-23 09:00:05 -0800195 }
196
197 SkPath path;
198 path.addRRect(rrect);
199
Brian Salomona3b45d42016-10-03 11:36:16 -0400200 return this->op(path, matrix, bounds, op, doAA);
robertphillips125f19a2015-11-23 09:00:05 -0800201}
202
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500203bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400204 SkRegion::Op op, bool doAA) {
robertphillips125f19a2015-11-23 09:00:05 -0800205 AUTO_RASTERCLIP_VALIDATE(*this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500206 SkIRect bounds(devBounds);
207 this->applyClipRestriction(op, &bounds);
reedd9544982014-09-09 18:46:22 -0700208
209 if (fForceConservativeRects) {
210 SkIRect ir;
211 switch (mutate_conservative_op(&op, path.isInverseFillType())) {
212 case kDoNothing_MutateResult:
213 return !this->isEmpty();
214 case kReplaceClippedAgainstGlobalBounds_MutateResult:
senorblancoafc7cce2016-02-02 18:44:15 -0800215 ir = bounds;
reedd9544982014-09-09 18:46:22 -0700216 break;
Brian Salomona3b45d42016-10-03 11:36:16 -0400217 case kContinue_MutateResult: {
218 SkRect bounds = path.getBounds();
219 matrix.mapRect(&bounds);
220 ir = bounds.roundOut();
reedd9544982014-09-09 18:46:22 -0700221 break;
Brian Salomona3b45d42016-10-03 11:36:16 -0400222 }
reedd9544982014-09-09 18:46:22 -0700223 }
224 return this->op(ir, op);
225 }
226
robertphillips125f19a2015-11-23 09:00:05 -0800227 // base is used to limit the size (and therefore memory allocation) of the
228 // region that results from scan converting devPath.
229 SkRegion base;
230
Brian Salomona3b45d42016-10-03 11:36:16 -0400231 SkPath devPath;
232 if (matrix.isIdentity()) {
233 devPath = path;
234 } else {
235 path.transform(matrix, &devPath);
236 devPath.setIsVolatile(true);
237 }
reedd64c9482014-09-05 17:37:38 -0700238 if (SkRegion::kIntersect_Op == op) {
239 // since we are intersect, we can do better (tighter) with currRgn's
240 // bounds, than just using the device. However, if currRgn is complex,
241 // our region blitter may hork, so we do that case in two steps.
242 if (this->isRect()) {
243 // FIXME: we should also be able to do this when this->isBW(),
244 // but relaxing the test above triggers GM asserts in
245 // SkRgnBuilder::blitH(). We need to investigate what's going on.
Brian Salomona3b45d42016-10-03 11:36:16 -0400246 return this->setPath(devPath, this->bwRgn(), doAA);
reedd64c9482014-09-05 17:37:38 -0700247 } else {
248 base.setRect(this->getBounds());
reedd9544982014-09-09 18:46:22 -0700249 SkRasterClip clip(fForceConservativeRects);
Brian Salomona3b45d42016-10-03 11:36:16 -0400250 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700251 return this->op(clip, op);
252 }
253 } else {
senorblancoafc7cce2016-02-02 18:44:15 -0800254 base.setRect(bounds);
halcanary9d524f22016-03-29 09:03:52 -0700255
reedd64c9482014-09-05 17:37:38 -0700256 if (SkRegion::kReplace_Op == op) {
Brian Salomona3b45d42016-10-03 11:36:16 -0400257 return this->setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700258 } else {
reedd9544982014-09-09 18:46:22 -0700259 SkRasterClip clip(fForceConservativeRects);
Brian Salomona3b45d42016-10-03 11:36:16 -0400260 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700261 return this->op(clip, op);
262 }
263 }
264}
265
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000266bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
267 SkRegion tmp;
268 tmp.setRect(clip);
269 return this->setPath(path, tmp, doAA);
270}
271
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000272bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000273 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000274
reed@google.coma1c6ff42012-05-11 14:36:57 +0000275 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
276 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000277}
278
reed@google.comba16da92011-10-11 13:15:03 +0000279bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000280 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000281
reed@google.comba16da92011-10-11 13:15:03 +0000282 if (fIsBW) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000283 (void)fBW.op(rgn, op);
reed@google.comba16da92011-10-11 13:15:03 +0000284 } else {
285 SkAAClip tmp;
286 tmp.setRegion(rgn);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000287 (void)fAA.op(tmp, op);
reed@google.comba16da92011-10-11 13:15:03 +0000288 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000289 return this->updateCacheAndReturnNonEmpty();
reed@google.comba16da92011-10-11 13:15:03 +0000290}
291
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000292bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000293 AUTO_RASTERCLIP_VALIDATE(*this);
294 clip.validate();
295
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000296 if (this->isBW() && clip.isBW()) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000297 (void)fBW.op(clip.fBW, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000298 } else {
299 SkAAClip tmp;
300 const SkAAClip* other;
301
302 if (this->isBW()) {
303 this->convertToAA();
304 }
305 if (clip.isBW()) {
306 tmp.setRegion(clip.bwRgn());
307 other = &tmp;
308 } else {
309 other = &clip.aaRgn();
310 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000311 (void)fAA.op(*other, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000312 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000313 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000314}
315
reed@google.com18c464b2012-05-11 20:57:25 +0000316/**
317 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
318 * axis. Thus we can treat an axis coordinate as an integer if it differs
319 * from its nearest int by < half of that value (1.8 in this case).
320 */
321static bool nearly_integral(SkScalar x) {
322 static const SkScalar domain = SK_Scalar1 / 4;
323 static const SkScalar halfDomain = domain / 2;
324
325 x += halfDomain;
326 return x - SkScalarFloorToScalar(x) < domain;
reed@google.com00177082011-10-12 14:34:30 +0000327}
328
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500329bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400330 SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000331 AUTO_RASTERCLIP_VALIDATE(*this);
Brian Salomona3b45d42016-10-03 11:36:16 -0400332 SkRect devRect;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000333
reedd9544982014-09-09 18:46:22 -0700334 if (fForceConservativeRects) {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500335 SkIRect bounds(devBounds);
336 this->applyClipRestriction(op, &bounds);
reedd9544982014-09-09 18:46:22 -0700337 SkIRect ir;
338 switch (mutate_conservative_op(&op, false)) {
339 case kDoNothing_MutateResult:
340 return !this->isEmpty();
341 case kReplaceClippedAgainstGlobalBounds_MutateResult:
senorblancoafc7cce2016-02-02 18:44:15 -0800342 ir = bounds;
reedd9544982014-09-09 18:46:22 -0700343 break;
344 case kContinue_MutateResult:
Brian Salomona3b45d42016-10-03 11:36:16 -0400345 matrix.mapRect(&devRect, localRect);
346 ir = devRect.roundOut();
reedd9544982014-09-09 18:46:22 -0700347 break;
348 }
349 return this->op(ir, op);
350 }
Brian Salomona3b45d42016-10-03 11:36:16 -0400351 const bool isScaleTrans = matrix.isScaleTranslate();
352 if (!isScaleTrans) {
353 SkPath path;
354 path.addRect(localRect);
355 path.setIsVolatile(true);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500356 return this->op(path, matrix, devBounds, op, doAA);
Brian Salomona3b45d42016-10-03 11:36:16 -0400357 }
358
359 matrix.mapRect(&devRect, localRect);
halcanary9d524f22016-03-29 09:03:52 -0700360
reed@google.com420f74f2012-05-11 18:46:43 +0000361 if (fIsBW && doAA) {
reed@google.com18c464b2012-05-11 20:57:25 +0000362 // check that the rect really needs aa, or is it close enought to
363 // integer boundaries that we can just treat it as a BW rect?
Brian Salomona3b45d42016-10-03 11:36:16 -0400364 if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
365 nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
reed@google.com00177082011-10-12 14:34:30 +0000366 doAA = false;
367 }
368 }
369
370 if (fIsBW && !doAA) {
371 SkIRect ir;
Brian Salomona3b45d42016-10-03 11:36:16 -0400372 devRect.round(&ir);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500373 this->applyClipRestriction(op, &ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000374 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000375 } else {
376 if (fIsBW) {
377 this->convertToAA();
378 }
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500379 this->applyClipRestriction(op, &devRect);
Brian Salomona3b45d42016-10-03 11:36:16 -0400380 (void)fAA.op(devRect, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000381 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000382 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000383}
384
reed@google.com34f7e472011-10-13 15:11:59 +0000385void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700386 if (nullptr == dst) {
reed@google.com34f7e472011-10-13 15:11:59 +0000387 return;
388 }
389
reed@google.com045e62d2011-10-24 12:19:46 +0000390 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000391
reed@google.com34f7e472011-10-13 15:11:59 +0000392 if (this->isEmpty()) {
393 dst->setEmpty();
394 return;
395 }
396 if (0 == (dx | dy)) {
397 *dst = *this;
398 return;
399 }
400
401 dst->fIsBW = fIsBW;
402 if (fIsBW) {
403 fBW.translate(dx, dy, &dst->fBW);
404 dst->fAA.setEmpty();
405 } else {
406 fAA.translate(dx, dy, &dst->fAA);
407 dst->fBW.setEmpty();
408 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000409 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000410}
411
reed@google.com045e62d2011-10-24 12:19:46 +0000412bool SkRasterClip::quickContains(const SkIRect& ir) const {
413 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
414}
415
reed@google.com34f7e472011-10-13 15:11:59 +0000416///////////////////////////////////////////////////////////////////////////////
417
reed@google.comba16da92011-10-11 13:15:03 +0000418const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000419 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000420
reed@google.comba16da92011-10-11 13:15:03 +0000421 if (!fIsBW) {
422 fBW.setRect(fAA.getBounds());
423 }
424 return fBW;
425}
426
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000427void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000428 AUTO_RASTERCLIP_VALIDATE(*this);
halcanary9d524f22016-03-29 09:03:52 -0700429
reedd9544982014-09-09 18:46:22 -0700430 SkASSERT(!fForceConservativeRects);
halcanary9d524f22016-03-29 09:03:52 -0700431
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000432 SkASSERT(fIsBW);
433 fAA.setRegion(fBW);
434 fIsBW = false;
halcanary9d524f22016-03-29 09:03:52 -0700435
reed202ab2a2014-08-07 11:48:10 -0700436 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
437 // ourselves back to BW.
438 (void)this->updateCacheAndReturnNonEmpty(false);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000439}
440
reed@google.com045e62d2011-10-24 12:19:46 +0000441#ifdef SK_DEBUG
442void SkRasterClip::validate() const {
443 // can't ever assert that fBW is empty, since we may have called forceGetBW
444 if (fIsBW) {
445 SkASSERT(fAA.isEmpty());
446 }
447
448 fBW.validate();
449 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000450
451 SkASSERT(this->computeIsEmpty() == fIsEmpty);
452 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000453}
454#endif
455
456///////////////////////////////////////////////////////////////////////////////
457
458SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
halcanary96fcdcc2015-08-27 07:41:13 -0700459 SkDEBUGCODE(fClipRgn = nullptr;)
460 SkDEBUGCODE(fBlitter = nullptr;)
reed@google.com045e62d2011-10-24 12:19:46 +0000461}
462
463SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
464 SkBlitter* blitter) {
465 this->init(clip, blitter);
466}
467
468SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
469 SkBlitter* blitter) {
470 SkASSERT(blitter);
471 SkASSERT(aaclip);
472 fBWRgn.setRect(aaclip->getBounds());
473 fAABlitter.init(blitter, aaclip);
474 // now our return values
475 fClipRgn = &fBWRgn;
476 fBlitter = &fAABlitter;
477}
478
479void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
480 SkASSERT(blitter);
481 if (clip.isBW()) {
482 fClipRgn = &clip.bwRgn();
483 fBlitter = blitter;
484 } else {
485 const SkAAClip& aaclip = clip.aaRgn();
486 fBWRgn.setRect(aaclip.getBounds());
487 fAABlitter.init(blitter, &aaclip);
488 // now our return values
489 fClipRgn = &fBWRgn;
490 fBlitter = &fAABlitter;
491 }
492}