SkRegion.h revision 137a4ca42423bbb6d683067ea544c9a48f18f06c
1/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkRegion_DEFINED
18#define SkRegion_DEFINED
19
20#include "SkRect.h"
21
22class SkPath;
23class SkRgnBuilder;
24
25namespace android {
26    class Region;
27}
28
29#define SkRegion_gEmptyRunHeadPtr   ((SkRegion::RunHead*)-1)
30#define SkRegion_gRectRunHeadPtr    0
31
32/** \class SkRegion
33
34    The SkRegion class encapsulates the geometric region used to specify
35    clipping areas for drawing.
36*/
37class SK_API SkRegion {
38public:
39    typedef int32_t RunType;
40    enum {
41        kRunTypeSentinel = 0x7FFFFFFF
42    };
43
44    SkRegion();
45    SkRegion(const SkRegion&);
46    explicit SkRegion(const SkIRect&);
47    ~SkRegion();
48
49    SkRegion& operator=(const SkRegion&);
50
51    friend int operator==(const SkRegion& a, const SkRegion& b);
52    friend int operator!=(const SkRegion& a, const SkRegion& b) {
53        return !(a == b);
54    }
55
56    /** Replace this region with the specified region, and return true if the
57        resulting region is non-empty.
58    */
59    bool set(const SkRegion& src) {
60        SkASSERT(&src);
61        *this = src;
62        return !this->isEmpty();
63    }
64
65    /** Swap the contents of this and the specified region. This operation
66        is gauarenteed to never fail.
67    */
68    void    swap(SkRegion&);
69
70    /** Return true if this region is empty */
71    bool    isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
72    /** Return true if this region is a single, non-empty rectangle */
73    bool    isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
74    /** Return true if this region consists of more than 1 rectangular area */
75    bool    isComplex() const { return !this->isEmpty() && !this->isRect(); }
76    /** Return the bounds of this region. If the region is empty, returns an
77        empty rectangle.
78    */
79    const SkIRect& getBounds() const { return fBounds; }
80
81    /** Returns true if the region is non-empty, and if so, sets the specified
82        path to the boundary(s) of the region.
83    */
84    bool getBoundaryPath(SkPath* path) const;
85
86    /** Set the region to be empty, and return false, since the resulting
87        region is empty
88    */
89    bool    setEmpty();
90
91    /** If rect is non-empty, set this region to that rectangle and return true,
92        otherwise set this region to empty and return false.
93    */
94    bool    setRect(const SkIRect&);
95
96    /** If left < right and top < bottom, set this region to that rectangle and
97        return true, otherwise set this region to empty and return false.
98    */
99    bool    setRect(int32_t left, int32_t top, int32_t right, int32_t bottom);
100
101    /** Set this region to the union of an array of rects. This is generally
102        faster than calling region.op(rect, kUnion_Op) in a loop. If count is
103        0, then this region is set to the empty region.
104        @return true if the resulting region is non-empty
105     */
106    bool setRects(const SkIRect rects[], int count);
107
108    /** Set this region to the specified region, and return true if it is
109        non-empty. */
110    bool    setRegion(const SkRegion&);
111
112    /** Set this region to the area described by the path, clipped.
113        Return true if the resulting region is non-empty.
114        This produces a region that is identical to the pixels that would be
115        drawn by the path (with no antialiasing) with the specified clip.
116    */
117    bool    setPath(const SkPath&, const SkRegion& clip);
118
119    /** Returns true if the specified rectangle has a non-empty intersection
120        with this region.
121    */
122    bool    intersects(const SkIRect&) const;
123
124    /** Returns true if the specified region has a non-empty intersection
125        with this region.
126    */
127    bool    intersects(const SkRegion&) const;
128
129    /** Return true if the specified x,y coordinate is inside the region.
130    */
131    bool    contains(int32_t x, int32_t y) const;
132
133    /** Return true if the specified rectangle is completely inside the region.
134        This works for simple (rectangular) and complex regions, and always
135        returns the correct result. Note: if either this region or the rectangle
136        is empty, contains() returns false.
137    */
138    bool    contains(const SkIRect&) const;
139
140    /** Return true if the specified region is completely inside the region.
141        This works for simple (rectangular) and complex regions, and always
142        returns the correct result. Note: if either region is empty, contains()
143        returns false.
144    */
145    bool    contains(const SkRegion&) const;
146
147    /** Return true if this region is a single rectangle (not complex) and the
148        specified rectangle is contained by this region. Returning false is not
149        a guarantee that the rectangle is not contained by this region, but
150        return true is a guarantee that the rectangle is contained by this region.
151    */
152    bool quickContains(const SkIRect& r) const {
153        return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
154    }
155
156    /** Return true if this region is a single rectangle (not complex) and the
157        specified rectangle is contained by this region. Returning false is not
158        a guarantee that the rectangle is not contained by this region, but
159        return true is a guarantee that the rectangle is contained by this
160        region.
161    */
162    bool quickContains(int32_t left, int32_t top, int32_t right,
163                       int32_t bottom) const {
164        SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
165
166        return left < right && top < bottom &&
167               fRunHead == SkRegion_gRectRunHeadPtr &&  // this->isRect()
168               /* fBounds.contains(left, top, right, bottom); */
169               fBounds.fLeft <= left && fBounds.fTop <= top &&
170               fBounds.fRight >= right && fBounds.fBottom >= bottom;
171    }
172
173    /** Return true if this region is empty, or if the specified rectangle does
174        not intersect the region. Returning false is not a guarantee that they
175        intersect, but returning true is a guarantee that they do not.
176    */
177    bool quickReject(const SkIRect& rect) const
178    {
179        return this->isEmpty() || rect.isEmpty() ||
180                !SkIRect::Intersects(fBounds, rect);
181    }
182
183    /** Return true if this region, or rgn, is empty, or if their bounds do not
184        intersect. Returning false is not a guarantee that they intersect, but
185        returning true is a guarantee that they do not.
186    */
187    bool quickReject(const SkRegion& rgn) const {
188        return this->isEmpty() || rgn.isEmpty() ||
189               !SkIRect::Intersects(fBounds, rgn.fBounds);
190    }
191
192    /** Translate the region by the specified (dx, dy) amount.
193    */
194    void translate(int dx, int dy) { this->translate(dx, dy, this); }
195
196    /** Translate the region by the specified (dx, dy) amount, writing the
197        resulting region into dst. Note: it is legal to pass this region as the
198        dst parameter, effectively translating the region in place. If dst is
199        null, nothing happens.
200    */
201    void translate(int dx, int dy, SkRegion* dst) const;
202
203    /** The logical operations that can be performed when combining two regions.
204    */
205    enum Op {
206        kDifference_Op, //!< subtract the op region from the first region
207        kIntersect_Op,  //!< intersect the two regions
208        kUnion_Op,      //!< union (inclusive-or) the two regions
209        kXOR_Op,        //!< exclusive-or the two regions
210        /** subtract the first region from the op region */
211        kReverseDifference_Op,
212        kReplace_Op     //!< replace the dst region with the op region
213    };
214
215    /** Set this region to the result of applying the Op to this region and the
216        specified rectangle: this = (this op rect).
217        Return true if the resulting region is non-empty.
218        */
219    bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); }
220
221    /** Set this region to the result of applying the Op to this region and the
222        specified rectangle: this = (this op rect).
223        Return true if the resulting region is non-empty.
224    */
225    bool op(int left, int top, int right, int bottom, Op op) {
226        SkIRect rect;
227        rect.set(left, top, right, bottom);
228        return this->op(*this, rect, op);
229    }
230
231    /** Set this region to the result of applying the Op to this region and the
232        specified region: this = (this op rgn).
233        Return true if the resulting region is non-empty.
234    */
235    bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
236    /** Set this region to the result of applying the Op to the specified
237        rectangle and region: this = (rect op rgn).
238        Return true if the resulting region is non-empty.
239    */
240    bool op(const SkIRect& rect, const SkRegion& rgn, Op);
241    /** Set this region to the result of applying the Op to the specified
242        region and rectangle: this = (rgn op rect).
243        Return true if the resulting region is non-empty.
244    */
245    bool op(const SkRegion& rgn, const SkIRect& rect, Op);
246    /** Set this region to the result of applying the Op to the specified
247        regions: this = (rgna op rgnb).
248        Return true if the resulting region is non-empty.
249    */
250    bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
251
252#ifdef ANDROID
253    /** Returns a new char* containing the list of rectangles in this region
254     */
255    char* toString();
256#endif
257
258    /** Returns the sequence of rectangles, sorted in Y and X, that make up
259        this region.
260    */
261    class SK_API Iterator {
262    public:
263        Iterator() : fRgn(NULL), fDone(true) {}
264        Iterator(const SkRegion&);
265        // if we have a region, reset to it and return true, else return false
266        bool rewind();
267        // reset the iterator, using the new region
268        void reset(const SkRegion&);
269        bool done() const { return fDone; }
270        void next();
271        const SkIRect& rect() const { return fRect; }
272        // may return null
273        const SkRegion* rgn() const { return fRgn; }
274    private:
275        const SkRegion* fRgn;
276        const RunType*  fRuns;
277        SkIRect         fRect;
278        bool            fDone;
279    };
280
281    /** Returns the sequence of rectangles, sorted in Y and X, that make up
282        this region intersected with the specified clip rectangle.
283    */
284    class SK_API Cliperator {
285    public:
286        Cliperator(const SkRegion&, const SkIRect& clip);
287        bool            done() { return fDone; }
288        void            next();
289        const SkIRect& rect() const { return fRect; }
290
291    private:
292        Iterator    fIter;
293        SkIRect     fClip;
294        SkIRect     fRect;
295        bool        fDone;
296    };
297
298    /** Returns the sequence of runs that make up this region for the specified
299        Y scanline, clipped to the specified left and right X values.
300    */
301    class Spanerator {
302    public:
303        Spanerator(const SkRegion&, int y, int left, int right);
304        bool    next(int* left, int* right);
305
306    private:
307        const SkRegion::RunType* fRuns;
308        int     fLeft, fRight;
309        bool    fDone;
310    };
311
312    /** Write the region to the buffer, and return the number of bytes written.
313        If buffer is NULL, it still returns the number of bytes.
314    */
315    uint32_t flatten(void* buffer) const;
316    /** Initialized the region from the buffer, returning the number
317        of bytes actually read.
318    */
319    uint32_t unflatten(const void* buffer);
320
321    SkDEBUGCODE(void dump() const;)
322    SkDEBUGCODE(void validate() const;)
323    SkDEBUGCODE(static void UnitTest();)
324
325    // expose this to allow for regression test on complex regions
326    SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);)
327
328private:
329    enum {
330        kOpCount = kReplace_Op + 1
331    };
332
333    enum {
334        kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S]
335    };
336
337    friend class android::Region;    // needed for marshalling efficiently
338    void allocateRuns(int count); // allocate space for count runs
339
340    struct RunHead;
341
342    SkIRect     fBounds;
343    RunHead*    fRunHead;
344
345    void            freeRuns();
346    const RunType*  getRuns(RunType tmpStorage[], int* count) const;
347    bool            setRuns(RunType runs[], int count);
348
349    int count_runtype_values(int* itop, int* ibot) const;
350
351    static void BuildRectRuns(const SkIRect& bounds,
352                              RunType runs[kRectRegionRuns]);
353    // returns true if runs are just a rect
354    static bool ComputeRunBounds(const RunType runs[], int count,
355                                 SkIRect* bounds);
356
357    friend struct RunHead;
358    friend class Iterator;
359    friend class Spanerator;
360    friend class SkRgnBuilder;
361    friend class SkFlatRegion;
362};
363
364
365#endif
366
367