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