/src/skia/include/core/SkRegion.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2005 The Android Open Source Project |
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 | | #ifndef SkRegion_DEFINED |
9 | | #define SkRegion_DEFINED |
10 | | |
11 | | #include "include/core/SkRect.h" |
12 | | #include "include/private/base/SkAPI.h" |
13 | | #include "include/private/base/SkAssert.h" |
14 | | #include "include/private/base/SkDebug.h" |
15 | | #include "include/private/base/SkTypeTraits.h" |
16 | | |
17 | | #include <cstddef> |
18 | | #include <cstdint> |
19 | | #include <type_traits> |
20 | | |
21 | | class SkPath; |
22 | | |
23 | | /** \class SkRegion |
24 | | SkRegion describes the set of pixels used to clip SkCanvas. SkRegion is compact, |
25 | | efficiently storing a single integer rectangle, or a run length encoded array |
26 | | of rectangles. SkRegion may reduce the current SkCanvas clip, or may be drawn as |
27 | | one or more integer rectangles. SkRegion iterator returns the scan lines or |
28 | | rectangles contained by it, optionally intersecting a bounding rectangle. |
29 | | */ |
30 | | class SK_API SkRegion { |
31 | | typedef int32_t RunType; |
32 | | public: |
33 | | |
34 | | /** Constructs an empty SkRegion. SkRegion is set to empty bounds |
35 | | at (0, 0) with zero width and height. |
36 | | |
37 | | @return empty SkRegion |
38 | | |
39 | | example: https://fiddle.skia.org/c/@Region_empty_constructor |
40 | | */ |
41 | | SkRegion(); |
42 | | |
43 | | /** Constructs a copy of an existing region. |
44 | | Copy constructor makes two regions identical by value. Internally, region and |
45 | | the returned result share pointer values. The underlying SkRect array is |
46 | | copied when modified. |
47 | | |
48 | | Creating a SkRegion copy is very efficient and never allocates memory. |
49 | | SkRegion are always copied by value from the interface; the underlying shared |
50 | | pointers are not exposed. |
51 | | |
52 | | @param region SkRegion to copy by value |
53 | | @return copy of SkRegion |
54 | | |
55 | | example: https://fiddle.skia.org/c/@Region_copy_const_SkRegion |
56 | | */ |
57 | | SkRegion(const SkRegion& region); |
58 | | |
59 | | /** Constructs a rectangular SkRegion matching the bounds of rect. |
60 | | |
61 | | @param rect bounds of constructed SkRegion |
62 | | @return rectangular SkRegion |
63 | | |
64 | | example: https://fiddle.skia.org/c/@Region_copy_const_SkIRect |
65 | | */ |
66 | | explicit SkRegion(const SkIRect& rect); |
67 | | |
68 | | /** Releases ownership of any shared data and deletes data if SkRegion is sole owner. |
69 | | |
70 | | example: https://fiddle.skia.org/c/@Region_destructor |
71 | | */ |
72 | | ~SkRegion(); |
73 | | |
74 | | /** Constructs a copy of an existing region. |
75 | | Makes two regions identical by value. Internally, region and |
76 | | the returned result share pointer values. The underlying SkRect array is |
77 | | copied when modified. |
78 | | |
79 | | Creating a SkRegion copy is very efficient and never allocates memory. |
80 | | SkRegion are always copied by value from the interface; the underlying shared |
81 | | pointers are not exposed. |
82 | | |
83 | | @param region SkRegion to copy by value |
84 | | @return SkRegion to copy by value |
85 | | |
86 | | example: https://fiddle.skia.org/c/@Region_copy_operator |
87 | | */ |
88 | | SkRegion& operator=(const SkRegion& region); |
89 | | |
90 | | /** Compares SkRegion and other; returns true if they enclose exactly |
91 | | the same area. |
92 | | |
93 | | @param other SkRegion to compare |
94 | | @return true if SkRegion pair are equivalent |
95 | | |
96 | | example: https://fiddle.skia.org/c/@Region_equal1_operator |
97 | | */ |
98 | | bool operator==(const SkRegion& other) const; |
99 | | |
100 | | /** Compares SkRegion and other; returns true if they do not enclose the same area. |
101 | | |
102 | | @param other SkRegion to compare |
103 | | @return true if SkRegion pair are not equivalent |
104 | | */ |
105 | 0 | bool operator!=(const SkRegion& other) const { |
106 | 0 | return !(*this == other); |
107 | 0 | } |
108 | | |
109 | | /** Sets SkRegion to src, and returns true if src bounds is not empty. |
110 | | This makes SkRegion and src identical by value. Internally, |
111 | | SkRegion and src share pointer values. The underlying SkRect array is |
112 | | copied when modified. |
113 | | |
114 | | Creating a SkRegion copy is very efficient and never allocates memory. |
115 | | SkRegion are always copied by value from the interface; the underlying shared |
116 | | pointers are not exposed. |
117 | | |
118 | | @param src SkRegion to copy |
119 | | @return copy of src |
120 | | */ |
121 | 3.18M | bool set(const SkRegion& src) { |
122 | 3.18M | *this = src; |
123 | 3.18M | return !this->isEmpty(); |
124 | 3.18M | } |
125 | | |
126 | | /** Exchanges SkIRect array of SkRegion and other. swap() internally exchanges pointers, |
127 | | so it is lightweight and does not allocate memory. |
128 | | |
129 | | swap() usage has largely been replaced by operator=(const SkRegion& region). |
130 | | SkPath do not copy their content on assignment until they are written to, |
131 | | making assignment as efficient as swap(). |
132 | | |
133 | | @param other operator=(const SkRegion& region) set |
134 | | |
135 | | example: https://fiddle.skia.org/c/@Region_swap |
136 | | */ |
137 | | void swap(SkRegion& other); |
138 | | |
139 | | /** Returns true if SkRegion is empty. |
140 | | Empty SkRegion has bounds width or height less than or equal to zero. |
141 | | SkRegion() constructs empty SkRegion; setEmpty() |
142 | | and setRect() with dimensionless data make SkRegion empty. |
143 | | |
144 | | @return true if bounds has no width or height |
145 | | */ |
146 | 1.18G | bool isEmpty() const { return fRunHead == emptyRunHeadPtr(); } |
147 | | |
148 | | /** Returns true if SkRegion is one SkIRect with positive dimensions. |
149 | | |
150 | | @return true if SkRegion contains one SkIRect |
151 | | */ |
152 | 523M | bool isRect() const { return fRunHead == kRectRunHeadPtr; } |
153 | | |
154 | | /** Returns true if SkRegion is described by more than one rectangle. |
155 | | |
156 | | @return true if SkRegion contains more than one SkIRect |
157 | | */ |
158 | 840M | bool isComplex() const { return !this->isEmpty() && !this->isRect(); } |
159 | | |
160 | | /** Returns minimum and maximum axes values of SkIRect array. |
161 | | Returns (0, 0, 0, 0) if SkRegion is empty. |
162 | | |
163 | | @return combined bounds of all SkIRect elements |
164 | | */ |
165 | 212M | const SkIRect& getBounds() const { return fBounds; } |
166 | | |
167 | | /** Returns a value that increases with the number of |
168 | | elements in SkRegion. Returns zero if SkRegion is empty. |
169 | | Returns one if SkRegion equals SkIRect; otherwise, returns |
170 | | value greater than one indicating that SkRegion is complex. |
171 | | |
172 | | Call to compare SkRegion for relative complexity. |
173 | | |
174 | | @return relative complexity |
175 | | |
176 | | example: https://fiddle.skia.org/c/@Region_computeRegionComplexity |
177 | | */ |
178 | | int computeRegionComplexity() const; |
179 | | |
180 | | /** Appends outline of SkRegion to path. |
181 | | Returns true if SkRegion is not empty; otherwise, returns false, and leaves path |
182 | | unmodified. |
183 | | |
184 | | @param path SkPath to append to |
185 | | @return true if path changed |
186 | | |
187 | | example: https://fiddle.skia.org/c/@Region_getBoundaryPath |
188 | | */ |
189 | | bool getBoundaryPath(SkPath* path) const; |
190 | | |
191 | | /** Constructs an empty SkRegion. SkRegion is set to empty bounds |
192 | | at (0, 0) with zero width and height. Always returns false. |
193 | | |
194 | | @return false |
195 | | |
196 | | example: https://fiddle.skia.org/c/@Region_setEmpty |
197 | | */ |
198 | | bool setEmpty(); |
199 | | |
200 | | /** Constructs a rectangular SkRegion matching the bounds of rect. |
201 | | If rect is empty, constructs empty and returns false. |
202 | | |
203 | | @param rect bounds of constructed SkRegion |
204 | | @return true if rect is not empty |
205 | | |
206 | | example: https://fiddle.skia.org/c/@Region_setRect |
207 | | */ |
208 | | bool setRect(const SkIRect& rect); |
209 | | |
210 | | /** Constructs SkRegion as the union of SkIRect in rects array. If count is |
211 | | zero, constructs empty SkRegion. Returns false if constructed SkRegion is empty. |
212 | | |
213 | | May be faster than repeated calls to op(). |
214 | | |
215 | | @param rects array of SkIRect |
216 | | @param count array size |
217 | | @return true if constructed SkRegion is not empty |
218 | | |
219 | | example: https://fiddle.skia.org/c/@Region_setRects |
220 | | */ |
221 | | bool setRects(const SkIRect rects[], int count); |
222 | | |
223 | | /** Constructs a copy of an existing region. |
224 | | Makes two regions identical by value. Internally, region and |
225 | | the returned result share pointer values. The underlying SkRect array is |
226 | | copied when modified. |
227 | | |
228 | | Creating a SkRegion copy is very efficient and never allocates memory. |
229 | | SkRegion are always copied by value from the interface; the underlying shared |
230 | | pointers are not exposed. |
231 | | |
232 | | @param region SkRegion to copy by value |
233 | | @return SkRegion to copy by value |
234 | | |
235 | | example: https://fiddle.skia.org/c/@Region_setRegion |
236 | | */ |
237 | | bool setRegion(const SkRegion& region); |
238 | | |
239 | | /** Constructs SkRegion to match outline of path within clip. |
240 | | Returns false if constructed SkRegion is empty. |
241 | | |
242 | | Constructed SkRegion draws the same pixels as path through clip when |
243 | | anti-aliasing is disabled. |
244 | | |
245 | | @param path SkPath providing outline |
246 | | @param clip SkRegion containing path |
247 | | @return true if constructed SkRegion is not empty |
248 | | |
249 | | example: https://fiddle.skia.org/c/@Region_setPath |
250 | | */ |
251 | | bool setPath(const SkPath& path, const SkRegion& clip); |
252 | | |
253 | | /** Returns true if SkRegion intersects rect. |
254 | | Returns false if either rect or SkRegion is empty, or do not intersect. |
255 | | |
256 | | @param rect SkIRect to intersect |
257 | | @return true if rect and SkRegion have area in common |
258 | | |
259 | | example: https://fiddle.skia.org/c/@Region_intersects |
260 | | */ |
261 | | bool intersects(const SkIRect& rect) const; |
262 | | |
263 | | /** Returns true if SkRegion intersects other. |
264 | | Returns false if either other or SkRegion is empty, or do not intersect. |
265 | | |
266 | | @param other SkRegion to intersect |
267 | | @return true if other and SkRegion have area in common |
268 | | |
269 | | example: https://fiddle.skia.org/c/@Region_intersects_2 |
270 | | */ |
271 | | bool intersects(const SkRegion& other) const; |
272 | | |
273 | | /** Returns true if SkIPoint (x, y) is inside SkRegion. |
274 | | Returns false if SkRegion is empty. |
275 | | |
276 | | @param x test SkIPoint x-coordinate |
277 | | @param y test SkIPoint y-coordinate |
278 | | @return true if (x, y) is inside SkRegion |
279 | | |
280 | | example: https://fiddle.skia.org/c/@Region_contains |
281 | | */ |
282 | | bool contains(int32_t x, int32_t y) const; |
283 | | |
284 | | /** Returns true if other is completely inside SkRegion. |
285 | | Returns false if SkRegion or other is empty. |
286 | | |
287 | | @param other SkIRect to contain |
288 | | @return true if other is inside SkRegion |
289 | | |
290 | | example: https://fiddle.skia.org/c/@Region_contains_2 |
291 | | */ |
292 | | bool contains(const SkIRect& other) const; |
293 | | |
294 | | /** Returns true if other is completely inside SkRegion. |
295 | | Returns false if SkRegion or other is empty. |
296 | | |
297 | | @param other SkRegion to contain |
298 | | @return true if other is inside SkRegion |
299 | | |
300 | | example: https://fiddle.skia.org/c/@Region_contains_3 |
301 | | */ |
302 | | bool contains(const SkRegion& other) const; |
303 | | |
304 | | /** Returns true if SkRegion is a single rectangle and contains r. |
305 | | May return false even though SkRegion contains r. |
306 | | |
307 | | @param r SkIRect to contain |
308 | | @return true quickly if r points are equal or inside |
309 | | */ |
310 | 475k | bool quickContains(const SkIRect& r) const { |
311 | 475k | SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region |
312 | | |
313 | 475k | return r.fLeft < r.fRight && r.fTop < r.fBottom && |
314 | 475k | fRunHead == kRectRunHeadPtr && // this->isRect() |
315 | | /* fBounds.contains(left, top, right, bottom); */ |
316 | 475k | fBounds.fLeft <= r.fLeft && fBounds.fTop <= r.fTop && |
317 | 475k | fBounds.fRight >= r.fRight && fBounds.fBottom >= r.fBottom; |
318 | 475k | } SkRegion::quickContains(SkIRect const&) const Line | Count | Source | 310 | 475k | bool quickContains(const SkIRect& r) const { | 311 | 475k | SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region | 312 | | | 313 | 475k | return r.fLeft < r.fRight && r.fTop < r.fBottom && | 314 | 475k | fRunHead == kRectRunHeadPtr && // this->isRect() | 315 | | /* fBounds.contains(left, top, right, bottom); */ | 316 | 475k | fBounds.fLeft <= r.fLeft && fBounds.fTop <= r.fTop && | 317 | 475k | fBounds.fRight >= r.fRight && fBounds.fBottom >= r.fBottom; | 318 | 475k | } |
Unexecuted instantiation: SkRegion::quickContains(SkIRect const&) const |
319 | | |
320 | | /** Returns true if SkRegion does not intersect rect. |
321 | | Returns true if rect is empty or SkRegion is empty. |
322 | | May return false even though SkRegion does not intersect rect. |
323 | | |
324 | | @param rect SkIRect to intersect |
325 | | @return true if rect does not intersect |
326 | | */ |
327 | 432k | bool quickReject(const SkIRect& rect) const { |
328 | 432k | return this->isEmpty() || rect.isEmpty() || |
329 | 432k | !SkIRect::Intersects(fBounds, rect); |
330 | 432k | } |
331 | | |
332 | | /** Returns true if SkRegion does not intersect rgn. |
333 | | Returns true if rgn is empty or SkRegion is empty. |
334 | | May return false even though SkRegion does not intersect rgn. |
335 | | |
336 | | @param rgn SkRegion to intersect |
337 | | @return true if rgn does not intersect |
338 | | */ |
339 | 0 | bool quickReject(const SkRegion& rgn) const { |
340 | 0 | return this->isEmpty() || rgn.isEmpty() || |
341 | 0 | !SkIRect::Intersects(fBounds, rgn.fBounds); |
342 | 0 | } |
343 | | |
344 | | /** Offsets SkRegion by ivector (dx, dy). Has no effect if SkRegion is empty. |
345 | | |
346 | | @param dx x-axis offset |
347 | | @param dy y-axis offset |
348 | | */ |
349 | 76.3M | void translate(int dx, int dy) { this->translate(dx, dy, this); } |
350 | | |
351 | | /** Offsets SkRegion by ivector (dx, dy), writing result to dst. SkRegion may be passed |
352 | | as dst parameter, translating SkRegion in place. Has no effect if dst is nullptr. |
353 | | If SkRegion is empty, sets dst to empty. |
354 | | |
355 | | @param dx x-axis offset |
356 | | @param dy y-axis offset |
357 | | @param dst translated result |
358 | | |
359 | | example: https://fiddle.skia.org/c/@Region_translate_2 |
360 | | */ |
361 | | void translate(int dx, int dy, SkRegion* dst) const; |
362 | | |
363 | | /** \enum SkRegion::Op |
364 | | The logical operations that can be performed when combining two SkRegion. |
365 | | */ |
366 | | enum Op { |
367 | | kDifference_Op, //!< target minus operand |
368 | | kIntersect_Op, //!< target intersected with operand |
369 | | kUnion_Op, //!< target unioned with operand |
370 | | kXOR_Op, //!< target exclusive or with operand |
371 | | kReverseDifference_Op, //!< operand minus target |
372 | | kReplace_Op, //!< replace target with operand |
373 | | kLastOp = kReplace_Op, //!< last operator |
374 | | }; |
375 | | |
376 | | static const int kOpCnt = kLastOp + 1; |
377 | | |
378 | | /** Replaces SkRegion with the result of SkRegion op rect. |
379 | | Returns true if replaced SkRegion is not empty. |
380 | | |
381 | | @param rect SkIRect operand |
382 | | @return false if result is empty |
383 | | */ |
384 | 427k | bool op(const SkIRect& rect, Op op) { |
385 | 427k | if (this->isRect() && kIntersect_Op == op) { |
386 | 317k | if (!fBounds.intersect(rect)) { |
387 | 13.2k | return this->setEmpty(); |
388 | 13.2k | } |
389 | 304k | return true; |
390 | 317k | } |
391 | 109k | return this->op(*this, rect, op); |
392 | 427k | } |
393 | | |
394 | | /** Replaces SkRegion with the result of SkRegion op rgn. |
395 | | Returns true if replaced SkRegion is not empty. |
396 | | |
397 | | @param rgn SkRegion operand |
398 | | @return false if result is empty |
399 | | */ |
400 | 76.3M | bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } |
401 | | |
402 | | /** Replaces SkRegion with the result of rect op rgn. |
403 | | Returns true if replaced SkRegion is not empty. |
404 | | |
405 | | @param rect SkIRect operand |
406 | | @param rgn SkRegion operand |
407 | | @return false if result is empty |
408 | | |
409 | | example: https://fiddle.skia.org/c/@Region_op_4 |
410 | | */ |
411 | | bool op(const SkIRect& rect, const SkRegion& rgn, Op op); |
412 | | |
413 | | /** Replaces SkRegion with the result of rgn op rect. |
414 | | Returns true if replaced SkRegion is not empty. |
415 | | |
416 | | @param rgn SkRegion operand |
417 | | @param rect SkIRect operand |
418 | | @return false if result is empty |
419 | | |
420 | | example: https://fiddle.skia.org/c/@Region_op_5 |
421 | | */ |
422 | | bool op(const SkRegion& rgn, const SkIRect& rect, Op op); |
423 | | |
424 | | /** Replaces SkRegion with the result of rgna op rgnb. |
425 | | Returns true if replaced SkRegion is not empty. |
426 | | |
427 | | @param rgna SkRegion operand |
428 | | @param rgnb SkRegion operand |
429 | | @return false if result is empty |
430 | | |
431 | | example: https://fiddle.skia.org/c/@Region_op_6 |
432 | | */ |
433 | | bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); |
434 | | |
435 | | #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK |
436 | | /** Private. Android framework only. |
437 | | |
438 | | @return string representation of SkRegion |
439 | | */ |
440 | | char* toString(); |
441 | | #endif |
442 | | |
443 | | /** \class SkRegion::Iterator |
444 | | Returns sequence of rectangles, sorted along y-axis, then x-axis, that make |
445 | | up SkRegion. |
446 | | */ |
447 | | class SK_API Iterator { |
448 | | public: |
449 | | |
450 | | /** Initializes SkRegion::Iterator with an empty SkRegion. done() on SkRegion::Iterator |
451 | | returns true. |
452 | | Call reset() to initialized SkRegion::Iterator at a later time. |
453 | | |
454 | | @return empty SkRegion iterator |
455 | | */ |
456 | 0 | Iterator() : fRgn(nullptr), fDone(true) {} |
457 | | |
458 | | /** Sets SkRegion::Iterator to return elements of SkIRect array in region. |
459 | | |
460 | | @param region SkRegion to iterate |
461 | | @return SkRegion iterator |
462 | | |
463 | | example: https://fiddle.skia.org/c/@Region_Iterator_copy_const_SkRegion |
464 | | */ |
465 | | Iterator(const SkRegion& region); |
466 | | |
467 | | /** SkPoint SkRegion::Iterator to start of SkRegion. |
468 | | Returns true if SkRegion was set; otherwise, returns false. |
469 | | |
470 | | @return true if SkRegion was set |
471 | | |
472 | | example: https://fiddle.skia.org/c/@Region_Iterator_rewind |
473 | | */ |
474 | | bool rewind(); |
475 | | |
476 | | /** Resets iterator, using the new SkRegion. |
477 | | |
478 | | @param region SkRegion to iterate |
479 | | |
480 | | example: https://fiddle.skia.org/c/@Region_Iterator_reset |
481 | | */ |
482 | | void reset(const SkRegion& region); |
483 | | |
484 | | /** Returns true if SkRegion::Iterator is pointing to final SkIRect in SkRegion. |
485 | | |
486 | | @return true if data parsing is complete |
487 | | */ |
488 | 11.9M | bool done() const { return fDone; } |
489 | | |
490 | | /** Advances SkRegion::Iterator to next SkIRect in SkRegion if it is not done. |
491 | | |
492 | | example: https://fiddle.skia.org/c/@Region_Iterator_next |
493 | | */ |
494 | | void next(); |
495 | | |
496 | | /** Returns SkIRect element in SkRegion. Does not return predictable results if SkRegion |
497 | | is empty. |
498 | | |
499 | | @return part of SkRegion as SkIRect |
500 | | */ |
501 | 2.78M | const SkIRect& rect() const { return fRect; } |
502 | | |
503 | | /** Returns SkRegion if set; otherwise, returns nullptr. |
504 | | |
505 | | @return iterated SkRegion |
506 | | */ |
507 | 0 | const SkRegion* rgn() const { return fRgn; } |
508 | | |
509 | | private: |
510 | | const SkRegion* fRgn; |
511 | | const SkRegion::RunType* fRuns; |
512 | | SkIRect fRect = {0, 0, 0, 0}; |
513 | | bool fDone; |
514 | | }; |
515 | | |
516 | | /** \class SkRegion::Cliperator |
517 | | Returns the sequence of rectangles, sorted along y-axis, then x-axis, that make |
518 | | up SkRegion intersected with the specified clip rectangle. |
519 | | */ |
520 | | class SK_API Cliperator { |
521 | | public: |
522 | | |
523 | | /** Sets SkRegion::Cliperator to return elements of SkIRect array in SkRegion within clip. |
524 | | |
525 | | @param region SkRegion to iterate |
526 | | @param clip bounds of iteration |
527 | | @return SkRegion iterator |
528 | | |
529 | | example: https://fiddle.skia.org/c/@Region_Cliperator_const_SkRegion_const_SkIRect |
530 | | */ |
531 | | Cliperator(const SkRegion& region, const SkIRect& clip); |
532 | | |
533 | | /** Returns true if SkRegion::Cliperator is pointing to final SkIRect in SkRegion. |
534 | | |
535 | | @return true if data parsing is complete |
536 | | */ |
537 | 2.29M | bool done() { return fDone; } |
538 | | |
539 | | /** Advances iterator to next SkIRect in SkRegion contained by clip. |
540 | | |
541 | | example: https://fiddle.skia.org/c/@Region_Cliperator_next |
542 | | */ |
543 | | void next(); |
544 | | |
545 | | /** Returns SkIRect element in SkRegion, intersected with clip passed to |
546 | | SkRegion::Cliperator constructor. Does not return predictable results if SkRegion |
547 | | is empty. |
548 | | |
549 | | @return part of SkRegion inside clip as SkIRect |
550 | | */ |
551 | 1.11M | const SkIRect& rect() const { return fRect; } |
552 | | |
553 | | private: |
554 | | Iterator fIter; |
555 | | SkIRect fClip; |
556 | | SkIRect fRect = {0, 0, 0, 0}; |
557 | | bool fDone; |
558 | | }; |
559 | | |
560 | | /** \class SkRegion::Spanerator |
561 | | Returns the line segment ends within SkRegion that intersect a horizontal line. |
562 | | */ |
563 | | class Spanerator { |
564 | | public: |
565 | | |
566 | | /** Sets SkRegion::Spanerator to return line segments in SkRegion on scan line. |
567 | | |
568 | | @param region SkRegion to iterate |
569 | | @param y horizontal line to intersect |
570 | | @param left bounds of iteration |
571 | | @param right bounds of iteration |
572 | | @return SkRegion iterator |
573 | | |
574 | | example: https://fiddle.skia.org/c/@Region_Spanerator_const_SkRegion_int_int_int |
575 | | */ |
576 | | Spanerator(const SkRegion& region, int y, int left, int right); |
577 | | |
578 | | /** Advances iterator to next span intersecting SkRegion within line segment provided |
579 | | in constructor. Returns true if interval was found. |
580 | | |
581 | | @param left pointer to span start; may be nullptr |
582 | | @param right pointer to span end; may be nullptr |
583 | | @return true if interval was found |
584 | | |
585 | | example: https://fiddle.skia.org/c/@Region_Spanerator_next |
586 | | */ |
587 | | bool next(int* left, int* right); |
588 | | |
589 | | private: |
590 | | const SkRegion::RunType* fRuns; |
591 | | int fLeft, fRight; |
592 | | bool fDone; |
593 | | }; |
594 | | |
595 | | /** Writes SkRegion to buffer, and returns number of bytes written. |
596 | | If buffer is nullptr, returns number number of bytes that would be written. |
597 | | |
598 | | @param buffer storage for binary data |
599 | | @return size of SkRegion |
600 | | |
601 | | example: https://fiddle.skia.org/c/@Region_writeToMemory |
602 | | */ |
603 | | size_t writeToMemory(void* buffer) const; |
604 | | |
605 | | /** Constructs SkRegion from buffer of size length. Returns bytes read. |
606 | | Returned value will be multiple of four or zero if length was too small. |
607 | | |
608 | | @param buffer storage for binary data |
609 | | @param length size of buffer |
610 | | @return bytes read |
611 | | |
612 | | example: https://fiddle.skia.org/c/@Region_readFromMemory |
613 | | */ |
614 | | size_t readFromMemory(const void* buffer, size_t length); |
615 | | |
616 | | using sk_is_trivially_relocatable = std::true_type; |
617 | | |
618 | | private: |
619 | | static constexpr int kOpCount = kReplace_Op + 1; |
620 | | |
621 | | // T |
622 | | // [B N L R S] |
623 | | // S |
624 | | static constexpr int kRectRegionRuns = 7; |
625 | | |
626 | | struct RunHead; |
627 | | |
628 | 1.18G | static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; } |
629 | | static constexpr RunHead* kRectRunHeadPtr = nullptr; |
630 | | |
631 | | // allocate space for count runs |
632 | | void allocateRuns(int count); |
633 | | void allocateRuns(int count, int ySpanCount, int intervalCount); |
634 | | void allocateRuns(const RunHead& src); |
635 | | |
636 | | SkDEBUGCODE(void dump() const;) |
637 | | |
638 | | SkIRect fBounds; |
639 | | RunHead* fRunHead; |
640 | | |
641 | | static_assert(::sk_is_trivially_relocatable<decltype(fBounds)>::value); |
642 | | static_assert(::sk_is_trivially_relocatable<decltype(fRunHead)>::value); |
643 | | |
644 | | void freeRuns(); |
645 | | |
646 | | /** |
647 | | * Return the runs from this region, consing up fake runs if the region |
648 | | * is empty or a rect. In those 2 cases, we use tmpStorage to hold the |
649 | | * run data. |
650 | | */ |
651 | | const RunType* getRuns(RunType tmpStorage[], int* intervals) const; |
652 | | |
653 | | // This is called with runs[] that do not yet have their interval-count |
654 | | // field set on each scanline. That is computed as part of this call |
655 | | // (inside ComputeRunBounds). |
656 | | bool setRuns(RunType runs[], int count); |
657 | | |
658 | | int count_runtype_values(int* itop, int* ibot) const; |
659 | | |
660 | | bool isValid() const; |
661 | | |
662 | | static void BuildRectRuns(const SkIRect& bounds, |
663 | | RunType runs[kRectRegionRuns]); |
664 | | |
665 | | // If the runs define a simple rect, return true and set bounds to that |
666 | | // rect. If not, return false and ignore bounds. |
667 | | static bool RunsAreARect(const SkRegion::RunType runs[], int count, |
668 | | SkIRect* bounds); |
669 | | |
670 | | /** |
671 | | * If the last arg is null, just return if the result is non-empty, |
672 | | * else store the result in the last arg. |
673 | | */ |
674 | | static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); |
675 | | |
676 | | friend struct RunHead; |
677 | | friend class Iterator; |
678 | | friend class Spanerator; |
679 | | friend class SkRegionPriv; |
680 | | friend class SkRgnBuilder; |
681 | | friend class SkFlatRegion; |
682 | | }; |
683 | | |
684 | | #endif |