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