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
15class SkPath;
16class SkRgnBuilder;
17
18namespace 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*/
30class SK_API SkRegion {
31public:
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     */
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 */
74    bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
75
76    /** Return true if this region is a single, non-empty rectangle */
77    bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
78
79    /** Return true if this region consists of more than 1 rectangular area */
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     */
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     */
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     */
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     */
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     */
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. */
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     */
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     */
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     */
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:
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&);
304        bool done() const { return fDone; }
305        void next();
306        const SkIRect& rect() const { return fRect; }
307        // may return null
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);
324        bool done() { return fDone; }
325        void  next();
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
375private:
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