blob: c71c0b4f32b45188abfadf0783e73701f560915b [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkPath.h"
9#include "src/core/SkRasterClip.h"
10#include "src/core/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) {
Michael Ludwig408959f2020-11-18 13:37:54 -050066 this->applyOpParams(op, doAA ? ClipAA::kYes : ClipAA::kNo,
67 ctm.isScaleTranslate() ? IsRect::kYes : IsRect::kNo);
Mike Reeda1361362017-03-07 09:37:29 -050068 SkIRect ir;
69 switch (mutate_conservative_op(&op, false)) {
70 case kDoNothing_MutateResult:
71 return;
72 case kReplaceClippedAgainstGlobalBounds_MutateResult:
Mike Reed2a65cc02017-03-22 10:01:53 -040073 ir = devBounds;
Mike Reeda1361362017-03-07 09:37:29 -050074 break;
Mike Reed2a65cc02017-03-22 10:01:53 -040075 case kContinue_MutateResult: {
76 SkRect devRect;
Mike Reeda1361362017-03-07 09:37:29 -050077 ctm.mapRect(&devRect, localRect);
78 ir = doAA ? devRect.roundOut() : devRect.round();
Mike Reed2a65cc02017-03-22 10:01:53 -040079 } break;
Mike Reeda1361362017-03-07 09:37:29 -050080 }
Mike Reed20800c82017-11-15 16:09:04 -050081 this->opIRect(ir, op);
Mike Reeda1361362017-03-07 09:37:29 -050082}
83
Mike Reed20800c82017-11-15 16:09:04 -050084void SkConservativeClip::opRRect(const SkRRect& rrect, const SkMatrix& ctm,
85 const SkIRect& devBounds, SkRegion::Op op, bool doAA) {
Michael Ludwig408959f2020-11-18 13:37:54 -050086 this->applyOpParams(op, doAA ? ClipAA::kYes : ClipAA::kNo,
87 (rrect.isRect() && ctm.isScaleTranslate()) ? IsRect::kYes : IsRect:: kNo);
Mike Reed20800c82017-11-15 16:09:04 -050088 this->opRect(rrect.getBounds(), ctm, devBounds, op, doAA);
Mike Reeda1361362017-03-07 09:37:29 -050089}
90
Mike Reed20800c82017-11-15 16:09:04 -050091void SkConservativeClip::opPath(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds,
92 SkRegion::Op op, bool doAA) {
Michael Ludwig408959f2020-11-18 13:37:54 -050093 this->applyOpParams(op, doAA ? ClipAA::kYes : ClipAA::kNo, IsRect::kNo);
Mike Reeda1361362017-03-07 09:37:29 -050094 SkIRect ir;
95 switch (mutate_conservative_op(&op, path.isInverseFillType())) {
96 case kDoNothing_MutateResult:
97 return;
98 case kReplaceClippedAgainstGlobalBounds_MutateResult:
Mike Reed2a65cc02017-03-22 10:01:53 -040099 ir = devBounds;
Mike Reeda1361362017-03-07 09:37:29 -0500100 break;
101 case kContinue_MutateResult: {
102 SkRect bounds = path.getBounds();
103 ctm.mapRect(&bounds);
104 ir = bounds.roundOut();
105 break;
106 }
107 }
Mike Reed20800c82017-11-15 16:09:04 -0500108 return this->opIRect(ir, op);
Mike Reeda1361362017-03-07 09:37:29 -0500109}
110
Mike Reed20800c82017-11-15 16:09:04 -0500111void SkConservativeClip::opRegion(const SkRegion& rgn, SkRegion::Op op) {
Michael Ludwig408959f2020-11-18 13:37:54 -0500112 this->applyOpParams(op, ClipAA::kNo, rgn.isRect() ? IsRect::kYes : IsRect::kNo);
Mike Reed20800c82017-11-15 16:09:04 -0500113 this->opIRect(rgn.getBounds(), op);
Mike Reeda1361362017-03-07 09:37:29 -0500114}
115
Mike Reed20800c82017-11-15 16:09:04 -0500116void SkConservativeClip::opIRect(const SkIRect& devRect, SkRegion::Op op) {
Michael Ludwig408959f2020-11-18 13:37:54 -0500117 this->applyOpParams(op, ClipAA::kNo, IsRect::kYes);
118
Mike Reedca490672017-03-07 14:55:37 -0500119 if (SkRegion::kIntersect_Op == op) {
Mike Reed02be3c12017-03-23 12:34:15 -0400120 if (!fBounds.intersect(devRect)) {
Mike Reedca490672017-03-07 14:55:37 -0500121 fBounds.setEmpty();
Mike Reedca490672017-03-07 14:55:37 -0500122 }
123 return;
124 }
125
Mike Reeda1361362017-03-07 09:37:29 -0500126 // This may still create a complex region (which we would then take the bounds
127 // Perhaps we should inline the op-logic directly to never create the rgn...
128 SkRegion result;
129 result.op(SkRegion(fBounds), SkRegion(devRect), op);
130 fBounds = result.getBounds();
Mike Reed2a65cc02017-03-22 10:01:53 -0400131 this->applyClipRestriction(op, &fBounds);
Mike Reeda1361362017-03-07 09:37:29 -0500132}
133
134///////////////////////////////////////////////////////////////////////////////////////////////////
135
Ben Wagner833313b2020-03-23 17:22:24 -0400136SkRasterClip::SkRasterClip(const SkRasterClip& that)
137 : fIsBW(that.fIsBW), fIsEmpty(that.fIsEmpty), fIsRect(that.fIsRect)
138 , fClipRestrictionRect(that.fClipRestrictionRect), fShader(that.fShader)
139{
140 AUTO_RASTERCLIP_VALIDATE(that);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000141
reed@google.com34f7e472011-10-13 15:11:59 +0000142 if (fIsBW) {
Ben Wagner833313b2020-03-23 17:22:24 -0400143 fBW = that.fBW;
reed@google.com34f7e472011-10-13 15:11:59 +0000144 } else {
Ben Wagner833313b2020-03-23 17:22:24 -0400145 fAA = that.fAA;
reed@google.com34f7e472011-10-13 15:11:59 +0000146 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000147
reed@google.coma1c6ff42012-05-11 14:36:57 +0000148 SkDEBUGCODE(this->validate();)
reed@google.com34f7e472011-10-13 15:11:59 +0000149}
150
Ben Wagner833313b2020-03-23 17:22:24 -0400151SkRasterClip& SkRasterClip::operator=(const SkRasterClip& that) {
152 AUTO_RASTERCLIP_VALIDATE(that);
153
154 fIsBW = that.fIsBW;
155 if (fIsBW) {
156 fBW = that.fBW;
157 } else {
158 fAA = that.fAA;
159 }
160
161 fIsEmpty = that.isEmpty();
162 fIsRect = that.isRect();
163 fClipRestrictionRect = that.fClipRestrictionRect;
164 fShader = that.fShader;
165 SkDEBUGCODE(this->validate();)
166 return *this;
167}
168
reed1e7f5e72016-04-27 07:49:17 -0700169SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
reed1e7f5e72016-04-27 07:49:17 -0700170 fIsBW = true;
171 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
172 fIsRect = !fIsEmpty;
173 SkDEBUGCODE(this->validate();)
174}
175
Mike Reeda1361362017-03-07 09:37:29 -0500176SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
reed@google.comba16da92011-10-11 13:15:03 +0000177 fIsBW = true;
reed@google.coma1c6ff42012-05-11 14:36:57 +0000178 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
179 fIsRect = !fIsEmpty;
180 SkDEBUGCODE(this->validate();)
reed@google.comba16da92011-10-11 13:15:03 +0000181}
182
Mike Reeda1361362017-03-07 09:37:29 -0500183SkRasterClip::SkRasterClip() {
reedd9544982014-09-09 18:46:22 -0700184 fIsBW = true;
185 fIsEmpty = true;
186 fIsRect = false;
187 SkDEBUGCODE(this->validate();)
188}
189
reed@google.com045e62d2011-10-24 12:19:46 +0000190SkRasterClip::~SkRasterClip() {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000191 SkDEBUGCODE(this->validate();)
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000192}
193
reed1e7f5e72016-04-27 07:49:17 -0700194bool SkRasterClip::operator==(const SkRasterClip& other) const {
reed1e7f5e72016-04-27 07:49:17 -0700195 if (fIsBW != other.fIsBW) {
196 return false;
197 }
198 bool isEqual = fIsBW ? fBW == other.fBW : fAA == other.fAA;
199#ifdef SK_DEBUG
200 if (isEqual) {
201 SkASSERT(fIsEmpty == other.fIsEmpty);
202 SkASSERT(fIsRect == other.fIsRect);
203 }
204#endif
205 return isEqual;
206}
207
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000208bool SkRasterClip::isComplex() const {
209 return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
210}
211
212const SkIRect& SkRasterClip::getBounds() const {
213 return fIsBW ? fBW.getBounds() : fAA.getBounds();
214}
215
216bool SkRasterClip::setEmpty() {
reed@google.com045e62d2011-10-24 12:19:46 +0000217 AUTO_RASTERCLIP_VALIDATE(*this);
218
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000219 fIsBW = true;
220 fBW.setEmpty();
221 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000222 fIsEmpty = true;
223 fIsRect = false;
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000224 return false;
225}
226
reed@google.comba16da92011-10-11 13:15:03 +0000227bool SkRasterClip::setRect(const SkIRect& rect) {
reed@google.com045e62d2011-10-24 12:19:46 +0000228 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000229
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000230 fIsBW = true;
231 fAA.setEmpty();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000232 fIsRect = fBW.setRect(rect);
233 fIsEmpty = !fIsRect;
234 return fIsRect;
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000235}
236
reedd9544982014-09-09 18:46:22 -0700237/////////////////////////////////////////////////////////////////////////////////////
238
239bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
reedd9544982014-09-09 18:46:22 -0700240 SkRegion::Op op;
241 if (isInverse) {
242 op = SkRegion::kDifference_Op;
243 } else {
244 op = SkRegion::kIntersect_Op;
245 }
246 fBW.setRect(clipR);
reedb07a94f2014-11-19 05:03:18 -0800247 fBW.op(r.roundOut(), op);
reedd9544982014-09-09 18:46:22 -0700248 return this->updateCacheAndReturnNonEmpty();
249}
250
251/////////////////////////////////////////////////////////////////////////////////////
252
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000253bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000254 AUTO_RASTERCLIP_VALIDATE(*this);
255
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000256 if (this->isBW() && !doAA) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000257 (void)fBW.setPath(path, clip);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000258 } else {
reed@google.com897fc412012-02-16 17:11:25 +0000259 // TODO: since we are going to over-write fAA completely (aren't we?)
260 // we should just clear our BW data (if any) and set fIsAA=true
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000261 if (this->isBW()) {
262 this->convertToAA();
263 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000264 (void)fAA.setPath(path, &clip, doAA);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000265 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000266 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000267}
268
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500269bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400270 SkRegion::Op op, bool doAA) {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500271 SkIRect bounds(devBounds);
272 this->applyClipRestriction(op, &bounds);
robertphillips125f19a2015-11-23 09:00:05 -0800273
Mike Reed43c78ab2020-08-27 21:46:02 -0400274 return this->op(SkPath::RRect(rrect), matrix, bounds, op, doAA);
robertphillips125f19a2015-11-23 09:00:05 -0800275}
276
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500277bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400278 SkRegion::Op op, bool doAA) {
robertphillips125f19a2015-11-23 09:00:05 -0800279 AUTO_RASTERCLIP_VALIDATE(*this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500280 SkIRect bounds(devBounds);
281 this->applyClipRestriction(op, &bounds);
reedd9544982014-09-09 18:46:22 -0700282
robertphillips125f19a2015-11-23 09:00:05 -0800283 // base is used to limit the size (and therefore memory allocation) of the
284 // region that results from scan converting devPath.
285 SkRegion base;
286
Brian Salomona3b45d42016-10-03 11:36:16 -0400287 SkPath devPath;
288 if (matrix.isIdentity()) {
289 devPath = path;
290 } else {
291 path.transform(matrix, &devPath);
292 devPath.setIsVolatile(true);
293 }
reedd64c9482014-09-05 17:37:38 -0700294 if (SkRegion::kIntersect_Op == op) {
295 // since we are intersect, we can do better (tighter) with currRgn's
296 // bounds, than just using the device. However, if currRgn is complex,
297 // our region blitter may hork, so we do that case in two steps.
298 if (this->isRect()) {
299 // FIXME: we should also be able to do this when this->isBW(),
300 // but relaxing the test above triggers GM asserts in
301 // SkRgnBuilder::blitH(). We need to investigate what's going on.
Brian Salomona3b45d42016-10-03 11:36:16 -0400302 return this->setPath(devPath, this->bwRgn(), doAA);
reedd64c9482014-09-05 17:37:38 -0700303 } else {
304 base.setRect(this->getBounds());
Mike Reeda1361362017-03-07 09:37:29 -0500305 SkRasterClip clip;
Brian Salomona3b45d42016-10-03 11:36:16 -0400306 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700307 return this->op(clip, op);
308 }
309 } else {
senorblancoafc7cce2016-02-02 18:44:15 -0800310 base.setRect(bounds);
halcanary9d524f22016-03-29 09:03:52 -0700311
reedd64c9482014-09-05 17:37:38 -0700312 if (SkRegion::kReplace_Op == op) {
Brian Salomona3b45d42016-10-03 11:36:16 -0400313 return this->setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700314 } else {
Mike Reeda1361362017-03-07 09:37:29 -0500315 SkRasterClip clip;
Brian Salomona3b45d42016-10-03 11:36:16 -0400316 clip.setPath(devPath, base, doAA);
reedd64c9482014-09-05 17:37:38 -0700317 return this->op(clip, op);
318 }
319 }
320}
321
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000322bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
323 SkRegion tmp;
324 tmp.setRect(clip);
325 return this->setPath(path, tmp, doAA);
326}
327
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000328bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000329 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000330
reed@google.coma1c6ff42012-05-11 14:36:57 +0000331 fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
332 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000333}
334
reed@google.comba16da92011-10-11 13:15:03 +0000335bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000336 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000337
reed@google.comba16da92011-10-11 13:15:03 +0000338 if (fIsBW) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000339 (void)fBW.op(rgn, op);
reed@google.comba16da92011-10-11 13:15:03 +0000340 } else {
341 SkAAClip tmp;
342 tmp.setRegion(rgn);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000343 (void)fAA.op(tmp, op);
reed@google.comba16da92011-10-11 13:15:03 +0000344 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000345 return this->updateCacheAndReturnNonEmpty();
reed@google.comba16da92011-10-11 13:15:03 +0000346}
347
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000348bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +0000349 AUTO_RASTERCLIP_VALIDATE(*this);
350 clip.validate();
351
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000352 if (this->isBW() && clip.isBW()) {
reed@google.coma1c6ff42012-05-11 14:36:57 +0000353 (void)fBW.op(clip.fBW, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000354 } else {
355 SkAAClip tmp;
356 const SkAAClip* other;
357
358 if (this->isBW()) {
359 this->convertToAA();
360 }
361 if (clip.isBW()) {
362 tmp.setRegion(clip.bwRgn());
363 other = &tmp;
364 } else {
365 other = &clip.aaRgn();
366 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000367 (void)fAA.op(*other, op);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000368 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000369 return this->updateCacheAndReturnNonEmpty();
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000370}
371
Mike Reedc2fe5ee2020-03-10 19:50:25 -0400372bool SkRasterClip::op(sk_sp<SkShader> sh) {
Mike Reed121c2af2020-03-10 14:02:56 -0400373 AUTO_RASTERCLIP_VALIDATE(*this);
374
Mike Reed121c2af2020-03-10 14:02:56 -0400375 if (!fShader) {
Mike Reed121c2af2020-03-10 14:02:56 -0400376 fShader = sh;
377 } else {
Mike Reedc2fe5ee2020-03-10 19:50:25 -0400378 fShader = SkShaders::Blend(SkBlendMode::kSrcIn, sh, fShader);
Mike Reed121c2af2020-03-10 14:02:56 -0400379 }
380 return !this->isEmpty();
381}
382
reed@google.com18c464b2012-05-11 20:57:25 +0000383/**
384 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
385 * axis. Thus we can treat an axis coordinate as an integer if it differs
386 * from its nearest int by < half of that value (1.8 in this case).
387 */
388static bool nearly_integral(SkScalar x) {
389 static const SkScalar domain = SK_Scalar1 / 4;
390 static const SkScalar halfDomain = domain / 2;
391
392 x += halfDomain;
393 return x - SkScalarFloorToScalar(x) < domain;
reed@google.com00177082011-10-12 14:34:30 +0000394}
395
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500396bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
Brian Salomona3b45d42016-10-03 11:36:16 -0400397 SkRegion::Op op, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000398 AUTO_RASTERCLIP_VALIDATE(*this);
Brian Salomona3b45d42016-10-03 11:36:16 -0400399 SkRect devRect;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000400
Brian Salomona3b45d42016-10-03 11:36:16 -0400401 const bool isScaleTrans = matrix.isScaleTranslate();
402 if (!isScaleTrans) {
403 SkPath path;
404 path.addRect(localRect);
405 path.setIsVolatile(true);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500406 return this->op(path, matrix, devBounds, op, doAA);
Brian Salomona3b45d42016-10-03 11:36:16 -0400407 }
408
409 matrix.mapRect(&devRect, localRect);
halcanary9d524f22016-03-29 09:03:52 -0700410
reed@google.com420f74f2012-05-11 18:46:43 +0000411 if (fIsBW && doAA) {
reed@google.com18c464b2012-05-11 20:57:25 +0000412 // check that the rect really needs aa, or is it close enought to
413 // integer boundaries that we can just treat it as a BW rect?
Brian Salomona3b45d42016-10-03 11:36:16 -0400414 if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
415 nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
reed@google.com00177082011-10-12 14:34:30 +0000416 doAA = false;
417 }
418 }
419
420 if (fIsBW && !doAA) {
421 SkIRect ir;
Brian Salomona3b45d42016-10-03 11:36:16 -0400422 devRect.round(&ir);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500423 this->applyClipRestriction(op, &ir);
reed@google.coma1c6ff42012-05-11 14:36:57 +0000424 (void)fBW.op(ir, op);
reed@google.com00177082011-10-12 14:34:30 +0000425 } else {
426 if (fIsBW) {
427 this->convertToAA();
428 }
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500429 this->applyClipRestriction(op, &devRect);
Brian Salomona3b45d42016-10-03 11:36:16 -0400430 (void)fAA.op(devRect, op, doAA);
reed@google.com00177082011-10-12 14:34:30 +0000431 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000432 return this->updateCacheAndReturnNonEmpty();
reed@google.com00177082011-10-12 14:34:30 +0000433}
434
reed@google.com34f7e472011-10-13 15:11:59 +0000435void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700436 if (nullptr == dst) {
reed@google.com34f7e472011-10-13 15:11:59 +0000437 return;
438 }
439
reed@google.com045e62d2011-10-24 12:19:46 +0000440 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000441
reed@google.com34f7e472011-10-13 15:11:59 +0000442 if (this->isEmpty()) {
443 dst->setEmpty();
444 return;
445 }
446 if (0 == (dx | dy)) {
447 *dst = *this;
448 return;
449 }
450
451 dst->fIsBW = fIsBW;
452 if (fIsBW) {
453 fBW.translate(dx, dy, &dst->fBW);
454 dst->fAA.setEmpty();
455 } else {
456 fAA.translate(dx, dy, &dst->fAA);
457 dst->fBW.setEmpty();
458 }
reed@google.coma1c6ff42012-05-11 14:36:57 +0000459 dst->updateCacheAndReturnNonEmpty();
reed@google.com34f7e472011-10-13 15:11:59 +0000460}
461
reed@google.com045e62d2011-10-24 12:19:46 +0000462bool SkRasterClip::quickContains(const SkIRect& ir) const {
463 return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
464}
465
reed@google.com34f7e472011-10-13 15:11:59 +0000466///////////////////////////////////////////////////////////////////////////////
467
reed@google.comba16da92011-10-11 13:15:03 +0000468const SkRegion& SkRasterClip::forceGetBW() {
reed@google.com045e62d2011-10-24 12:19:46 +0000469 AUTO_RASTERCLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000470
reed@google.comba16da92011-10-11 13:15:03 +0000471 if (!fIsBW) {
472 fBW.setRect(fAA.getBounds());
473 }
474 return fBW;
475}
476
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000477void SkRasterClip::convertToAA() {
reed@google.com045e62d2011-10-24 12:19:46 +0000478 AUTO_RASTERCLIP_VALIDATE(*this);
halcanary9d524f22016-03-29 09:03:52 -0700479
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000480 SkASSERT(fIsBW);
481 fAA.setRegion(fBW);
482 fIsBW = false;
halcanary9d524f22016-03-29 09:03:52 -0700483
reed202ab2a2014-08-07 11:48:10 -0700484 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
485 // ourselves back to BW.
486 (void)this->updateCacheAndReturnNonEmpty(false);
reed@google.comd1e3c5f2011-10-10 19:36:25 +0000487}
488
reed@google.com045e62d2011-10-24 12:19:46 +0000489#ifdef SK_DEBUG
490void SkRasterClip::validate() const {
491 // can't ever assert that fBW is empty, since we may have called forceGetBW
492 if (fIsBW) {
493 SkASSERT(fAA.isEmpty());
494 }
495
Cary Clark69436892018-07-28 10:14:27 -0400496 SkRegionPriv::Validate(fBW);
reed@google.com045e62d2011-10-24 12:19:46 +0000497 fAA.validate();
reed@google.coma1c6ff42012-05-11 14:36:57 +0000498
499 SkASSERT(this->computeIsEmpty() == fIsEmpty);
500 SkASSERT(this->computeIsRect() == fIsRect);
reed@google.com045e62d2011-10-24 12:19:46 +0000501}
502#endif
503
504///////////////////////////////////////////////////////////////////////////////
505
506SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
halcanary96fcdcc2015-08-27 07:41:13 -0700507 SkDEBUGCODE(fClipRgn = nullptr;)
508 SkDEBUGCODE(fBlitter = nullptr;)
reed@google.com045e62d2011-10-24 12:19:46 +0000509}
510
511SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
512 SkBlitter* blitter) {
513 this->init(clip, blitter);
514}
515
516SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
517 SkBlitter* blitter) {
518 SkASSERT(blitter);
519 SkASSERT(aaclip);
520 fBWRgn.setRect(aaclip->getBounds());
521 fAABlitter.init(blitter, aaclip);
522 // now our return values
523 fClipRgn = &fBWRgn;
524 fBlitter = &fAABlitter;
525}
526
527void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
528 SkASSERT(blitter);
529 if (clip.isBW()) {
530 fClipRgn = &clip.bwRgn();
531 fBlitter = blitter;
532 } else {
533 const SkAAClip& aaclip = clip.aaRgn();
534 fBWRgn.setRect(aaclip.getBounds());
535 fAABlitter.init(blitter, &aaclip);
536 // now our return values
537 fClipRgn = &fBWRgn;
538 fBlitter = &fAABlitter;
539 }
540}