Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkRasterClip.cpp
Go to the documentation of this file.
1/*
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
9
13#include "include/core/SkPath.h"
17
18class SkBlitter;
19
21 : fIsBW(that.fIsBW)
22 , fIsEmpty(that.fIsEmpty)
23 , fIsRect(that.fIsRect)
24 , fShader(that.fShader)
25{
27
28 if (fIsBW) {
29 fBW = that.fBW;
30 } else {
31 fAA = that.fAA;
32 }
33
34 SkDEBUGCODE(this->validate();)
35}
36
39
40 fIsBW = that.fIsBW;
41 if (fIsBW) {
42 fBW = that.fBW;
43 } else {
44 fAA = that.fAA;
45 }
46
47 fIsEmpty = that.isEmpty();
48 fIsRect = that.isRect();
49 fShader = that.fShader;
50 SkDEBUGCODE(this->validate();)
51 return *this;
52}
53
54SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
55 fIsBW = true;
56 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
57 fIsRect = !fIsEmpty;
58 SkDEBUGCODE(this->validate();)
59}
60
61SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
62 fIsBW = true;
63 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
64 fIsRect = !fIsEmpty;
65 SkDEBUGCODE(this->validate();)
66}
67
69 fIsBW = true;
70 fIsEmpty = true;
71 fIsRect = false;
72 SkDEBUGCODE(this->validate();)
73}
74
75SkRasterClip::SkRasterClip(const SkPath& path, const SkIRect& bounds, bool doAA) {
76 if (doAA) {
77 fIsBW = false;
78 fAA.setPath(path, bounds, true);
79 } else {
80 fIsBW = true;
81 fBW.setPath(path, SkRegion(bounds));
82 }
83 fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
84 fIsRect = this->computeIsRect();
85 SkDEBUGCODE(this->validate();)
86}
87
91
94
95 fIsBW = true;
96 fBW.setEmpty();
97 fAA.setEmpty();
98 fIsEmpty = true;
99 fIsRect = false;
100 return false;
101}
102
105
106 fIsBW = true;
107 fAA.setEmpty();
108 fIsRect = fBW.setRect(rect);
109 fIsEmpty = !fIsRect;
110 return fIsRect;
111}
112
113/////////////////////////////////////////////////////////////////////////////////////
114
115bool SkRasterClip::op(const SkIRect& rect, SkClipOp op) {
117
118 if (fIsBW) {
119 fBW.op(rect, (SkRegion::Op) op);
120 } else {
121 fAA.op(rect, op);
122 }
123 return this->updateCacheAndReturnNonEmpty();
124}
125
126bool SkRasterClip::op(const SkRegion& rgn, SkClipOp op) {
128
129 if (fIsBW) {
130 (void)fBW.op(rgn, (SkRegion::Op) op);
131 } else {
132 SkAAClip tmp;
133 tmp.setRegion(rgn);
134 (void)fAA.op(tmp, op);
135 }
136 return this->updateCacheAndReturnNonEmpty();
137}
138
139/**
140 * Our antialiasing currently has a granularity of 1/4 of a pixel along each
141 * axis. Thus we can treat an axis coordinate as an integer if it differs
142 * from its nearest int by < half of that value (1/8 in this case).
143 */
145 static const SkScalar domain = SK_Scalar1 / 4;
146 static const SkScalar halfDomain = domain / 2;
147
148 x += halfDomain;
149 return x - SkScalarFloorToScalar(x) < domain;
150}
151
152bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, SkClipOp op, bool doAA) {
154
155 const bool isScaleTrans = matrix.isScaleTranslate();
156 if (!isScaleTrans) {
157 return this->op(SkPath::Rect(localRect), matrix, op, doAA);
158 }
159
160 SkRect devRect = matrix.mapRect(localRect);
161 if (fIsBW && doAA) {
162 // check that the rect really needs aa, or is it close enought to
163 // integer boundaries that we can just treat it as a BW rect?
164 if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
165 nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
166 doAA = false;
167 }
168 }
169
170 if (fIsBW && !doAA) {
171 (void)fBW.op(devRect.round(), (SkRegion::Op) op);
172 } else {
173 if (fIsBW) {
174 this->convertToAA();
175 }
176 (void)fAA.op(devRect, op, doAA);
177 }
178 return this->updateCacheAndReturnNonEmpty();
179}
180
181bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, SkClipOp op, bool doAA) {
182 return this->op(SkPath::RRect(rrect), matrix, op, doAA);
183}
184
185bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, SkClipOp op, bool doAA) {
187
188 SkPath devPath;
189 path.transform(matrix, &devPath);
190
191 // Since op is either intersect or difference, the clip is always shrinking; that means we can
192 // always use our current bounds as the limiting factor for region/aaclip operations.
193 if (this->isRect() && op == SkClipOp::kIntersect) {
194 // However, in the relatively common case of intersecting a new path with a rectangular
195 // clip, it's faster to convert the path into a region/aa-mask in place than evaluate the
196 // actual intersection. See skbug.com/12398
197 if (doAA && fIsBW) {
198 this->convertToAA();
199 }
200 if (fIsBW) {
201 fBW.setPath(devPath, SkRegion(this->getBounds()));
202 } else {
203 fAA.setPath(devPath, this->getBounds(), doAA);
204 }
205 return this->updateCacheAndReturnNonEmpty();
206 } else {
207 return this->op(SkRasterClip(devPath, this->getBounds(), doAA), op);
208 }
209}
210
213
214 if (!fShader) {
215 fShader = sh;
216 } else {
217 fShader = SkShaders::Blend(SkBlendMode::kSrcIn, sh, fShader);
218 }
219 return !this->isEmpty();
220}
221
224 clip.validate();
225
226 if (this->isBW() && clip.isBW()) {
227 (void)fBW.op(clip.fBW, (SkRegion::Op) op);
228 } else {
229 SkAAClip tmp;
230 const SkAAClip* other;
231
232 if (this->isBW()) {
233 this->convertToAA();
234 }
235 if (clip.isBW()) {
236 tmp.setRegion(clip.bwRgn());
237 other = &tmp;
238 } else {
239 other = &clip.aaRgn();
240 }
241 (void)fAA.op(*other, op);
242 }
243 return this->updateCacheAndReturnNonEmpty();
244}
245
246void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
247 if (nullptr == dst) {
248 return;
249 }
250
252
253 if (this->isEmpty()) {
254 dst->setEmpty();
255 return;
256 }
257 if (0 == (dx | dy)) {
258 *dst = *this;
259 return;
260 }
261
262 dst->fIsBW = fIsBW;
263 if (fIsBW) {
264 fBW.translate(dx, dy, &dst->fBW);
265 dst->fAA.setEmpty();
266 } else {
267 fAA.translate(dx, dy, &dst->fAA);
268 dst->fBW.setEmpty();
269 }
270 dst->updateCacheAndReturnNonEmpty();
271}
272
273void SkRasterClip::convertToAA() {
275
276 SkASSERT(fIsBW);
277 fAA.setRegion(fBW);
278 fIsBW = false;
279
280 // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
281 // ourselves back to BW.
282 (void)this->updateCacheAndReturnNonEmpty(false);
283}
284
285#ifdef SK_DEBUG
286void SkRasterClip::validate() const {
287 // can't ever assert that fBW is empty, since we may have called forceGetBW
288 if (fIsBW) {
289 SkASSERT(fAA.isEmpty());
290 }
291
292 SkRegionPriv::Validate(fBW);
293 fAA.validate();
294
295 SkASSERT(this->computeIsEmpty() == fIsEmpty);
296 SkASSERT(this->computeIsRect() == fIsRect);
297}
298#endif
299
300///////////////////////////////////////////////////////////////////////////////
301
303 SkDEBUGCODE(fClipRgn = nullptr;)
304 SkDEBUGCODE(fBlitter = nullptr;)
305}
306
308 SkBlitter* blitter) {
309 this->init(clip, blitter);
310}
311
313 SkBlitter* blitter) {
314 SkASSERT(blitter);
315 SkASSERT(aaclip);
316 fBWRgn.setRect(aaclip->getBounds());
317 fAABlitter.init(blitter, aaclip);
318 // now our return values
319 fClipRgn = &fBWRgn;
320 fBlitter = &fAABlitter;
321}
322
324 SkASSERT(blitter);
325 if (clip.isBW()) {
326 fClipRgn = &clip.bwRgn();
327 fBlitter = blitter;
328 } else {
329 const SkAAClip& aaclip = clip.aaRgn();
330 fBWRgn.setRect(aaclip.getBounds());
331 fAABlitter.init(blitter, &aaclip);
332 // now our return values
333 fClipRgn = &fBWRgn;
334 fBlitter = &fAABlitter;
335 }
336}
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kSrcIn
r = s * da
SkClipOp
Definition SkClipOp.h:13
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static bool nearly_integral(SkScalar x)
#define AUTO_RASTERCLIP_VALIDATE(rc)
#define SkScalarFloorToScalar(x)
Definition SkScalar.h:30
#define SK_Scalar1
Definition SkScalar.h:18
void init(const SkRasterClip &, SkBlitter *)
void init(SkBlitter *blitter, const SkAAClip *aaclip)
Definition SkAAClip.h:96
void validate() const
Definition SkAAClip.h:64
bool setEmpty()
bool translate(int dx, int dy, SkAAClip *dst) const
const SkIRect & getBounds() const
Definition SkAAClip.h:33
bool setPath(const SkPath &, const SkIRect &bounds, bool doAA=true)
bool op(const SkIRect &, SkClipOp)
bool isEmpty() const
Definition SkAAClip.h:32
bool setRegion(const SkRegion &)
static SkPath RRect(const SkRRect &, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:3534
static SkPath Rect(const SkRect &, SkPathDirection=SkPathDirection::kCW, unsigned startIndex=0)
Definition SkPath.cpp:3518
const SkIRect & getBounds() const
void validate() const
SkRasterClip & operator=(const SkRasterClip &)
void translate(int dx, int dy, SkRasterClip *dst) const
bool isRect() const
bool isBW() const
bool setRect(const SkIRect &)
bool isEmpty() const
bool op(const SkIRect &, SkClipOp)
void translate(int dx, int dy)
Definition SkRegion.h:349
bool setEmpty()
Definition SkRegion.cpp:185
bool op(const SkIRect &rect, Op op)
Definition SkRegion.h:384
bool setRect(const SkIRect &rect)
Definition SkRegion.cpp:192
bool setPath(const SkPath &path, const SkRegion &clip)
float SkScalar
Definition extension.cpp:12
double x
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
void round(SkIRect *dst) const
Definition SkRect.h:1228
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15