|  |  | 
|  | /* | 
|  | * Copyright 2005 The Android Open Source Project | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #ifndef SkRegion_DEFINED | 
|  | #define SkRegion_DEFINED | 
|  |  | 
|  | #include "SkRect.h" | 
|  |  | 
|  | class SkPath; | 
|  | class SkRgnBuilder; | 
|  |  | 
|  | namespace android { | 
|  | class Region; | 
|  | } | 
|  |  | 
|  | #define SkRegion_gEmptyRunHeadPtr   ((SkRegion::RunHead*)-1) | 
|  | #define SkRegion_gRectRunHeadPtr    0 | 
|  |  | 
|  | /** \class SkRegion | 
|  |  | 
|  | The SkRegion class encapsulates the geometric region used to specify | 
|  | clipping areas for drawing. | 
|  | */ | 
|  | class SK_API SkRegion { | 
|  | public: | 
|  | typedef int32_t RunType; | 
|  | enum { | 
|  | kRunTypeSentinel = 0x7FFFFFFF | 
|  | }; | 
|  |  | 
|  | SkRegion(); | 
|  | SkRegion(const SkRegion&); | 
|  | explicit SkRegion(const SkIRect&); | 
|  | ~SkRegion(); | 
|  |  | 
|  | SkRegion& operator=(const SkRegion&); | 
|  |  | 
|  | /** | 
|  | *  Return true if the two regions are equal. i.e. The enclose exactly | 
|  | *  the same area. | 
|  | */ | 
|  | bool operator==(const SkRegion& other) const; | 
|  |  | 
|  | /** | 
|  | *  Return true if the two regions are not equal. | 
|  | */ | 
|  | bool operator!=(const SkRegion& other) const { | 
|  | return !(*this == other); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *  Replace this region with the specified region, and return true if the | 
|  | *  resulting region is non-empty. | 
|  | */ | 
|  | bool set(const SkRegion& src) { | 
|  | SkASSERT(&src); | 
|  | *this = src; | 
|  | return !this->isEmpty(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *  Swap the contents of this and the specified region. This operation | 
|  | *  is gauarenteed to never fail. | 
|  | */ | 
|  | void swap(SkRegion&); | 
|  |  | 
|  | /** Return true if this region is empty */ | 
|  | bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; } | 
|  |  | 
|  | /** Return true if this region is a single, non-empty rectangle */ | 
|  | bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; } | 
|  |  | 
|  | /** Return true if this region consists of more than 1 rectangular area */ | 
|  | bool isComplex() const { return !this->isEmpty() && !this->isRect(); } | 
|  |  | 
|  | /** | 
|  | *  Return the bounds of this region. If the region is empty, returns an | 
|  | *  empty rectangle. | 
|  | */ | 
|  | const SkIRect& getBounds() const { return fBounds; } | 
|  |  | 
|  | /** | 
|  | *  Returns a value that grows approximately linearly with the number of | 
|  | *  intervals comprised in the region. Empty region will return 0, Rect | 
|  | *  will return 1, Complex will return a value > 1. | 
|  | * | 
|  | *  Use this to compare two regions, where the larger count likely | 
|  | *  indicates a more complex region. | 
|  | */ | 
|  | int computeRegionComplexity() const; | 
|  |  | 
|  | /** | 
|  | *  Returns true if the region is non-empty, and if so, appends the | 
|  | *  boundary(s) of the region to the specified path. | 
|  | *  If the region is empty, returns false, and path is left unmodified. | 
|  | */ | 
|  | bool getBoundaryPath(SkPath* path) const; | 
|  |  | 
|  | /** | 
|  | *  Set the region to be empty, and return false, since the resulting | 
|  | *  region is empty | 
|  | */ | 
|  | bool setEmpty(); | 
|  |  | 
|  | /** | 
|  | *  If rect is non-empty, set this region to that rectangle and return true, | 
|  | *  otherwise set this region to empty and return false. | 
|  | */ | 
|  | bool setRect(const SkIRect&); | 
|  |  | 
|  | /** | 
|  | *  If left < right and top < bottom, set this region to that rectangle and | 
|  | *  return true, otherwise set this region to empty and return false. | 
|  | */ | 
|  | bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom); | 
|  |  | 
|  | /** | 
|  | *  Set this region to the union of an array of rects. This is generally | 
|  | *  faster than calling region.op(rect, kUnion_Op) in a loop. If count is | 
|  | *  0, then this region is set to the empty region. | 
|  | *  @return true if the resulting region is non-empty | 
|  | */ | 
|  | bool setRects(const SkIRect rects[], int count); | 
|  |  | 
|  | /** | 
|  | *  Set this region to the specified region, and return true if it is | 
|  | *  non-empty. | 
|  | */ | 
|  | bool setRegion(const SkRegion&); | 
|  |  | 
|  | /** | 
|  | *  Set this region to the area described by the path, clipped. | 
|  | *  Return true if the resulting region is non-empty. | 
|  | *  This produces a region that is identical to the pixels that would be | 
|  | *  drawn by the path (with no antialiasing) with the specified clip. | 
|  | */ | 
|  | bool setPath(const SkPath&, const SkRegion& clip); | 
|  |  | 
|  | /** | 
|  | *  Returns true if the specified rectangle has a non-empty intersection | 
|  | *  with this region. | 
|  | */ | 
|  | bool intersects(const SkIRect&) const; | 
|  |  | 
|  | /** | 
|  | *  Returns true if the specified region has a non-empty intersection | 
|  | *  with this region. | 
|  | */ | 
|  | bool intersects(const SkRegion&) const; | 
|  |  | 
|  | /** | 
|  | *  Return true if the specified x,y coordinate is inside the region. | 
|  | */ | 
|  | bool contains(int32_t x, int32_t y) const; | 
|  |  | 
|  | /** | 
|  | *  Return true if the specified rectangle is completely inside the region. | 
|  | *  This works for simple (rectangular) and complex regions, and always | 
|  | *  returns the correct result. Note: if either this region or the rectangle | 
|  | *  is empty, contains() returns false. | 
|  | */ | 
|  | bool contains(const SkIRect&) const; | 
|  |  | 
|  | /** | 
|  | *  Return true if the specified region is completely inside the region. | 
|  | *  This works for simple (rectangular) and complex regions, and always | 
|  | *  returns the correct result. Note: if either region is empty, contains() | 
|  | *  returns false. | 
|  | */ | 
|  | bool contains(const SkRegion&) const; | 
|  |  | 
|  | /** | 
|  | *  Return true if this region is a single rectangle (not complex) and the | 
|  | *  specified rectangle is contained by this region. Returning false is not | 
|  | *  a guarantee that the rectangle is not contained by this region, but | 
|  | *  return true is a guarantee that the rectangle is contained by this region. | 
|  | */ | 
|  | bool quickContains(const SkIRect& r) const { | 
|  | return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *  Return true if this region is a single rectangle (not complex) and the | 
|  | *  specified rectangle is contained by this region. Returning false is not | 
|  | *  a guarantee that the rectangle is not contained by this region, but | 
|  | *  return true is a guarantee that the rectangle is contained by this | 
|  | *  region. | 
|  | */ | 
|  | bool quickContains(int32_t left, int32_t top, int32_t right, | 
|  | int32_t bottom) const { | 
|  | SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region | 
|  |  | 
|  | return left < right && top < bottom && | 
|  | fRunHead == SkRegion_gRectRunHeadPtr &&  // this->isRect() | 
|  | /* fBounds.contains(left, top, right, bottom); */ | 
|  | fBounds.fLeft <= left && fBounds.fTop <= top && | 
|  | fBounds.fRight >= right && fBounds.fBottom >= bottom; | 
|  | } | 
|  |  | 
|  | /** | 
|  | *  Return true if this region is empty, or if the specified rectangle does | 
|  | *  not intersect the region. Returning false is not a guarantee that they | 
|  | *  intersect, but returning true is a guarantee that they do not. | 
|  | */ | 
|  | bool quickReject(const SkIRect& rect) const { | 
|  | return this->isEmpty() || rect.isEmpty() || | 
|  | !SkIRect::Intersects(fBounds, rect); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *  Return true if this region, or rgn, is empty, or if their bounds do not | 
|  | *  intersect. Returning false is not a guarantee that they intersect, but | 
|  | *  returning true is a guarantee that they do not. | 
|  | */ | 
|  | bool quickReject(const SkRegion& rgn) const { | 
|  | return this->isEmpty() || rgn.isEmpty() || | 
|  | !SkIRect::Intersects(fBounds, rgn.fBounds); | 
|  | } | 
|  |  | 
|  | /** Translate the region by the specified (dx, dy) amount. */ | 
|  | void translate(int dx, int dy) { this->translate(dx, dy, this); } | 
|  |  | 
|  | /** | 
|  | *  Translate the region by the specified (dx, dy) amount, writing the | 
|  | *  resulting region into dst. Note: it is legal to pass this region as the | 
|  | *  dst parameter, effectively translating the region in place. If dst is | 
|  | *  null, nothing happens. | 
|  | */ | 
|  | void translate(int dx, int dy, SkRegion* dst) const; | 
|  |  | 
|  | /** | 
|  | *  The logical operations that can be performed when combining two regions. | 
|  | */ | 
|  | enum Op { | 
|  | kDifference_Op, //!< subtract the op region from the first region | 
|  | kIntersect_Op,  //!< intersect the two regions | 
|  | kUnion_Op,      //!< union (inclusive-or) the two regions | 
|  | kXOR_Op,        //!< exclusive-or the two regions | 
|  | /** subtract the first region from the op region */ | 
|  | kReverseDifference_Op, | 
|  | kReplace_Op,    //!< replace the dst region with the op region | 
|  |  | 
|  | kLastOp = kReplace_Op | 
|  | }; | 
|  |  | 
|  | static const int kOpCnt = kLastOp + 1; | 
|  |  | 
|  | /** | 
|  | *  Set this region to the result of applying the Op to this region and the | 
|  | *  specified rectangle: this = (this op rect). | 
|  | *  Return true if the resulting region is non-empty. | 
|  | */ | 
|  | bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } | 
|  |  | 
|  | /** | 
|  | *  Set this region to the result of applying the Op to this region and the | 
|  | *  specified rectangle: this = (this op rect). | 
|  | *  Return true if the resulting region is non-empty. | 
|  | */ | 
|  | bool op(int left, int top, int right, int bottom, Op op) { | 
|  | SkIRect rect; | 
|  | rect.set(left, top, right, bottom); | 
|  | return this->op(*this, rect, op); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *  Set this region to the result of applying the Op to this region and the | 
|  | *  specified region: this = (this op rgn). | 
|  | *  Return true if the resulting region is non-empty. | 
|  | */ | 
|  | bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } | 
|  |  | 
|  | /** | 
|  | *  Set this region to the result of applying the Op to the specified | 
|  | *  rectangle and region: this = (rect op rgn). | 
|  | *  Return true if the resulting region is non-empty. | 
|  | */ | 
|  | bool op(const SkIRect& rect, const SkRegion& rgn, Op); | 
|  |  | 
|  | /** | 
|  | *  Set this region to the result of applying the Op to the specified | 
|  | *  region and rectangle: this = (rgn op rect). | 
|  | *  Return true if the resulting region is non-empty. | 
|  | */ | 
|  | bool op(const SkRegion& rgn, const SkIRect& rect, Op); | 
|  |  | 
|  | /** | 
|  | *  Set this region to the result of applying the Op to the specified | 
|  | *  regions: this = (rgna op rgnb). | 
|  | *  Return true if the resulting region is non-empty. | 
|  | */ | 
|  | bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); | 
|  |  | 
|  | #ifdef SK_BUILD_FOR_ANDROID | 
|  | /** Returns a new char* containing the list of rectangles in this region | 
|  | */ | 
|  | char* toString(); | 
|  | #endif | 
|  |  | 
|  | /** | 
|  | *  Returns the sequence of rectangles, sorted in Y and X, that make up | 
|  | *  this region. | 
|  | */ | 
|  | class SK_API Iterator { | 
|  | public: | 
|  | Iterator() : fRgn(NULL), fDone(true) {} | 
|  | Iterator(const SkRegion&); | 
|  | // if we have a region, reset to it and return true, else return false | 
|  | bool rewind(); | 
|  | // reset the iterator, using the new region | 
|  | void reset(const SkRegion&); | 
|  | bool done() const { return fDone; } | 
|  | void next(); | 
|  | const SkIRect& rect() const { return fRect; } | 
|  | // may return null | 
|  | const SkRegion* rgn() const { return fRgn; } | 
|  |  | 
|  | private: | 
|  | const SkRegion* fRgn; | 
|  | const RunType*  fRuns; | 
|  | SkIRect         fRect; | 
|  | bool            fDone; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | *  Returns the sequence of rectangles, sorted in Y and X, that make up | 
|  | *  this region intersected with the specified clip rectangle. | 
|  | */ | 
|  | class SK_API Cliperator { | 
|  | public: | 
|  | Cliperator(const SkRegion&, const SkIRect& clip); | 
|  | bool done() { return fDone; } | 
|  | void  next(); | 
|  | const SkIRect& rect() const { return fRect; } | 
|  |  | 
|  | private: | 
|  | Iterator    fIter; | 
|  | SkIRect     fClip; | 
|  | SkIRect     fRect; | 
|  | bool        fDone; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | *  Returns the sequence of runs that make up this region for the specified | 
|  | *  Y scanline, clipped to the specified left and right X values. | 
|  | */ | 
|  | class Spanerator { | 
|  | public: | 
|  | Spanerator(const SkRegion&, int y, int left, int right); | 
|  | bool next(int* left, int* right); | 
|  |  | 
|  | private: | 
|  | const SkRegion::RunType* fRuns; | 
|  | int     fLeft, fRight; | 
|  | bool    fDone; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | *  Write the region to the buffer, and return the number of bytes written. | 
|  | *  If buffer is NULL, it still returns the number of bytes. | 
|  | */ | 
|  | size_t writeToMemory(void* buffer) const; | 
|  | /** | 
|  | * Initializes the region from the buffer | 
|  | * | 
|  | * @param buffer Memory to read from | 
|  | * @param length Amount of memory available in the buffer | 
|  | * @return number of bytes read (must be a multiple of 4) or | 
|  | *         0 if there was not enough memory available | 
|  | */ | 
|  | size_t readFromMemory(const void* buffer, size_t length); | 
|  |  | 
|  | /** | 
|  | *  Returns a reference to a global empty region. Just a convenience for | 
|  | *  callers that need a const empty region. | 
|  | */ | 
|  | static const SkRegion& GetEmptyRegion(); | 
|  |  | 
|  | SkDEBUGCODE(void dump() const;) | 
|  | SkDEBUGCODE(void validate() const;) | 
|  | SkDEBUGCODE(static void UnitTest();) | 
|  |  | 
|  | // expose this to allow for regression test on complex regions | 
|  | SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) | 
|  |  | 
|  | private: | 
|  | enum { | 
|  | kOpCount = kReplace_Op + 1 | 
|  | }; | 
|  |  | 
|  | enum { | 
|  | // T | 
|  | // [B N L R S] | 
|  | // S | 
|  | kRectRegionRuns = 7 | 
|  | }; | 
|  |  | 
|  | friend class android::Region;    // needed for marshalling efficiently | 
|  |  | 
|  | struct RunHead; | 
|  |  | 
|  | // allocate space for count runs | 
|  | void allocateRuns(int count); | 
|  | void allocateRuns(int count, int ySpanCount, int intervalCount); | 
|  | void allocateRuns(const RunHead& src); | 
|  |  | 
|  | SkIRect     fBounds; | 
|  | RunHead*    fRunHead; | 
|  |  | 
|  | void freeRuns(); | 
|  |  | 
|  | /** | 
|  | *  Return the runs from this region, consing up fake runs if the region | 
|  | *  is empty or a rect. In those 2 cases, we use tmpStorage to hold the | 
|  | *  run data. | 
|  | */ | 
|  | const RunType*  getRuns(RunType tmpStorage[], int* intervals) const; | 
|  |  | 
|  | // This is called with runs[] that do not yet have their interval-count | 
|  | // field set on each scanline. That is computed as part of this call | 
|  | // (inside ComputeRunBounds). | 
|  | bool setRuns(RunType runs[], int count); | 
|  |  | 
|  | int count_runtype_values(int* itop, int* ibot) const; | 
|  |  | 
|  | static void BuildRectRuns(const SkIRect& bounds, | 
|  | RunType runs[kRectRegionRuns]); | 
|  |  | 
|  | // If the runs define a simple rect, return true and set bounds to that | 
|  | // rect. If not, return false and ignore bounds. | 
|  | static bool RunsAreARect(const SkRegion::RunType runs[], int count, | 
|  | SkIRect* bounds); | 
|  |  | 
|  | /** | 
|  | *  If the last arg is null, just return if the result is non-empty, | 
|  | *  else store the result in the last arg. | 
|  | */ | 
|  | static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); | 
|  |  | 
|  | friend struct RunHead; | 
|  | friend class Iterator; | 
|  | friend class Spanerator; | 
|  | friend class SkRgnBuilder; | 
|  | friend class SkFlatRegion; | 
|  | }; | 
|  |  | 
|  | #endif |