* 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 "include/core/SkRect.h"
class SkPath;
class SkRgnBuilder;
SkRegion describes the set of pixels used to clip SkCanvas. SkRegion is compact,
efficiently storing a single integer rectangle, or a run length encoded array
of rectangles. SkRegion may reduce the current SkCanvas clip, or may be drawn as
one or more integer rectangles. SkRegion iterator returns the scan lines or
rectangles contained by it, optionally intersecting a bounding rectangle.
*/
class SK_API SkRegion {
typedef int32_t RunType;
public:
at (0, 0) with zero width and height.
@return empty SkRegion
*/
SkRegion();
Copy constructor makes two regions identical by value. Internally, region and
the returned result share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param region SkRegion to copy by value
@return copy of SkRegion
*/
SkRegion(const SkRegion& region);
@param rect bounds of constructed SkRegion
@return rectangular SkRegion
*/
explicit SkRegion(const SkIRect& rect);
*/
~SkRegion();
Makes two regions identical by value. Internally, region and
the returned result share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param region SkRegion to copy by value
@return SkRegion to copy by value
*/
SkRegion& operator=(const SkRegion& region);
the same area.
@param other SkRegion to compare
@return true if SkRegion pair are equivalent
*/
bool operator==(const SkRegion& other) const;
@param other SkRegion to compare
@return true if SkRegion pair are not equivalent
*/
bool operator!=(const SkRegion& other) const {
return !(*this == other);
}
This makes SkRegion and src identical by value. Internally,
SkRegion and src share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param src SkRegion to copy
@return copy of src
*/
bool set(const SkRegion& src) {
*this = src;
return !this->isEmpty();
}
so it is lightweight and does not allocate memory.
swap() usage has largely been replaced by operator=(const SkRegion& region).
SkPath do not copy their content on assignment until they are written to,
making assignment as efficient as swap().
@param other operator=(const SkRegion& region) set
*/
void swap(SkRegion& other);
Empty SkRegion has bounds width or height less than or equal to zero.
SkRegion() constructs empty SkRegion; setEmpty()
and setRect() with dimensionless data make SkRegion empty.
@return true if bounds has no width or height
*/
bool isEmpty() const { return fRunHead == emptyRunHeadPtr(); }
@return true if SkRegion contains one SkIRect
*/
bool isRect() const { return fRunHead == kRectRunHeadPtr; }
@return true if SkRegion contains more than one SkIRect
*/
bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
Returns (0, 0, 0, 0) if SkRegion is empty.
@return combined bounds of all SkIRect elements
*/
const SkIRect& getBounds() const { return fBounds; }
elements in SkRegion. Returns zero if SkRegion is empty.
Returns one if SkRegion equals SkIRect; otherwise, returns
value greater than one indicating that SkRegion is complex.
Call to compare SkRegion for relative complexity.
@return relative complexity
*/
int computeRegionComplexity() const;
Returns true if SkRegion is not empty; otherwise, returns false, and leaves path
unmodified.
@param path SkPath to append to
@return true if path changed
*/
bool getBoundaryPath(SkPath* path) const;
at (0, 0) with zero width and height. Always returns false.
@return false
*/
bool setEmpty();
If rect is empty, constructs empty and returns false.
@param rect bounds of constructed SkRegion
@return true if rect is not empty
*/
bool setRect(const SkIRect& rect);
Returns true if left is less than right and top is less than bottom; otherwise,
constructs empty SkRegion and returns false.
@param left edge of bounds on x-axis
@param top edge of bounds on y-axis
@param right edge of bounds on x-axis
@param bottom edge of bounds on y-axis
@return rectangular SkRegion
*/
bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
return this->setRect({ left, top, right, bottom });
}
zero, constructs empty SkRegion. Returns false if constructed SkRegion is empty.
May be faster than repeated calls to op().
@param rects array of SkIRect
@param count array size
@return true if constructed SkRegion is not empty
*/
bool setRects(const SkIRect rects[], int count);
Makes two regions identical by value. Internally, region and
the returned result share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param region SkRegion to copy by value
@return SkRegion to copy by value
*/
bool setRegion(const SkRegion& region);
Returns false if constructed SkRegion is empty.
Constructed SkRegion draws the same pixels as path through clip when
anti-aliasing is disabled.
@param path SkPath providing outline
@param clip SkRegion containing path
@return true if constructed SkRegion is not empty
*/
bool setPath(const SkPath& path, const SkRegion& clip);
Returns false if either rect or SkRegion is empty, or do not intersect.
@param rect SkIRect to intersect
@return true if rect and SkRegion have area in common
*/
bool intersects(const SkIRect& rect) const;
Returns false if either other or SkRegion is empty, or do not intersect.
@param other SkRegion to intersect
@return true if other and SkRegion have area in common
*/
bool intersects(const SkRegion& other) const;
Returns false if SkRegion is empty.
@param x test SkIPoint x-coordinate
@param y test SkIPoint y-coordinate
@return true if (x, y) is inside SkRegion
*/
bool contains(int32_t x, int32_t y) const;
Returns false if SkRegion or other is empty.
@param other SkIRect to contain
@return true if other is inside SkRegion
*/
bool contains(const SkIRect& other) const;
Returns false if SkRegion or other is empty.
@param other SkRegion to contain
@return true if other is inside SkRegion
*/
bool contains(const SkRegion& other) const;
May return false even though SkRegion contains r.
@param r SkIRect to contain
@return true quickly if r points are equal or inside
*/
bool quickContains(const SkIRect& r) const {
return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
}
(left, top, right, bottom).
Returns false if SkRegion is empty or SkIRect (left, top, right, bottom) is empty.
May return false even though SkRegion contains (left, top, right, bottom).
@param left edge of bounds on x-axis
@param top edge of bounds on y-axis
@param right edge of bounds on x-axis
@param bottom edge of bounds on y-axis
@return true quickly if SkIRect are equal or inside
*/
bool quickContains(int32_t left, int32_t top, int32_t right,
int32_t bottom) const {
SkASSERT(this->isEmpty() == fBounds.isEmpty());
return left < right && top < bottom &&
fRunHead == kRectRunHeadPtr &&
fBounds.fLeft <= left && fBounds.fTop <= top &&
fBounds.fRight >= right && fBounds.fBottom >= bottom;
}
Returns true if rect is empty or SkRegion is empty.
May return false even though SkRegion does not intersect rect.
@param rect SkIRect to intersect
@return true if rect does not intersect
*/
bool quickReject(const SkIRect& rect) const {
return this->isEmpty() || rect.isEmpty() ||
!SkIRect::Intersects(fBounds, rect);
}
Returns true if rgn is empty or SkRegion is empty.
May return false even though SkRegion does not intersect rgn.
@param rgn SkRegion to intersect
@return true if rgn does not intersect
*/
bool quickReject(const SkRegion& rgn) const {
return this->isEmpty() || rgn.isEmpty() ||
!SkIRect::Intersects(fBounds, rgn.fBounds);
}
@param dx x-axis offset
@param dy y-axis offset
*/
void translate(int dx, int dy) { this->translate(dx, dy, this); }
as dst parameter, translating SkRegion in place. Has no effect if dst is nullptr.
If SkRegion is empty, sets dst to empty.
@param dx x-axis offset
@param dy y-axis offset
@param dst translated result
*/
void translate(int dx, int dy, SkRegion* dst) const;
The logical operations that can be performed when combining two SkRegion.
*/
enum Op {
kDifference_Op,
kIntersect_Op,
kUnion_Op,
kXOR_Op,
kReverseDifference_Op,
kReplace_Op,
kLastOp = kReplace_Op,
};
static const int kOpCnt = kLastOp + 1;
Returns true if replaced SkRegion is not empty.
@param rect SkIRect operand
@param op operator, one of:
kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op,
kReplace_Op
@return false if result is empty
*/
bool op(const SkIRect& rect, Op op) {
if (this->isRect() && kIntersect_Op == op) {
if (!fBounds.intersect(rect)) {
return this->setEmpty();
}
return true;
}
return this->op(*this, rect, op);
}
Returns true if replaced SkRegion is not empty.
@param left edge of bounds on x-axis
@param top edge of bounds on y-axis
@param right edge of bounds on x-axis
@param bottom edge of bounds on y-axis
@param op operator, one of:
kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op,
kReplace_Op
@return false if result is 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);
}
Returns true if replaced SkRegion is not empty.
@param rgn SkRegion operand
@param op operator, one of:
kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op,
kReplace_Op
@return false if result is empty
*/
bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
Returns true if replaced SkRegion is not empty.
@param rect SkIRect operand
@param rgn SkRegion operand
@param op operator, one of:
kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op,
kReplace_Op
@return false if result is empty
*/
bool op(const SkIRect& rect, const SkRegion& rgn, Op op);
Returns true if replaced SkRegion is not empty.
@param rgn SkRegion operand
@param rect SkIRect operand
@param op operator, one of:
kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op,
kReplace_Op
@return false if result is empty
*/
bool op(const SkRegion& rgn, const SkIRect& rect, Op op);
Returns true if replaced SkRegion is not empty.
@param rgna SkRegion operand
@param rgnb SkRegion operand
@param op operator, one of:
kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op,
kReplace_Op
@return false if result is empty
*/
bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
@return string representation of SkRegion
*/
char* toString();
#endif
Returns sequence of rectangles, sorted along y-axis, then x-axis, that make
up SkRegion.
*/
class SK_API Iterator {
public:
returns true.
Call reset() to initialized SkRegion::Iterator at a later time.
@return empty SkRegion iterator
*/
Iterator() : fRgn(nullptr), fDone(true) {}
@param region SkRegion to iterate
@return SkRegion iterator
*/
Iterator(const SkRegion& region);
Returns true if SkRegion was set; otherwise, returns false.
@return true if SkRegion was set
*/
bool rewind();
@param region SkRegion to iterate
*/
void reset(const SkRegion& region);
@return true if data parsing is complete
*/
bool done() const { return fDone; }
*/
void next();
is empty.
@return part of SkRegion as SkIRect
*/
const SkIRect& rect() const { return fRect; }
@return iterated SkRegion
*/
const SkRegion* rgn() const { return fRgn; }
private:
const SkRegion* fRgn;
const SkRegion::RunType* fRuns;
SkIRect fRect = {0, 0, 0, 0};
bool fDone;
};
Returns the sequence of rectangles, sorted along y-axis, then x-axis, that make
up SkRegion intersected with the specified clip rectangle.
*/
class SK_API Cliperator {
public:
@param region SkRegion to iterate
@param clip bounds of iteration
@return SkRegion iterator
*/
Cliperator(const SkRegion& region, const SkIRect& clip);
@return true if data parsing is complete
*/
bool done() { return fDone; }
*/
void next();
SkRegion::Cliperator constructor. Does not return predictable results if SkRegion
is empty.
@return part of SkRegion inside clip as SkIRect
*/
const SkIRect& rect() const { return fRect; }
private:
Iterator fIter;
SkIRect fClip;
SkIRect fRect = {0, 0, 0, 0};
bool fDone;
};
Returns the line segment ends within SkRegion that intersect a horizontal line.
*/
class Spanerator {
public:
@param region SkRegion to iterate
@param y horizontal line to intersect
@param left bounds of iteration
@param right bounds of iteration
@return SkRegion iterator
*/
Spanerator(const SkRegion& region, int y, int left, int right);
in constructor. Returns true if interval was found.
@param left pointer to span start; may be nullptr
@param right pointer to span end; may be nullptr
@return true if interval was found
*/
bool next(int* left, int* right);
private:
const SkRegion::RunType* fRuns;
int fLeft, fRight;
bool fDone;
};
If buffer is nullptr, returns number number of bytes that would be written.
@param buffer storage for binary data
@return size of SkRegion
*/
size_t writeToMemory(void* buffer) const;
Returned value will be multiple of four or zero if length was too small.
@param buffer storage for binary data
@param length size of buffer
@return bytes read
*/
size_t readFromMemory(const void* buffer, size_t length);
private:
static constexpr int kOpCount = kReplace_Op + 1;
static constexpr int kRectRegionRuns = 7;
struct RunHead;
static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; }
static constexpr RunHead* kRectRunHeadPtr = nullptr;
void allocateRuns(int count);
void allocateRuns(int count, int ySpanCount, int intervalCount);
void allocateRuns(const RunHead& src);
SkDEBUGCODE(void dump() const;)
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;
bool setRuns(RunType runs[], int count);
int count_runtype_values(int* itop, int* ibot) const;
bool isValid() const;
static void BuildRectRuns(const SkIRect& bounds,
RunType runs[kRectRegionRuns]);
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 SkRegionPriv;
friend class SkRgnBuilder;
friend class SkFlatRegion;
};
#endif