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