• 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    0
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         SkASSERT(&src);
63         *this = src;
64         return !this->isEmpty();
65     }
66 
67     /**
68      *  Swap the contents of this and the specified region. This operation
69      *  is gauarenteed to never fail.
70      */
71     void swap(SkRegion&);
72 
73     /** Return true if this region is empty */
isEmpty()74     bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
75 
76     /** Return true if this region is a single, non-empty rectangle */
isRect()77     bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
78 
79     /** Return true if this region consists of more than 1 rectangular area */
isComplex()80     bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
81 
82     /**
83      *  Return the bounds of this region. If the region is empty, returns an
84      *  empty rectangle.
85      */
getBounds()86     const SkIRect& getBounds() const { return fBounds; }
87 
88     /**
89      *  Returns true if the region is non-empty, and if so, appends the
90      *  boundary(s) of the region to the specified path.
91      *  If the region is empty, returns false, and path is left unmodified.
92      */
93     bool getBoundaryPath(SkPath* path) const;
94 
95     /**
96      *  Set the region to be empty, and return false, since the resulting
97      *  region is empty
98      */
99     bool setEmpty();
100 
101     /**
102      *  If rect is non-empty, set this region to that rectangle and return true,
103      *  otherwise set this region to empty and return false.
104      */
105     bool setRect(const SkIRect&);
106 
107     /**
108      *  If left < right and top < bottom, set this region to that rectangle and
109      *  return true, otherwise set this region to empty and return false.
110      */
111     bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom);
112 
113     /**
114      *  Set this region to the union of an array of rects. This is generally
115      *  faster than calling region.op(rect, kUnion_Op) in a loop. If count is
116      *  0, then this region is set to the empty region.
117      *  @return true if the resulting region is non-empty
118      */
119     bool setRects(const SkIRect rects[], int count);
120 
121     /**
122      *  Set this region to the specified region, and return true if it is
123      *  non-empty.
124      */
125     bool setRegion(const SkRegion&);
126 
127     /**
128      *  Set this region to the area described by the path, clipped.
129      *  Return true if the resulting region is non-empty.
130      *  This produces a region that is identical to the pixels that would be
131      *  drawn by the path (with no antialiasing) with the specified clip.
132      */
133     bool setPath(const SkPath&, const SkRegion& clip);
134 
135     /**
136      *  Returns true if the specified rectangle has a non-empty intersection
137      *  with this region.
138      */
139     bool intersects(const SkIRect&) const;
140 
141     /**
142      *  Returns true if the specified region has a non-empty intersection
143      *  with this region.
144      */
145     bool intersects(const SkRegion&) const;
146 
147     /**
148      *  Return true if the specified x,y coordinate is inside the region.
149      */
150     bool contains(int32_t x, int32_t y) const;
151 
152     /**
153      *  Return true if the specified rectangle is completely inside the region.
154      *  This works for simple (rectangular) and complex regions, and always
155      *  returns the correct result. Note: if either this region or the rectangle
156      *  is empty, contains() returns false.
157      */
158     bool contains(const SkIRect&) const;
159 
160     /**
161      *  Return true if the specified region is completely inside the region.
162      *  This works for simple (rectangular) and complex regions, and always
163      *  returns the correct result. Note: if either region is empty, contains()
164      *  returns false.
165      */
166     bool contains(const SkRegion&) const;
167 
168     /**
169      *  Return true if this region is a single rectangle (not complex) and the
170      *  specified rectangle is contained by this region. Returning false is not
171      *  a guarantee that the rectangle is not contained by this region, but
172      *  return true is a guarantee that the rectangle is contained by this region.
173      */
quickContains(const SkIRect & r)174     bool quickContains(const SkIRect& r) const {
175         return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
176     }
177 
178     /**
179      *  Return true if this region is a single rectangle (not complex) and the
180      *  specified rectangle is contained by this region. Returning false is not
181      *  a guarantee that the rectangle is not contained by this region, but
182      *  return true is a guarantee that the rectangle is contained by this
183      *  region.
184      */
quickContains(int32_t left,int32_t top,int32_t right,int32_t bottom)185     bool quickContains(int32_t left, int32_t top, int32_t right,
186                        int32_t bottom) const {
187         SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
188 
189         return left < right && top < bottom &&
190                fRunHead == SkRegion_gRectRunHeadPtr &&  // this->isRect()
191                /* fBounds.contains(left, top, right, bottom); */
192                fBounds.fLeft <= left && fBounds.fTop <= top &&
193                fBounds.fRight >= right && fBounds.fBottom >= bottom;
194     }
195 
196     /**
197      *  Return true if this region is empty, or if the specified rectangle does
198      *  not intersect the region. Returning false is not a guarantee that they
199      *  intersect, but returning true is a guarantee that they do not.
200      */
quickReject(const SkIRect & rect)201     bool quickReject(const SkIRect& rect) const {
202         return this->isEmpty() || rect.isEmpty() ||
203                 !SkIRect::Intersects(fBounds, rect);
204     }
205 
206     /**
207      *  Return true if this region, or rgn, is empty, or if their bounds do not
208      *  intersect. Returning false is not a guarantee that they intersect, but
209      *  returning true is a guarantee that they do not.
210      */
quickReject(const SkRegion & rgn)211     bool quickReject(const SkRegion& rgn) const {
212         return this->isEmpty() || rgn.isEmpty() ||
213                !SkIRect::Intersects(fBounds, rgn.fBounds);
214     }
215 
216     /** Translate the region by the specified (dx, dy) amount. */
translate(int dx,int dy)217     void translate(int dx, int dy) { this->translate(dx, dy, this); }
218 
219     /**
220      *  Translate the region by the specified (dx, dy) amount, writing the
221      *  resulting region into dst. Note: it is legal to pass this region as the
222      *  dst parameter, effectively translating the region in place. If dst is
223      *  null, nothing happens.
224      */
225     void translate(int dx, int dy, SkRegion* dst) const;
226 
227     /**
228      *  The logical operations that can be performed when combining two regions.
229      */
230     enum Op {
231         kDifference_Op, //!< subtract the op region from the first region
232         kIntersect_Op,  //!< intersect the two regions
233         kUnion_Op,      //!< union (inclusive-or) the two regions
234         kXOR_Op,        //!< exclusive-or the two regions
235         /** subtract the first region from the op region */
236         kReverseDifference_Op,
237         kReplace_Op     //!< replace the dst region with the op region
238     };
239 
240     /**
241      *  Set this region to the result of applying the Op to this region and the
242      *  specified rectangle: this = (this op rect).
243      *  Return true if the resulting region is non-empty.
244      */
op(const SkIRect & rect,Op op)245     bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); }
246 
247     /**
248      *  Set this region to the result of applying the Op to this region and the
249      *  specified rectangle: this = (this op rect).
250      *  Return true if the resulting region is non-empty.
251      */
op(int left,int top,int right,int bottom,Op op)252     bool op(int left, int top, int right, int bottom, Op op) {
253         SkIRect rect;
254         rect.set(left, top, right, bottom);
255         return this->op(*this, rect, op);
256     }
257 
258     /**
259      *  Set this region to the result of applying the Op to this region and the
260      *  specified region: this = (this op rgn).
261      *  Return true if the resulting region is non-empty.
262      */
op(const SkRegion & rgn,Op op)263     bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
264 
265     /**
266      *  Set this region to the result of applying the Op to the specified
267      *  rectangle and region: this = (rect op rgn).
268      *  Return true if the resulting region is non-empty.
269      */
270     bool op(const SkIRect& rect, const SkRegion& rgn, Op);
271 
272     /**
273      *  Set this region to the result of applying the Op to the specified
274      *  region and rectangle: this = (rgn op rect).
275      *  Return true if the resulting region is non-empty.
276      */
277     bool op(const SkRegion& rgn, const SkIRect& rect, Op);
278 
279     /**
280      *  Set this region to the result of applying the Op to the specified
281      *  regions: this = (rgna op rgnb).
282      *  Return true if the resulting region is non-empty.
283      */
284     bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
285 
286 #ifdef SK_BUILD_FOR_ANDROID
287     /** Returns a new char* containing the list of rectangles in this region
288      */
289     char* toString();
290 #endif
291 
292     /**
293      *  Returns the sequence of rectangles, sorted in Y and X, that make up
294      *  this region.
295      */
296     class SK_API Iterator {
297     public:
Iterator()298         Iterator() : fRgn(NULL), fDone(true) {}
299         Iterator(const SkRegion&);
300         // if we have a region, reset to it and return true, else return false
301         bool rewind();
302         // reset the iterator, using the new region
303         void reset(const SkRegion&);
done()304         bool done() const { return fDone; }
305         void next();
rect()306         const SkIRect& rect() const { return fRect; }
307         // may return null
rgn()308         const SkRegion* rgn() const { return fRgn; }
309 
310     private:
311         const SkRegion* fRgn;
312         const RunType*  fRuns;
313         SkIRect         fRect;
314         bool            fDone;
315     };
316 
317     /**
318      *  Returns the sequence of rectangles, sorted in Y and X, that make up
319      *  this region intersected with the specified clip rectangle.
320      */
321     class SK_API Cliperator {
322     public:
323         Cliperator(const SkRegion&, const SkIRect& clip);
done()324         bool done() { return fDone; }
325         void  next();
rect()326         const SkIRect& rect() const { return fRect; }
327 
328     private:
329         Iterator    fIter;
330         SkIRect     fClip;
331         SkIRect     fRect;
332         bool        fDone;
333     };
334 
335     /**
336      *  Returns the sequence of runs that make up this region for the specified
337      *  Y scanline, clipped to the specified left and right X values.
338      */
339     class Spanerator {
340     public:
341         Spanerator(const SkRegion&, int y, int left, int right);
342         bool next(int* left, int* right);
343 
344     private:
345         const SkRegion::RunType* fRuns;
346         int     fLeft, fRight;
347         bool    fDone;
348     };
349 
350     /**
351      *  Write the region to the buffer, and return the number of bytes written.
352      *  If buffer is NULL, it still returns the number of bytes.
353      */
354     uint32_t flatten(void* buffer) const;
355 
356     /**
357      *  Initialized the region from the buffer, returning the number
358      *  of bytes actually read.
359      */
360     uint32_t unflatten(const void* buffer);
361 
362     /**
363      *  Returns a reference to a global empty region. Just a convenience for
364      *  callers that need a const empty region.
365      */
366     static const SkRegion& GetEmptyRegion();
367 
368     SkDEBUGCODE(void dump() const;)
369     SkDEBUGCODE(void validate() const;)
370     SkDEBUGCODE(static void UnitTest();)
371 
372     // expose this to allow for regression test on complex regions
373     SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);)
374 
375 private:
376     enum {
377         kOpCount = kReplace_Op + 1
378     };
379 
380     enum {
381         kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S]
382     };
383 
384     friend class android::Region;    // needed for marshalling efficiently
385     void allocateRuns(int count); // allocate space for count runs
386 
387     struct RunHead;
388 
389     SkIRect     fBounds;
390     RunHead*    fRunHead;
391 
392     void            freeRuns();
393     const RunType*  getRuns(RunType tmpStorage[], int* count) const;
394     bool            setRuns(RunType runs[], int count);
395 
396     int count_runtype_values(int* itop, int* ibot) const;
397 
398     static void BuildRectRuns(const SkIRect& bounds,
399                               RunType runs[kRectRegionRuns]);
400     // returns true if runs are just a rect
401     static bool ComputeRunBounds(const RunType runs[], int count,
402                                  SkIRect* bounds);
403 
404     friend struct RunHead;
405     friend class Iterator;
406     friend class Spanerator;
407     friend class SkRgnBuilder;
408     friend class SkFlatRegion;
409 };
410 
411 #endif
412