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