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 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      */
     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 */
     81     bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
     82 
     83     /** Return true if this region is a single, non-empty rectangle */
     84     bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
     85 
     86     /** Return true if this region consists of more than 1 rectangular area */
     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      */
     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      */
    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      */
    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      */
    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      */
    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. */
    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      */
    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      */
    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      */
    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:
    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&);
    311         bool done() const { return fDone; }
    312         void next();
    313         const SkIRect& rect() const { return fRect; }
    314         // may return null
    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);
    331         bool done() { return fDone; }
    332         void  next();
    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