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