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