• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 class SkPath;
23 class SkRgnBuilder;
24 
25 namespace 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 */
37 class SkRegion {
38 public:
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     */
set(const SkRegion & src)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 */
isEmpty()71     bool    isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
72     /** Return true if this region is a single, non-empty rectangle */
isRect()73     bool    isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
74     /** Return true if this region consists of more than 1 rectangular area */
isComplex()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     */
getBounds()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 specified region, and return true if it is
102         non-empty. */
103     bool    setRegion(const SkRegion&);
104 
105     /** Set this region to the area described by the path, clipped.
106         Return true if the resulting region is non-empty.
107         This produces a region that is identical to the pixels that would be
108         drawn by the path (with no antialiasing) with the specified clip.
109     */
110     bool    setPath(const SkPath&, const SkRegion& clip);
111 
112     /** Returns true if the specified rectangle has a non-empty intersection
113         with this region.
114     */
115     bool    intersects(const SkIRect&) const;
116 
117     /** Returns true if the specified region has a non-empty intersection
118         with this region.
119     */
120     bool    intersects(const SkRegion&) const;
121 
122     /** Return true if the specified x,y coordinate is inside the region.
123     */
124     bool    contains(int32_t x, int32_t y) const;
125 
126     /** Return true if the specified rectangle is completely inside the region.
127         This works for simple (rectangular) and complex regions, and always
128         returns the correct result. Note: if either this region or the rectangle
129         is empty, contains() returns false.
130     */
131     bool    contains(const SkIRect&) const;
132 
133     /** Return true if the specified region is completely inside the region.
134         This works for simple (rectangular) and complex regions, and always
135         returns the correct result. Note: if either region is empty, contains()
136         returns false.
137     */
138     bool    contains(const SkRegion&) const;
139 
140     /** Return true if this region is a single rectangle (not complex) and the
141         specified rectangle is contained by this region. Returning false is not
142         a guarantee that the rectangle is not contained by this region, but
143         return true is a guarantee that the rectangle is contained by this region.
144     */
quickContains(const SkIRect & r)145     bool quickContains(const SkIRect& r) const {
146         return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
147     }
148 
149     /** Return true if this region is a single rectangle (not complex) and the
150         specified rectangle is contained by this region. Returning false is not
151         a guarantee that the rectangle is not contained by this region, but
152         return true is a guarantee that the rectangle is contained by this
153         region.
154     */
quickContains(int32_t left,int32_t top,int32_t right,int32_t bottom)155     bool quickContains(int32_t left, int32_t top, int32_t right,
156                        int32_t bottom) const {
157         SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
158 
159         return left < right && top < bottom &&
160                fRunHead == SkRegion_gRectRunHeadPtr &&  // this->isRect()
161                /* fBounds.contains(left, top, right, bottom); */
162                fBounds.fLeft <= left && fBounds.fTop <= top &&
163                fBounds.fRight >= right && fBounds.fBottom >= bottom;
164     }
165 
166     /** Return true if this region is empty, or if the specified rectangle does
167         not intersect the region. Returning false is not a guarantee that they
168         intersect, but returning true is a guarantee that they do not.
169     */
quickReject(const SkIRect & rect)170     bool quickReject(const SkIRect& rect) const
171     {
172         return this->isEmpty() || rect.isEmpty() ||
173                 !SkIRect::Intersects(fBounds, rect);
174     }
175 
176     /** Return true if this region, or rgn, is empty, or if their bounds do not
177         intersect. Returning false is not a guarantee that they intersect, but
178         returning true is a guarantee that they do not.
179     */
quickReject(const SkRegion & rgn)180     bool quickReject(const SkRegion& rgn) const {
181         return this->isEmpty() || rgn.isEmpty() ||
182                !SkIRect::Intersects(fBounds, rgn.fBounds);
183     }
184 
185     /** Translate the region by the specified (dx, dy) amount.
186     */
translate(int dx,int dy)187     void translate(int dx, int dy) { this->translate(dx, dy, this); }
188 
189     /** Translate the region by the specified (dx, dy) amount, writing the
190         resulting region into dst. Note: it is legal to pass this region as the
191         dst parameter, effectively translating the region in place. If dst is
192         null, nothing happens.
193     */
194     void translate(int dx, int dy, SkRegion* dst) const;
195 
196     /** The logical operations that can be performed when combining two regions.
197     */
198     enum Op {
199         kDifference_Op, //!< subtract the op region from the first region
200         kIntersect_Op,  //!< intersect the two regions
201         kUnion_Op,      //!< union (inclusive-or) the two regions
202         kXOR_Op,        //!< exclusive-or the two regions
203         /** subtract the first region from the op region */
204         kReverseDifference_Op,
205         kReplace_Op     //!< replace the dst region with the op region
206     };
207 
208     /** Set this region to the result of applying the Op to this region and the
209         specified rectangle: this = (this op rect).
210         Return true if the resulting region is non-empty.
211         */
op(const SkIRect & rect,Op op)212     bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); }
213 
214     /** Set this region to the result of applying the Op to this region and the
215         specified rectangle: this = (this op rect).
216         Return true if the resulting region is non-empty.
217     */
op(int left,int top,int right,int bottom,Op op)218     bool op(int left, int top, int right, int bottom, Op op) {
219         SkIRect rect;
220         rect.set(left, top, right, bottom);
221         return this->op(*this, rect, op);
222     }
223 
224     /** Set this region to the result of applying the Op to this region and the
225         specified region: this = (this op rgn).
226         Return true if the resulting region is non-empty.
227     */
op(const SkRegion & rgn,Op op)228     bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
229     /** Set this region to the result of applying the Op to the specified
230         rectangle and region: this = (rect op rgn).
231         Return true if the resulting region is non-empty.
232     */
233     bool op(const SkIRect& rect, const SkRegion& rgn, Op);
234     /** Set this region to the result of applying the Op to the specified
235         region and rectangle: this = (rgn op rect).
236         Return true if the resulting region is non-empty.
237     */
238     bool op(const SkRegion& rgn, const SkIRect& rect, Op);
239     /** Set this region to the result of applying the Op to the specified
240         regions: this = (rgna op rgnb).
241         Return true if the resulting region is non-empty.
242     */
243     bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
244 
245     /** Returns the sequence of rectangles, sorted in Y and X, that make up
246         this region.
247     */
248     class Iterator {
249     public:
Iterator()250         Iterator() : fRgn(NULL), fDone(true) {}
251         Iterator(const SkRegion&);
252         // if we have a region, reset to it and return true, else return false
253         bool rewind();
254         // reset the iterator, using the new region
255         void reset(const SkRegion&);
done()256         bool done() { return fDone; }
257         void next();
rect()258         const SkIRect& rect() const { return fRect; }
259 
260     private:
261         const SkRegion* fRgn;
262         const RunType*  fRuns;
263         SkIRect         fRect;
264         bool            fDone;
265     };
266 
267     /** Returns the sequence of rectangles, sorted in Y and X, that make up
268         this region intersected with the specified clip rectangle.
269     */
270     class Cliperator {
271     public:
272         Cliperator(const SkRegion&, const SkIRect& clip);
done()273         bool            done() { return fDone; }
274         void            next();
rect()275         const SkIRect& rect() const { return fRect; }
276 
277     private:
278         Iterator    fIter;
279         SkIRect     fClip;
280         SkIRect     fRect;
281         bool        fDone;
282     };
283 
284     /** Returns the sequence of runs that make up this region for the specified
285         Y scanline, clipped to the specified left and right X values.
286     */
287     class Spanerator {
288     public:
289         Spanerator(const SkRegion&, int y, int left, int right);
290         bool    next(int* left, int* right);
291 
292     private:
293         const SkRegion::RunType* fRuns;
294         int     fLeft, fRight;
295         bool    fDone;
296     };
297 
298     /** Write the region to the buffer, and return the number of bytes written.
299         If buffer is NULL, it still returns the number of bytes.
300     */
301     uint32_t flatten(void* buffer) const;
302     /** Initialized the region from the buffer, returning the number
303         of bytes actually read.
304     */
305     uint32_t unflatten(const void* buffer);
306 
307     SkDEBUGCODE(void dump() const;)
308     SkDEBUGCODE(void validate() const;)
309     SkDEBUGCODE(static void UnitTest();)
310 
311     // expose this to allow for regression test on complex regions
312     SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);)
313 
314 private:
315     enum {
316         kOpCount = kReplace_Op + 1
317     };
318 
319     enum {
320         kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S]
321     };
322 
323     friend class android::Region;    // needed for marshalling efficiently
324     void allocateRuns(int count); // allocate space for count runs
325 
326     struct RunHead;
327 
328     SkIRect     fBounds;
329     RunHead*    fRunHead;
330 
331     void            freeRuns();
332     const RunType*  getRuns(RunType tmpStorage[], int* count) const;
333     bool            setRuns(RunType runs[], int count);
334 
335     int count_runtype_values(int* itop, int* ibot) const;
336 
337     static void BuildRectRuns(const SkIRect& bounds,
338                               RunType runs[kRectRegionRuns]);
339     // returns true if runs are just a rect
340     static bool ComputeRunBounds(const RunType runs[], int count,
341                                  SkIRect* bounds);
342 
343     friend struct RunHead;
344     friend class Iterator;
345     friend class Spanerator;
346     friend class SkRgnBuilder;
347     friend class SkFlatRegion;
348 };
349 
350 
351 #endif
352 
353