123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- /*
- * 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;
- /** \class SkRegion
- 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:
- /** Constructs an empty SkRegion. SkRegion is set to empty bounds
- at (0, 0) with zero width and height.
- @return empty SkRegion
- */
- SkRegion();
- /** Constructs a copy of an existing region.
- 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);
- /** Constructs a rectangular SkRegion matching the bounds of rect.
- @param rect bounds of constructed SkRegion
- @return rectangular SkRegion
- */
- explicit SkRegion(const SkIRect& rect);
- /** Releases ownership of any shared data and deletes data if SkRegion is sole owner.
- */
- ~SkRegion();
- /** Constructs a copy of an existing region.
- 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);
- /** Compares SkRegion and other; returns true if they enclose exactly
- the same area.
- @param other SkRegion to compare
- @return true if SkRegion pair are equivalent
- */
- bool operator==(const SkRegion& other) const;
- /** Compares SkRegion and other; returns true if they do not enclose the same area.
- @param other SkRegion to compare
- @return true if SkRegion pair are not equivalent
- */
- bool operator!=(const SkRegion& other) const {
- return !(*this == other);
- }
- /** Sets SkRegion to src, and returns true if src bounds is not empty.
- 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();
- }
- /** Exchanges SkIRect array of SkRegion and other. swap() internally exchanges pointers,
- 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);
- /** Returns true if SkRegion is empty.
- 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(); }
- /** Returns true if SkRegion is one SkIRect with positive dimensions.
- @return true if SkRegion contains one SkIRect
- */
- bool isRect() const { return fRunHead == kRectRunHeadPtr; }
- /** Returns true if SkRegion is described by more than one rectangle.
- @return true if SkRegion contains more than one SkIRect
- */
- bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
- /** Returns minimum and maximum axes values of SkIRect array.
- Returns (0, 0, 0, 0) if SkRegion is empty.
- @return combined bounds of all SkIRect elements
- */
- const SkIRect& getBounds() const { return fBounds; }
- /** Returns a value that increases with the number of
- 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;
- /** Appends outline of SkRegion to path.
- 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;
- /** Constructs an empty SkRegion. SkRegion is set to empty bounds
- at (0, 0) with zero width and height. Always returns false.
- @return false
- */
- bool setEmpty();
- /** Constructs a rectangular SkRegion matching the bounds of rect.
- 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);
- /** Constructs SkRegion with bounds (left, top, right, bottom).
- 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 });
- }
- /** Constructs SkRegion as the union of SkIRect in rects array. If count is
- 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);
- /** Constructs a copy of an existing region.
- 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);
- /** Constructs SkRegion to match outline of path within clip.
- 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 true if SkRegion intersects rect.
- 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 true if SkRegion intersects other.
- 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 true if SkIPoint (x, y) is inside SkRegion.
- 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 true if other is completely inside SkRegion.
- 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 true if other is completely inside SkRegion.
- 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;
- /** Returns true if SkRegion is a single rectangle and contains r.
- 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);
- }
- /** Returns true if SkRegion is a single rectangle and contains SkIRect
- (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()); // valid region
- return left < right && top < bottom &&
- fRunHead == kRectRunHeadPtr && // this->isRect()
- /* fBounds.contains(left, top, right, bottom); */
- fBounds.fLeft <= left && fBounds.fTop <= top &&
- fBounds.fRight >= right && fBounds.fBottom >= bottom;
- }
- /** Returns true if SkRegion does not intersect rect.
- 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 SkRegion does not intersect rgn.
- 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);
- }
- /** Offsets SkRegion by ivector (dx, dy). Has no effect if SkRegion is empty.
- @param dx x-axis offset
- @param dy y-axis offset
- */
- void translate(int dx, int dy) { this->translate(dx, dy, this); }
- /** Offsets SkRegion by ivector (dx, dy), writing result to dst. SkRegion may be passed
- 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;
- /** \enum SkRegion::Op
- The logical operations that can be performed when combining two SkRegion.
- */
- enum Op {
- kDifference_Op, //!< target minus operand
- kIntersect_Op, //!< target intersected with operand
- kUnion_Op, //!< target unioned with operand
- kXOR_Op, //!< target exclusive or with operand
- kReverseDifference_Op, //!< operand minus target
- kReplace_Op, //!< replace target with operand
- kLastOp = kReplace_Op, //!< last operator
- };
- static const int kOpCnt = kLastOp + 1;
- /** Replaces SkRegion with the result of SkRegion op rect.
- 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);
- }
- /** Replaces SkRegion with the result of SkRegion op SkIRect (left, top, right, bottom).
- 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);
- }
- /** Replaces SkRegion with the result of SkRegion op rgn.
- 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); }
- /** Replaces SkRegion with the result of rect op rgn.
- 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);
- /** Replaces SkRegion with the result of rgn op rect.
- 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);
- /** Replaces SkRegion with the result of rgna op rgnb.
- 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
- /** Private. Android framework only.
- @return string representation of SkRegion
- */
- char* toString();
- #endif
- /** \class SkRegion::Iterator
- Returns sequence of rectangles, sorted along y-axis, then x-axis, that make
- up SkRegion.
- */
- class SK_API Iterator {
- public:
- /** Initializes SkRegion::Iterator with an empty SkRegion. done() on SkRegion::Iterator
- returns true.
- Call reset() to initialized SkRegion::Iterator at a later time.
- @return empty SkRegion iterator
- */
- Iterator() : fRgn(nullptr), fDone(true) {}
- /** Sets SkRegion::Iterator to return elements of SkIRect array in region.
- @param region SkRegion to iterate
- @return SkRegion iterator
- */
- Iterator(const SkRegion& region);
- /** SkPoint SkRegion::Iterator to start of SkRegion.
- Returns true if SkRegion was set; otherwise, returns false.
- @return true if SkRegion was set
- */
- bool rewind();
- /** Resets iterator, using the new SkRegion.
- @param region SkRegion to iterate
- */
- void reset(const SkRegion& region);
- /** Returns true if SkRegion::Iterator is pointing to final SkIRect in SkRegion.
- @return true if data parsing is complete
- */
- bool done() const { return fDone; }
- /** Advances SkRegion::Iterator to next SkIRect in SkRegion if it is not done.
- */
- void next();
- /** Returns SkIRect element in SkRegion. Does not return predictable results if SkRegion
- is empty.
- @return part of SkRegion as SkIRect
- */
- const SkIRect& rect() const { return fRect; }
- /** Returns SkRegion if set; otherwise, returns nullptr.
- @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;
- };
- /** \class SkRegion::Cliperator
- 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:
- /** Sets SkRegion::Cliperator to return elements of SkIRect array in SkRegion within clip.
- @param region SkRegion to iterate
- @param clip bounds of iteration
- @return SkRegion iterator
- */
- Cliperator(const SkRegion& region, const SkIRect& clip);
- /** Returns true if SkRegion::Cliperator is pointing to final SkIRect in SkRegion.
- @return true if data parsing is complete
- */
- bool done() { return fDone; }
- /** Advances iterator to next SkIRect in SkRegion contained by clip.
- */
- void next();
- /** Returns SkIRect element in SkRegion, intersected with clip passed to
- 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;
- };
- /** \class SkRegion::Spanerator
- Returns the line segment ends within SkRegion that intersect a horizontal line.
- */
- class Spanerator {
- public:
- /** Sets SkRegion::Spanerator to return line segments in SkRegion on scan line.
- @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);
- /** Advances iterator to next span intersecting SkRegion within line segment provided
- 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;
- };
- /** Writes SkRegion to buffer, and returns number of bytes written.
- 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;
- /** Constructs SkRegion from buffer of size length. Returns bytes read.
- 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;
- // T
- // [B N L R S]
- // S
- static constexpr int kRectRegionRuns = 7;
- struct RunHead;
- static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; }
- static constexpr RunHead* kRectRunHeadPtr = nullptr;
- // allocate space for count runs
- 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;
- // 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;
- bool isValid() 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 SkRegionPriv;
- friend class SkRgnBuilder;
- friend class SkFlatRegion;
- };
- #endif
|