blob: f3ebe4c1f6d83c83f9b4a42baa3119bb81b16c5d [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"
Cary Clark69436892018-07-28 10:14:27 -040010#include "SkRegionPriv.h"
reed@google.comd1e3c5f2011-10-10 19:36:25 +000011
Mike Reeda1361362017-03-07 09:37:29 -050012enum MutateResult {
13 kDoNothing_MutateResult,
14 kReplaceClippedAgainstGlobalBounds_MutateResult,
15 kContinue_MutateResult,
16};
17
18static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
19 if (inverseFilled) {
20 switch (*op) {
21 case SkRegion::kIntersect_Op:
22 case SkRegion::kDifference_Op:
23 // These ops can only shrink the current clip. So leaving
24 // the clip unchanged conservatively respects the contract.
25 return kDoNothing_MutateResult;
26 case SkRegion::kUnion_Op:
27 case SkRegion::kReplace_Op:
28 case SkRegion::kReverseDifference_Op:
29 case SkRegion::kXOR_Op: {
30 // These ops can grow the current clip up to the extents of
31 // the input clip, which is inverse filled, so we just set
32 // the current clip to the device bounds.
33 *op = SkRegion::kReplace_Op;
34 return kReplaceClippedAgainstGlobalBounds_MutateResult;
35 }
36 }
37 } else {
38 // Not inverse filled
39 switch (*op) {
40 case SkRegion::kIntersect_Op:
41 case SkRegion::kUnion_Op:
42 case SkRegion::kReplace_Op:
43 return kContinue_MutateResult;
44 case SkRegion::kDifference_Op:
45 // Difference can only shrink the current clip.
46 // Leaving clip unchanged conservatively fullfills the contract.
47 return kDoNothing_MutateResult;
48 case SkRegion::kReverseDifference_Op:
49 // To reverse, we swap in the bounds with a replace op.
50 // As with difference, leave it unchanged.
51 *op = SkRegion::kReplace_Op;
52 return kContinue_MutateResult;
53 case SkRegion::kXOR_Op:
54 // Be conservative, based on (A XOR B) always included in (A union B),
55 // which is always included in (bounds(A) union bounds(B))
56 *op = SkRegion::kUnion_Op;
57 return kContinue_MutateResult;
58 }
59 }
Mike Reed20800c82017-11-15 16:09:04 -050060 SkASSERT(false); // unknown op
Mike Reeda1361362017-03-07 09:37:29 -050061 return kDoNothing_MutateResult;
62}
63
Mike Reed20800c82017-11-15 16:09:04 -050064void SkConservativeClip::opRect(const SkRect& localRect, const SkMatrix& ctm,
65 const SkIRect& devBounds, SkRegion::Op op, bool doAA) {
Mike Reeda1361362017-03-07 09:37:29 -050066 SkIRect ir;
67 switch (mutate_conservative_op(&op, false)) {
68 case kDoNothing_MutateResult:
69 return;
70 case kReplaceClippedAgainstGlobalBounds_MutateResult:
Mike Reed2a65cc02017-03-22 10:01:53 -040071 ir = devBounds;
Mike Reeda1361362017-03-07 09:37:29 -050072 break;
Mike Reed2a65cc02017-03-22 10:01:53 -040073 case kContinue_MutateResult: {
74 SkRect devRect;
Mike Reeda1361362017-03-07 09:37:29 -050075 ctm.mapRect(&devRect, localRect);
76 ir = doAA ? devRect.roundOut() : devRect.round();
Mike Reed2a65cc02017-03-22 10:01:53 -040077 } break;
Mike Reeda1361362017-03-07 09:37:29 -050078 }
Mike Reed20800c82017-11-15 16:09:04 -050079 this->opIRect(ir, op);
Mike Reeda1361362017-03-07 09:37:29 -050080}
81
Mike Reed20800c82017-11-15 16:09:04 -050082void SkConservativeClip::opRRect(const SkRRect& rrect, const SkMatrix& ctm,
83 const SkIRect& devBounds, SkRegion::Op op, bool doAA) {
84 this->opRect(rrect.getBounds(), ctm, devBounds, op, doAA);
Mike Reeda1361362017-03-07 09:37:29 -050085}
86
Mike Reed20800c82017-11-15 16:09:04 -050087void SkConservativeClip::opPath(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds,
88 SkRegion::Op op, bool doAA) {
Mike Reeda1361362017-03-07 09:37:29 -050089 SkIRect ir;
90 switch (mutate_conservative_op(&op, path.isInverseFillType())) {
91 case kDoNothing_MutateResult:
92 return;
93 case kReplaceClippedAgainstGlobalBounds_MutateResult:
Mike Reed2a65cc02017-03-22 10:01:53 -040094 ir = devBounds;
Mike Reeda1361362017-03-07 09:37:29 -050095 break;
96 case kContinue_MutateResult: {
97 SkRect bounds = path.getBounds();
98 ctm.mapRect(&bounds);
99 ir = bounds.roundOut();
100 break;
101 }
102 }
Mike Reed20800c82017-11-15 16:09:04 -0500103 return this->opIRect(ir, op);
Mike Reeda1361362017-03-07 09:37:29 -0500104}
105
Mike Reed20800c82017-11-15 16:09:04 -0500106void SkConservativeClip::opRegion(const SkRegion& rgn, SkRegion::Op op) {
107 this->opIRect(rgn.getBounds(), op);
Mike Reeda1361362017-03-07 09:37:29 -0500108}
109
Mike Reed20800c82017-11-15 16:09:04 -0500110void SkConservativeClip::opIRect(const SkIRect& devRect, SkRegion::Op op) {
Mike Reedca490672017-03-07 14:55:37 -0500111 if (SkRegion::kIntersect_Op == op) {
Mike Reed02be3c12017-03-23 12:34:15 -0400112 if (!fBounds.intersect(devRect)) {
Mike Reedca490672017-03-07 14:55:37 -0500113 fBounds.setEmpty();
Mike Reedca490672017-03-07 14:55:37 -0500114 }
115 return;
116 }
117
Mike Reeda1361362017-03-07 09:37:29 -0500118 // 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();
Mike Reed2a65cc02017-03-22 10:01:53 -0400123 this->applyClipRestriction(op, &fBounds);
Mike Reeda1361362017-03-07 09:37:29 -0500124}
125
126///////////////////////////////////////////////////////////////////////////////////////////////////
127
reed@google.com34f7e472011-10-13 15:11:59 +0000128SkRasterClip::SkRasterClip(const SkRasterClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000129 AUTO_RASTERCLIP_VALIDATE(src);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000130
reed@google.com34f7e472011-10-13 15:11:59 +0000131 fIsBW = src.fIsBW;
132 if (fIsBW) {
133 fBW = src.fBW;
134 } else {
135 fAA = src.fAA;
136 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000137
138 fIsEmpty = src.isEmpty();
139 fIsRect = src.isRect();
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500140 fClipRestrictionRect = src.fClipRestrictionRect;
reed@google.coma1c6ff42012-05-11 14:36:57 +0000141 SkDEBUGCODE(this->validate();)
reed@google.com34f7e472011-10-13 15:11:59 +0000142}
143
reed1e7f5e72016-04-27 07:49:17 -0700144SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
reed1e7f5e72016-04-27 07:49:17 -0700145 fIsBW = true;
146 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
147 fIsRect = !fIsEmpty;
148 SkDEBUGCODE(this->validate();)
149}
150
Mike Reeda1361362017-03-07 09:37:29 -0500151SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
reed@google.comba16da92011-10-11 13:15:03 +0000152 fIsBW = true;
reed@google.coma1c6ff42012-05-11 14:36:57 +0000153 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
154 fIsRect = !fIsEmpty;
155 SkDEBUGCODE(this->validate();)
reed@google.comba16da92011-10-11 13:15:03 +0000156}
157
Mike Reeda1361362017-03-07 09:37:29 -0500158SkRasterClip::SkRasterClip() {
reedd9544982014-09-09 18:46:22 -0700159 fIsBW = true;
160 fIsEmpty = true;
161 fIsRect = false;
162 SkDEBUGCODE(this->validate();)
163}
164
reed@google.com045e62d2011-10-24 12:19:46 +0000165SkRasterClip::~SkRasterClip() {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000166 SkDEBUGCODE(this->validate();)
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000167}
168
reed1e7f5e72016-04-27 07:49:17 -0700169bool SkRasterClip::operator==(const SkRasterClip& other) const {
reed1e7f5e72016-04-27 07:49:17 -0700170 if (fIsBW != other.fIsBW) {
171 return false;
172 }
173 bool isEqual = fIsBW ? fBW == other.fBW : fAA == other.fAA;
174#ifdef SK_DEBUG
175 if (isEqual) {
176 SkASSERT(fIsEmpty == other.fIsEmpty);
177 SkASSERT(fIsRect == other.fIsRect);
178 }
179#endif
180 return isEqual;
181}
182
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000183bool SkRasterClip::isComplex() const {
184 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
185}
186
187const SkIRect& SkRasterClip::getBounds() const {
188 return fIsBW ? fBW.getBounds() : fAA.getBounds();
189}
190
191bool SkRasterClip::setEmpty() {
reed@google.com045e62d2011-10-24 12:19:46 +0000192 AUTO_RASTERCLIP_VALIDATE(*this);
193
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000194 fIsBW = true;
195 fBW.setEmpty();
196 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000197 fIsEmpty = true;
198 fIsRect = false;
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000199 return false;
200}
201
reed@google.comba16da92011-10-11 13:15:03 +0000202bool SkRasterClip::setRect(const SkIRect& rect) {
reed@google.com045e62d2011-10-24 12:19:46 +0000203 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000204
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000205 fIsBW = true;
206 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000207 fIsRect = fBW.setRect(rect);
208 fIsEmpty = !fIsRect;
209 return fIsRect;
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000210}
211
reedd9544982014-09-09 18:46:22 -0700212/////////////////////////////////////////////////////////////////////////////////////
213
214bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
reedd9544982014-09-09 18:46:22 -0700215 SkRegion::Op op;
216 if (isInverse) {
217 op = SkRegion::kDifference_Op;
218 } else {
219 op = SkRegion::kIntersect_Op;
220 }
221 fBW.setRect(clipR);
reedb07a94f2014-11-19 05:03:18 -0800222 fBW.op(r.roundOut(), op);
reedd9544982014-09-09 18:46:22 -0700223 return this->updateCacheAndReturnNonEmpty();
224}
225
226/////////////////////////////////////////////////////////////////////////////////////
227
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000228bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000229 AUTO_RASTERCLIP_VALIDATE(*this);
230
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000231 if (this->isBW() && !doAA) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000232 (void)fBW.setPath(path, clip);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000233 } else {
reed@google.com897fc412012-02-16 17:11:25 +0000234 // TODO: since we are going to over-write fAA completely (aren't we?)
235 // we should just clear our BW data (if any) and set fIsAA=true
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000236 if (this->isBW()) {
237 this->convertToAA();
238 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000239 (void)fAA.setPath(path, &clip, doAA);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000240 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000241 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000242}
243
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500244bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400245 SkRegion::Op op, bool doAA) {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500246 SkIRect bounds(devBounds);
247 this->applyClipRestriction(op, &bounds);
robertphillips125f19a2015-11-23 09:00:05 -0800248
249 SkPath path;
250 path.addRRect(rrect);
251
Brian Salomona3b45d42016-10-03 11:36:16 -0400252 return this->op(path, matrix, bounds, op, doAA);
robertphillips125f19a2015-11-23 09:00:05 -0800253}
254
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500255bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400256 SkRegion::Op op, bool doAA) {
robertphillips125f19a2015-11-23 09:00:05 -0800257 AUTO_RASTERCLIP_VALIDATE(*this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500258 SkIRect bounds(devBounds);
259 this->applyClipRestriction(op, &bounds);
reedd9544982014-09-09 18:46:22 -0700260
robertphillips125f19a2015-11-23 09:00:05 -0800261 // base is used to limit the size (and therefore memory allocation) of the
262 // region that results from scan converting devPath.
263 SkRegion base;
264
Brian Salomona3b45d42016-10-03 11:36:16 -0400265 SkPath devPath;
266 if (matrix.isIdentity()) {
267 devPath = path;
268 } else {
269 path.transform(matrix, &devPath);
270 devPath.setIsVolatile(true);
271 }
reedd64c9482014-09-05 17:37:38 -0700272 if (SkRegion::kIntersect_Op == op) {
273 // since we are intersect, we can do better (tighter) with currRgn's
274 // bounds, than just using the device. However, if currRgn is complex,
275 // our region blitter may hork, so we do that case in two steps.
276 if (this->isRect()) {
277 // FIXME: we should also be able to do this when this->isBW(),
278 // but relaxing the test above triggers GM asserts in
279 // SkRgnBuilder::blitH(). We need to investigate what's going on.
Brian Salomona3b45d42016-10-03 11:36:16 -0400280 return this->setPath(devPath, this->bwRgn(), doAA);
reedd64c9482014-09-05 17:37:38 -0700281 } else {
282 base.setRect(this->getBounds());
Mike Reeda1361362017-03-07 09:37:29 -0500283 SkRasterClip clip;
Brian Salomona3b45d42016-10-03 11:36:16 -0400284 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700285 return this->op(clip, op);
286 }
287 } else {
senorblancoafc7cce2016-02-02 18:44:15 -0800288 base.setRect(bounds);
halcanary9d524f22016-03-29 09:03:52 -0700289
reedd64c9482014-09-05 17:37:38 -0700290 if (SkRegion::kReplace_Op == op) {
Brian Salomona3b45d42016-10-03 11:36:16 -0400291 return this->setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700292 } else {
Mike Reeda1361362017-03-07 09:37:29 -0500293 SkRasterClip clip;
Brian Salomona3b45d42016-10-03 11:36:16 -0400294 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700295 return this->op(clip, op);
296 }
297 }
298}
299
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000300bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
301 SkRegion tmp;
302 tmp.setRect(clip);
303 return this->setPath(path, tmp, doAA);
304}
305
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000306bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000307 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000308
reed@google.coma1c6ff42012-05-11 14:36:57 +0000309 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
310 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000311}
312
reed@google.comba16da92011-10-11 13:15:03 +0000313bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000314 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000315
reed@google.comba16da92011-10-11 13:15:03 +0000316 if (fIsBW) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000317 (void)fBW.op(rgn, op);
reed@google.comba16da92011-10-11 13:15:03 +0000318 } else {
319 SkAAClip tmp;
320 tmp.setRegion(rgn);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000321 (void)fAA.op(tmp, op);
reed@google.comba16da92011-10-11 13:15:03 +0000322 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000323 return this->updateCacheAndReturnNonEmpty();
reed@google.comba16da92011-10-11 13:15:03 +0000324}
325
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000326bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000327 AUTO_RASTERCLIP_VALIDATE(*this);
328 clip.validate();
329
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000330 if (this->isBW() && clip.isBW()) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000331 (void)fBW.op(clip.fBW, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000332 } else {
333 SkAAClip tmp;
334 const SkAAClip* other;
335
336 if (this->isBW()) {
337 this->convertToAA();
338 }
339 if (clip.isBW()) {
340 tmp.setRegion(clip.bwRgn());
341 other = &tmp;
342 } else {
343 other = &clip.aaRgn();
344 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000345 (void)fAA.op(*other, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000346 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000347 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000348}
349
reed@google.com18c464b2012-05-11 20:57:25 +0000350/**
351 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
352 * axis. Thus we can treat an axis coordinate as an integer if it differs
353 * from its nearest int by < half of that value (1.8 in this case).
354 */
355static bool nearly_integral(SkScalar x) {
356 static const SkScalar domain = SK_Scalar1 / 4;
357 static const SkScalar halfDomain = domain / 2;
358
359 x += halfDomain;
360 return x - SkScalarFloorToScalar(x) < domain;
reed@google.com00177082011-10-12 14:34:30 +0000361}
362
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500363bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400364 SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000365 AUTO_RASTERCLIP_VALIDATE(*this);
Brian Salomona3b45d42016-10-03 11:36:16 -0400366 SkRect devRect;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000367
Brian Salomona3b45d42016-10-03 11:36:16 -0400368 const bool isScaleTrans = matrix.isScaleTranslate();
369 if (!isScaleTrans) {
370 SkPath path;
371 path.addRect(localRect);
372 path.setIsVolatile(true);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500373 return this->op(path, matrix, devBounds, op, doAA);
Brian Salomona3b45d42016-10-03 11:36:16 -0400374 }
375
376 matrix.mapRect(&devRect, localRect);
halcanary9d524f22016-03-29 09:03:52 -0700377
reed@google.com420f74f2012-05-11 18:46:43 +0000378 if (fIsBW && doAA) {
reed@google.com18c464b2012-05-11 20:57:25 +0000379 // check that the rect really needs aa, or is it close enought to
380 // integer boundaries that we can just treat it as a BW rect?
Brian Salomona3b45d42016-10-03 11:36:16 -0400381 if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
382 nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
reed@google.com00177082011-10-12 14:34:30 +0000383 doAA = false;
384 }
385 }
386
387 if (fIsBW && !doAA) {
388 SkIRect ir;
Brian Salomona3b45d42016-10-03 11:36:16 -0400389 devRect.round(&ir);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500390 this->applyClipRestriction(op, &ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000391 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000392 } else {
393 if (fIsBW) {
394 this->convertToAA();
395 }
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500396 this->applyClipRestriction(op, &devRect);
Brian Salomona3b45d42016-10-03 11:36:16 -0400397 (void)fAA.op(devRect, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000398 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000399 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000400}
401
reed@google.com34f7e472011-10-13 15:11:59 +0000402void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700403 if (nullptr == dst) {
reed@google.com34f7e472011-10-13 15:11:59 +0000404 return;
405 }
406
reed@google.com045e62d2011-10-24 12:19:46 +0000407 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000408
reed@google.com34f7e472011-10-13 15:11:59 +0000409 if (this->isEmpty()) {
410 dst->setEmpty();
411 return;
412 }
413 if (0 == (dx | dy)) {
414 *dst = *this;
415 return;
416 }
417
418 dst->fIsBW = fIsBW;
419 if (fIsBW) {
420 fBW.translate(dx, dy, &dst->fBW);
421 dst->fAA.setEmpty();
422 } else {
423 fAA.translate(dx, dy, &dst->fAA);
424 dst->fBW.setEmpty();
425 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000426 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000427}
428
reed@google.com045e62d2011-10-24 12:19:46 +0000429bool SkRasterClip::quickContains(const SkIRect& ir) const {
430 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
431}
432
reed@google.com34f7e472011-10-13 15:11:59 +0000433///////////////////////////////////////////////////////////////////////////////
434
reed@google.comba16da92011-10-11 13:15:03 +0000435const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000436 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000437
reed@google.comba16da92011-10-11 13:15:03 +0000438 if (!fIsBW) {
439 fBW.setRect(fAA.getBounds());
440 }
441 return fBW;
442}
443
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000444void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000445 AUTO_RASTERCLIP_VALIDATE(*this);
halcanary9d524f22016-03-29 09:03:52 -0700446
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000447 SkASSERT(fIsBW);
448 fAA.setRegion(fBW);
449 fIsBW = false;
halcanary9d524f22016-03-29 09:03:52 -0700450
reed202ab2a2014-08-07 11:48:10 -0700451 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
452 // ourselves back to BW.
453 (void)this->updateCacheAndReturnNonEmpty(false);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000454}
455
reed@google.com045e62d2011-10-24 12:19:46 +0000456#ifdef SK_DEBUG
457void SkRasterClip::validate() const {
458 // can't ever assert that fBW is empty, since we may have called forceGetBW
459 if (fIsBW) {
460 SkASSERT(fAA.isEmpty());
461 }
462
Cary Clark69436892018-07-28 10:14:27 -0400463 SkRegionPriv::Validate(fBW);
reed@google.com045e62d2011-10-24 12:19:46 +0000464 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000465
466 SkASSERT(this->computeIsEmpty() == fIsEmpty);
467 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000468}
469#endif
470
471///////////////////////////////////////////////////////////////////////////////
472
473SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
halcanary96fcdcc2015-08-27 07:41:13 -0700474 SkDEBUGCODE(fClipRgn = nullptr;)
475 SkDEBUGCODE(fBlitter = nullptr;)
reed@google.com045e62d2011-10-24 12:19:46 +0000476}
477
478SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
479 SkBlitter* blitter) {
480 this->init(clip, blitter);
481}
482
483SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
484 SkBlitter* blitter) {
485 SkASSERT(blitter);
486 SkASSERT(aaclip);
487 fBWRgn.setRect(aaclip->getBounds());
488 fAABlitter.init(blitter, aaclip);
489 // now our return values
490 fClipRgn = &fBWRgn;
491 fBlitter = &fAABlitter;
492}
493
494void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
495 SkASSERT(blitter);
496 if (clip.isBW()) {
497 fClipRgn = &clip.bwRgn();
498 fBlitter = blitter;
499 } else {
500 const SkAAClip& aaclip = clip.aaRgn();
501 fBWRgn.setRect(aaclip.getBounds());
502 fAABlitter.init(blitter, &aaclip);
503 // now our return values
504 fClipRgn = &fBWRgn;
505 fBlitter = &fAABlitter;
506 }
507}