Home | History | Annotate | Download | only in core
      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     */
     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 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     */
    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     */
    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     */
    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     */
    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     */
    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         */
    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     */
    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     */
    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:
    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&);
    256         bool done() { return fDone; }
    257         void next();
    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);
    273         bool            done() { return fDone; }
    274         void            next();
    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