blob: f61090ca8d551cc76cda182ad2cb7c5542628cdf [file] [log] [blame]
/* include/corecg/SkRegion.h
**
** Copyright 2006, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#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 SkRegion {
public:
typedef int16_t RunType;
SkRegion();
explicit SkRegion(const SkRegion&);
explicit SkRegion(const SkRect16&);
~SkRegion();
SkRegion& operator=(const SkRegion&);
friend int operator==(const SkRegion& a, const SkRegion& b);
friend int operator!=(const SkRegion& a, const SkRegion& b)
{
return !(a == b);
}
// provide explicitly, so we'll have a java equivalent
void set(const SkRegion& src)
{
SkASSERT(&src);
*this = src;
}
/** 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 SkRect16& getBounds() const { return fBounds; }
/** Returns true if the region is non-empty, and if so, sets the specified path to the
boundary(s) of the region.
*/
bool getBoundaryPath(SkPath* path) const;
/** Set the region to be empty, and return false */
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 SkRect16&);
/** 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(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom);
/** 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, optionally clipped (if clip is
not nil). 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).
*/
bool setPath(const SkPath&, const SkRegion* clip = nil);
/** Return true if the specified x,y coordinate is inside the region.
*/
bool contains(S16CPU x, S16CPU y) 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 SkRect16& r) const
{
return this->isRect() && fBounds.contains(r);
}
/** 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(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom) const
{
return this->isRect() && fBounds.contains(left, top, right, 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 SkRect16& rect) const
{
return this->isEmpty() || !SkRect16::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() || !SkRect16::Intersects(fBounds, rgn.fBounds);
}
void translate(int dx, int dy)
{
this->translate(dx, dy, this);
}
void translate(int dx, int dy, SkRegion* dst) const;
enum Op {
kDifference_Op,
kIntersect_Op,
kUnion_Op,
kXOR_Op,
kOpCount
};
/** Set this region to the result of applying the Opereation to this region and the specified
rectangle. Return true if the resulting region is non-empty.
*/
bool op(const SkRect16&, Op);
// helper for java, so it doesn't have to create a Rect object
bool op(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom, Op op)
{
SkRect16 r;
r.set(left, top, right, bottom);
return this->op(r, op);
}
/** Set this region to the result of applying the Opereation to this region and the specified
region. 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 Opereation to the specified rectangle and region.
Return true if the resulting region is non-empty.
*/
bool op(const SkRect16&, const SkRegion&, Op);
/** Set this region to the result of applying the Opereation to the specified regions.
Return true if the resulting region is non-empty.
*/
bool op(const SkRegion&, const SkRegion&, Op);
/** Helper class that returns the sequence of rectangles that make up this region.
*/
class Iterator {
public:
Iterator();
Iterator(const SkRegion&);
void reset(const SkRegion&);
bool done() { return fDone; }
void next();
const SkRect16& rect() const { return fRect; }
private:
const RunType* fRuns;
SkRect16 fRect;
bool fDone;
};
/** Helper class that returns the sequence of rectangles that make up this region,
intersected with the clip rectangle.
*/
class Cliperator {
public:
Cliperator(const SkRegion&, const SkRect16& clip);
bool done() { return fDone; }
void next();
const SkRect16& rect() const { return fRect; }
private:
Iterator fIter;
SkRect16 fClip;
SkRect16 fRect;
bool fDone;
};
/** Helper class that returns the sequence of scanline runs that make up this region.
*/
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;
};
/** Return the number of bytes need to write this region to a buffer.
*/
size_t computeBufferSize() const;
/** Write the region to the buffer, and return the number of bytes written.
*/
size_t writeToBuffer(void* buffer) const;
/** Initialized the region from the buffer, returning the number
of bytes actually read.
*/
size_t readFromBuffer(const void* buffer);
SkDEBUGCODE(void dump() const;)
SkDEBUGCODE(void validate() const;)
SkDEBUGCODE(static void UnitTest();)
private:
enum {
kRectRegionRuns = 6, // need to store a region of a rect [T B L R S S]
kRunTypeSentinel = 0x7FFF
};
friend class android::Region; // needed for marshalling efficiently
void allocateRuns(int count); // allocate space for count runs
struct RunHead;
SkRect16 fBounds;
RunHead* fRunHead;
void freeRuns();
const RunType* getRuns(RunType tmpStorage[], int* count) const;
bool setRuns(RunType runs[], int count);
int count_runtype_values(int* itop, int* ibot) const;
static void build_rect_runs(const SkRect16& bounds, RunType runs[kRectRegionRuns]);
static bool compute_run_bounds(const RunType runs[], int count, SkRect16* bounds);
friend struct RunHead;
friend class Iterator;
friend class Spanerator;
friend class SkRgnBuilder;
};
#endif