• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2005 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #ifndef SkRegion_DEFINED
11 #define SkRegion_DEFINED
12 
13 #include "SkRect.h"
14 
15 class SkPath;
16 class SkRgnBuilder;
17 
18 namespace android {
19     class Region;
20 }
21 
22 #define SkRegion_gEmptyRunHeadPtr   ((SkRegion::RunHead*)-1)
23 #define SkRegion_gRectRunHeadPtr    nullptr
24 
25 /** \class SkRegion
26 
27     The SkRegion class encapsulates the geometric region used to specify
28     clipping areas for drawing.
29 */
30 class SK_API SkRegion {
31 public:
32     typedef int32_t RunType;
33     enum {
34         kRunTypeSentinel = 0x7FFFFFFF
35     };
36 
37     SkRegion();
38     SkRegion(const SkRegion&);
39     explicit SkRegion(const SkIRect&);
40     ~SkRegion();
41 
42     SkRegion& operator=(const SkRegion&);
43 
44     /**
45      *  Return true if the two regions are equal. i.e. The enclose exactly
46      *  the same area.
47      */
48     bool operator==(const SkRegion& other) const;
49 
50     /**
51      *  Return true if the two regions are not equal.
52      */
53     bool operator!=(const SkRegion& other) const {
54         return !(*this == other);
55     }
56 
57     /**
58      *  Replace this region with the specified region, and return true if the
59      *  resulting region is non-empty.
60      */
set(const SkRegion & src)61     bool set(const SkRegion& src) {
62         *this = src;
63         return !this->isEmpty();
64     }
65 
66     /**
67      *  Swap the contents of this and the specified region. This operation
68      *  is gauarenteed to never fail.
69      */
70     void swap(SkRegion&);
71 
72     /** Return true if this region is empty */
isEmpty()73     bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
74 
75     /** Return true if this region is a single, non-empty rectangle */
isRect()76     bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
77 
78     /** Return true if this region consists of more than 1 rectangular area */
isComplex()79     bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
80 
81     /**
82      *  Return the bounds of this region. If the region is empty, returns an
83      *  empty rectangle.
84      */
getBounds()85     const SkIRect& getBounds() const { return fBounds; }
86 
87     /**
88      *  Returns a value that grows approximately linearly with the number of
89      *  intervals comprised in the region. Empty region will return 0, Rect
90      *  will return 1, Complex will return a value > 1.
91      *
92      *  Use this to compare two regions, where the larger count likely
93      *  indicates a more complex region.
94      */
95     int computeRegionComplexity() const;
96 
97     /**
98      *  Returns true if the region is non-empty, and if so, appends the
99      *  boundary(s) of the region to the specified path.
100      *  If the region is empty, returns false, and path is left unmodified.
101      */
102     bool getBoundaryPath(SkPath* path) const;
103 
104     /**
105      *  Set the region to be empty, and return false, since the resulting
106      *  region is empty
107      */
108     bool setEmpty();
109 
110     /**
111      *  If rect is non-empty, set this region to that rectangle and return true,
112      *  otherwise set this region to empty and return false.
113      */
114     bool setRect(const SkIRect&);
115 
116     /**
117      *  If left < right and top < bottom, set this region to that rectangle and
118      *  return true, otherwise set this region to empty and return false.
119      */
setRect(int32_t left,int32_t top,int32_t right,int32_t bottom)120     bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
121         return this->setRect({ left, top, right, bottom });
122     }
123 
124     /**
125      *  Set this region to the union of an array of rects. This is generally
126      *  faster than calling region.op(rect, kUnion_Op) in a loop. If count is
127      *  0, then this region is set to the empty region.
128      *  @return true if the resulting region is non-empty
129      */
130     bool setRects(const SkIRect rects[], int count);
131 
132     /**
133      *  Set this region to the specified region, and return true if it is
134      *  non-empty.
135      */
136     bool setRegion(const SkRegion&);
137 
138     /**
139      *  Set this region to the area described by the path, clipped.
140      *  Return true if the resulting region is non-empty.
141      *  This produces a region that is identical to the pixels that would be
142      *  drawn by the path (with no antialiasing) with the specified clip.
143      */
144     bool setPath(const SkPath&, const SkRegion& clip);
145 
146     /**
147      *  Returns true if the specified rectangle has a non-empty intersection
148      *  with this region.
149      */
150     bool intersects(const SkIRect&) const;
151 
152     /**
153      *  Returns true if the specified region has a non-empty intersection
154      *  with this region.
155      */
156     bool intersects(const SkRegion&) const;
157 
158     /**
159      *  Return true if the specified x,y coordinate is inside the region.
160      */
161     bool contains(int32_t x, int32_t y) const;
162 
163     /**
164      *  Return true if the specified rectangle is completely inside the region.
165      *  This works for simple (rectangular) and complex regions, and always
166      *  returns the correct result. Note: if either this region or the rectangle
167      *  is empty, contains() returns false.
168      */
169     bool contains(const SkIRect&) const;
170 
171     /**
172      *  Return true if the specified region is completely inside the region.
173      *  This works for simple (rectangular) and complex regions, and always
174      *  returns the correct result. Note: if either region is empty, contains()
175      *  returns false.
176      */
177     bool contains(const SkRegion&) const;
178 
179     /**
180      *  Return true if this region is a single rectangle (not complex) and the
181      *  specified rectangle is contained by this region. Returning false is not
182      *  a guarantee that the rectangle is not contained by this region, but
183      *  return true is a guarantee that the rectangle is contained by this region.
184      */
quickContains(const SkIRect & r)185     bool quickContains(const SkIRect& r) const {
186         return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
187     }
188 
189     /**
190      *  Return true if this region is a single rectangle (not complex) and the
191      *  specified rectangle is contained by this region. Returning false is not
192      *  a guarantee that the rectangle is not contained by this region, but
193      *  return true is a guarantee that the rectangle is contained by this
194      *  region.
195      */
quickContains(int32_t left,int32_t top,int32_t right,int32_t bottom)196     bool quickContains(int32_t left, int32_t top, int32_t right,
197                        int32_t bottom) const {
198         SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
199 
200         return left < right && top < bottom &&
201                fRunHead == SkRegion_gRectRunHeadPtr &&  // this->isRect()
202                /* fBounds.contains(left, top, right, bottom); */
203                fBounds.fLeft <= left && fBounds.fTop <= top &&
204                fBounds.fRight >= right && fBounds.fBottom >= bottom;
205     }
206 
207     /**
208      *  Return true if this region is empty, or if the specified rectangle does
209      *  not intersect the region. Returning false is not a guarantee that they
210      *  intersect, but returning true is a guarantee that they do not.
211      */
quickReject(const SkIRect & rect)212     bool quickReject(const SkIRect& rect) const {
213         return this->isEmpty() || rect.isEmpty() ||
214                 !SkIRect::Intersects(fBounds, rect);
215     }
216 
217     /**
218      *  Return true if this region, or rgn, is empty, or if their bounds do not
219      *  intersect. Returning false is not a guarantee that they intersect, but
220      *  returning true is a guarantee that they do not.
221      */
quickReject(const SkRegion & rgn)222     bool quickReject(const SkRegion& rgn) const {
223         return this->isEmpty() || rgn.isEmpty() ||
224                !SkIRect::Intersects(fBounds, rgn.fBounds);
225     }
226 
227     /** Translate the region by the specified (dx, dy) amount. */
translate(int dx,int dy)228     void translate(int dx, int dy) { this->translate(dx, dy, this); }
229 
230     /**
231      *  Translate the region by the specified (dx, dy) amount, writing the
232      *  resulting region into dst. Note: it is legal to pass this region as the
233      *  dst parameter, effectively translating the region in place. If dst is
234      *  null, nothing happens.
235      */
236     void translate(int dx, int dy, SkRegion* dst) const;
237 
238     /**
239      *  The logical operations that can be performed when combining two regions.
240      */
241     enum Op {
242         kDifference_Op, //!< subtract the op region from the first region
243         kIntersect_Op,  //!< intersect the two regions
244         kUnion_Op,      //!< union (inclusive-or) the two regions
245         kXOR_Op,        //!< exclusive-or the two regions
246         /** subtract the first region from the op region */
247         kReverseDifference_Op,
248         kReplace_Op,    //!< replace the dst region with the op region
249 
250         kLastOp = kReplace_Op
251     };
252 
253     static const int kOpCnt = kLastOp + 1;
254 
255     /**
256      *  Set this region to the result of applying the Op to this region and the
257      *  specified rectangle: this = (this op rect).
258      *  Return true if the resulting region is non-empty.
259      */
op(const SkIRect & rect,Op op)260     bool op(const SkIRect& rect, Op op) {
261         if (this->isRect() && kIntersect_Op == op) {
262             if (!fBounds.intersect(rect)) {
263                 return this->setEmpty();
264             }
265             return true;
266         }
267         return this->op(*this, rect, op);
268     }
269 
270     /**
271      *  Set this region to the result of applying the Op to this region and the
272      *  specified rectangle: this = (this op rect).
273      *  Return true if the resulting region is non-empty.
274      */
op(int left,int top,int right,int bottom,Op op)275     bool op(int left, int top, int right, int bottom, Op op) {
276         SkIRect rect;
277         rect.set(left, top, right, bottom);
278         return this->op(*this, rect, op);
279     }
280 
281     /**
282      *  Set this region to the result of applying the Op to this region and the
283      *  specified region: this = (this op rgn).
284      *  Return true if the resulting region is non-empty.
285      */
op(const SkRegion & rgn,Op op)286     bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
287 
288     /**
289      *  Set this region to the result of applying the Op to the specified
290      *  rectangle and region: this = (rect op rgn).
291      *  Return true if the resulting region is non-empty.
292      */
293     bool op(const SkIRect& rect, const SkRegion& rgn, Op);
294 
295     /**
296      *  Set this region to the result of applying the Op to the specified
297      *  region and rectangle: this = (rgn op rect).
298      *  Return true if the resulting region is non-empty.
299      */
300     bool op(const SkRegion& rgn, const SkIRect& rect, Op);
301 
302     /**
303      *  Set this region to the result of applying the Op to the specified
304      *  regions: this = (rgna op rgnb).
305      *  Return true if the resulting region is non-empty.
306      */
307     bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
308 
309 #ifdef SK_BUILD_FOR_ANDROID
310     /** Returns a new char* containing the list of rectangles in this region
311      */
312     char* toString();
313 #endif
314 
315     /**
316      *  Returns the sequence of rectangles, sorted in Y and X, that make up
317      *  this region.
318      */
319     class SK_API Iterator {
320     public:
Iterator()321         Iterator() : fRgn(nullptr), fDone(true) {}
322         Iterator(const SkRegion&);
323         // if we have a region, reset to it and return true, else return false
324         bool rewind();
325         // reset the iterator, using the new region
326         void reset(const SkRegion&);
done()327         bool done() const { return fDone; }
328         void next();
rect()329         const SkIRect& rect() const { return fRect; }
330         // may return null
rgn()331         const SkRegion* rgn() const { return fRgn; }
332 
333     private:
334         const SkRegion* fRgn;
335         const RunType*  fRuns;
336         SkIRect         fRect;
337         bool            fDone;
338     };
339 
340     /**
341      *  Returns the sequence of rectangles, sorted in Y and X, that make up
342      *  this region intersected with the specified clip rectangle.
343      */
344     class SK_API Cliperator {
345     public:
346         Cliperator(const SkRegion&, const SkIRect& clip);
done()347         bool done() { return fDone; }
348         void  next();
rect()349         const SkIRect& rect() const { return fRect; }
350 
351     private:
352         Iterator    fIter;
353         SkIRect     fClip;
354         SkIRect     fRect;
355         bool        fDone;
356     };
357 
358     /**
359      *  Returns the sequence of runs that make up this region for the specified
360      *  Y scanline, clipped to the specified left and right X values.
361      */
362     class Spanerator {
363     public:
364         Spanerator(const SkRegion&, int y, int left, int right);
365         bool next(int* left, int* right);
366 
367     private:
368         const SkRegion::RunType* fRuns;
369         int     fLeft, fRight;
370         bool    fDone;
371     };
372 
373     /**
374      *  Write the region to the buffer, and return the number of bytes written.
375      *  If buffer is NULL, it still returns the number of bytes.
376      */
377     size_t writeToMemory(void* buffer) const;
378     /**
379      * Initializes the region from the buffer
380      *
381      * @param buffer Memory to read from
382      * @param length Amount of memory available in the buffer
383      * @return number of bytes read (must be a multiple of 4) or
384      *         0 if there was not enough memory available
385      */
386     size_t readFromMemory(const void* buffer, size_t length);
387 
388     /**
389      *  Returns a reference to a global empty region. Just a convenience for
390      *  callers that need a const empty region.
391      */
392     static const SkRegion& GetEmptyRegion();
393 
394     SkDEBUGCODE(void dump() const;)
395     SkDEBUGCODE(void validate() const;)
396     SkDEBUGCODE(static void UnitTest();)
397 
398     // expose this to allow for regression test on complex regions
399     SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);)
400 
401 private:
402     enum {
403         kOpCount = kReplace_Op + 1
404     };
405 
406     enum {
407         // T
408         // [B N L R S]
409         // S
410         kRectRegionRuns = 7
411     };
412 
413     friend class android::Region;    // needed for marshalling efficiently
414 
415     struct RunHead;
416 
417     // allocate space for count runs
418     void allocateRuns(int count);
419     void allocateRuns(int count, int ySpanCount, int intervalCount);
420     void allocateRuns(const RunHead& src);
421 
422     SkIRect     fBounds;
423     RunHead*    fRunHead;
424 
425     void freeRuns();
426 
427     /**
428      *  Return the runs from this region, consing up fake runs if the region
429      *  is empty or a rect. In those 2 cases, we use tmpStorage to hold the
430      *  run data.
431      */
432     const RunType*  getRuns(RunType tmpStorage[], int* intervals) const;
433 
434     // This is called with runs[] that do not yet have their interval-count
435     // field set on each scanline. That is computed as part of this call
436     // (inside ComputeRunBounds).
437     bool setRuns(RunType runs[], int count);
438 
439     int count_runtype_values(int* itop, int* ibot) const;
440 
441     bool isValid() const;
442 
443     static void BuildRectRuns(const SkIRect& bounds,
444                               RunType runs[kRectRegionRuns]);
445 
446     // If the runs define a simple rect, return true and set bounds to that
447     // rect. If not, return false and ignore bounds.
448     static bool RunsAreARect(const SkRegion::RunType runs[], int count,
449                              SkIRect* bounds);
450 
451     /**
452      *  If the last arg is null, just return if the result is non-empty,
453      *  else store the result in the last arg.
454      */
455     static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*);
456 
457     friend struct RunHead;
458     friend class Iterator;
459     friend class Spanerator;
460     friend class SkRegionPriv;
461     friend class SkRgnBuilder;
462     friend class SkFlatRegion;
463 };
464 
465 #endif
466