diff options
Diffstat (limited to 'include/core/SkRRect.h')
-rw-r--r-- | include/core/SkRRect.h | 487 |
1 files changed, 339 insertions, 148 deletions
diff --git a/include/core/SkRRect.h b/include/core/SkRRect.h index dae5a0cdde..140e1dac2c 100644 --- a/include/core/SkRRect.h +++ b/include/core/SkRRect.h @@ -5,6 +5,16 @@ * found in the LICENSE file. */ +/* Generated by tools/bookmaker from include/core/SkRRect.h and docs/SkRRect_Reference.bmh + on 2018-07-13 08:15:10. Additional documentation and examples can be found at: + https://skia.org/user/api/SkRRect_Reference + + You may edit either file directly. Structural changes to public interfaces require + editing both files. After editing docs/SkRRect_Reference.bmh, run: + bookmaker -b docs -i include/core/SkRRect.h -p + to create an updated version of this file. + */ + #ifndef SkRRect_DEFINED #define SkRRect_DEFINED @@ -14,89 +24,77 @@ class SkPath; class SkMatrix; -// Path forward: -// core work -// add contains(SkRect&) - for clip stack -// add contains(SkRRect&) - for clip stack -// add heart rect computation (max rect inside RR) -// add 9patch rect computation -// add growToInclude(SkPath&) -// analysis -// use growToInclude to fit skp round rects & generate stats (RRs vs. real paths) -// check on # of rectorus's the RRs could handle -// rendering work -// update SkPath.addRRect() to only use quads -// add GM and bench -// further out -// detect and triangulate RRectorii rather than falling back to SW in Ganesh -// - /** \class SkRRect + SkRRect describes a rounded rectangle with a bounds and a pair of radii for each corner. + The bounds and radii can be set so that SkRRect describes a rectangle with sharp corners, + a circle, an oval, or a rectangle with one or more rounded corners. - The SkRRect class represents a rounded rect with a potentially different - radii for each corner. It does not have a constructor so must be - initialized with one of the initialization functions (e.g., setEmpty, - setRectRadii, etc.) + SkRRect allows implementing CSS properties that describe rounded corners. + SkRRect may have up to eight different radii, one for each axis on each of its four + corners. - This class is intended to roughly match CSS' border-*-*-radius capabilities. - This means: - If either of a corner's radii are 0 the corner will be square. - Negative radii are not allowed (they are clamped to zero). - If the corner curves overlap they will be proportionally reduced to fit. + SkRRect may modify the provided parameters when initializing bounds and radii. + If either axis radii is zero or less, radii are stored as zero; corner is square. + If corner curves overlap, radii are proportionally reduced to fit within bounds. */ class SK_API SkRRect { public: - /** Default initialized to a rrect at the origin with zero width and height. */ + + /** Initializes bounds at (0, 0), the origin, with zero width and height. + Initializes corner radii to (0, 0), and sets type of kEmpty_Type. + + @return empty SkRRect + */ SkRRect() = default; + /** Initializes to copy of rrect bounds and corner radii. + + @param rrect bounds and corner to copy + @return copy of rrect + */ SkRRect(const SkRRect& rrect) = default; + + /** Copies rrect bounds and corner radii. + + @param rrect bounds and corner to copy + @return copy of rrect + */ SkRRect& operator=(const SkRRect& rrect) = default; - /** - * Enum to capture the various possible subtypes of RR. Accessed - * by type(). The subtypes become progressively less restrictive. - */ + /** \enum SkRRect::Type + Type describes possible specializations of SkRRect. Each Type is + exclusive; a SkRRect may only have one type. + + Type members become progressively less restrictive; larger values of + Type have more degrees of freedom than smaller values. + */ enum Type { - // !< The RR has zero width and/or zero height. All radii are zero. - kEmpty_Type, - - //!< The RR is actually a (non-empty) rect (i.e., at least one radius - //!< at each corner is zero) - kRect_Type, - - //!< The RR is actually a (non-empty) oval (i.e., all x radii are equal - //!< and >= width/2 and all the y radii are equal and >= height/2 - kOval_Type, - - //!< The RR is non-empty and all the x radii are equal & all y radii - //!< are equal but it is not an oval (i.e., there are lines between - //!< the curves) nor a rect (i.e., both radii are non-zero) - kSimple_Type, - - //!< The RR is non-empty and the two left x radii are equal, the two top - //!< y radii are equal, and the same for the right and bottom but it is - //!< neither an rect, oval, nor a simple RR. It is called "nine patch" - //!< because the centers of the corner ellipses form an axis aligned - //!< rect with edges that divide the RR into an 9 rectangular patches: - //!< an interior patch, four edge patches, and four corner patches. - kNinePatch_Type, - - //!< A fully general (non-empty) RR. Some of the x and/or y radii are - //!< different from the others and there must be one corner where - //!< both radii are non-zero. - kComplex_Type, - - kLastType = kComplex_Type, + kEmpty_Type, //!< zero width or height + kRect_Type, //!< non-zero width and height, and zeroed radii + kOval_Type, //!< non-zero width and height filled with radii + kSimple_Type, //!< non-zero width and height with equal radii + kNinePatch_Type, //!< non-zero width and height with axis-aligned radii + kComplex_Type, //!< non-zero width and height with arbitrary radii + kLastType = kComplex_Type, //!< largest Type value }; - /** - * Returns the RR's sub type. - */ + /** Returns SkRRect::Type, one of: + kEmpty_Type, kRect_Type, kOval_Type, kSimple_Type, kNinePatch_Type, + kComplex_Type. + + @return SkRRect::Type + */ Type getType() const { SkASSERT(this->isValid()); return static_cast<Type>(fType); } + /** Returns SkRRect::Type, one of: + kEmpty_Type, kRect_Type, kOval_Type, kSimple_Type, kNinePatch_Type, + kComplex_Type. + + @return SkRRect::Type + */ Type type() const { return this->getType(); } inline bool isEmpty() const { return kEmpty_Type == this->getType(); } @@ -106,26 +104,42 @@ public: inline bool isNinePatch() const { return kNinePatch_Type == this->getType(); } inline bool isComplex() const { return kComplex_Type == this->getType(); } + /** Returns span on the x-axis. This does not check if result fits in 32-bit float; + result may be infinity. + + @return bounds().fRight minus bounds().fLeft + */ SkScalar width() const { return fRect.width(); } + + /** Returns span on the y-axis. This does not check if result fits in 32-bit float; + result may be infinity. + + @return bounds().fBottom minus bounds().fTop + */ SkScalar height() const { return fRect.height(); } - /** - * kSimple means that all corners have the same x,y radii. This returns the top/left - * corner's radii as representative of all corners. If the RRect is kComplex, then - * this still returns that corner's radii, but it is not indicative of the other corners. - */ + /** Returns top-left corner x-radii. If type() returns kEmpty_Type, kRect_Type, + kOval_Type, or kSimple_Type, returns a value representative of all corner radii. + If type() returns kNinePatch_Type or kComplex_Type, at least one of the + remaining three corners has a different value. + + @return corner radii for simple types + */ SkVector getSimpleRadii() const { return fRadii[0]; } - /** - * Same as default initialized - zero width and height at the origin. - */ + /** Sets bounds to zero width and height at (0, 0), the origin. Sets + corner radii to zero and sets type to kEmpty_Type. + */ void setEmpty() { *this = SkRRect(); } - /** - * Set this RR to match the supplied rect. All radii will be 0. - */ + /** Sets bounds to sorted rect, and sets corner radii to zero. + If set bounds has width and height, and sets type to kRect_Type; + otherwise, sets type to kEmpty_Type. + + @param rect bounds to set + */ void setRect(const SkRect& rect) { if (!this->initializeRect(rect)) { return; @@ -137,31 +151,61 @@ public: SkASSERT(this->isValid()); } - /** Makes an empty rrect at the origin with zero width and height. */ + /** Initializes bounds at (0, 0), the origin, with zero width and height. + Initializes corner radii to (0, 0), and sets type of kEmpty_Type. + + @return empty SkRRect + */ static SkRRect MakeEmpty() { return SkRRect(); } + /** Initializes to copy of r bounds and zeroes corner radii. + + @param r bounds to copy + @return copy of r + */ static SkRRect MakeRect(const SkRect& r) { SkRRect rr; rr.setRect(r); return rr; } + /** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii + to half oval.height(). If oval bounds is empty, sets to kEmpty_Type. + Otherwise, sets to kOval_Type. + + @param oval bounds of oval + @return oval + */ static SkRRect MakeOval(const SkRect& oval) { SkRRect rr; rr.setOval(oval); return rr; } + /** Sets to rounded rectangle with the same radii for all four corners. + If rect is empty, sets to kEmpty_Type. + Otherwise, if xRad and yRad are zero, sets to kRect_Type. + Otherwise, if xRad is at least half rect.width() and yRad is at least half + rect.height(), sets to kOval_Type. + Otherwise, sets to kSimple_Type. + + @param rect bounds of rounded rectangle + @param xRad x-axis radius of corners + @param yRad y-axis radius of corners + @return rounded rectangle + */ static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { SkRRect rr; rr.setRectXY(rect, xRad, yRad); return rr; } - /** - * Set this RR to match the supplied oval. All x radii will equal half the - * width and all y radii will equal half the height. - */ + /** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii + to half oval.height(). If oval bounds is empty, sets to kEmpty_Type. + Otherwise, sets to kOval_Type. + + @param oval bounds of oval + */ void setOval(const SkRect& oval) { if (!this->initializeRect(oval)) { return; @@ -178,131 +222,278 @@ public: SkASSERT(this->isValid()); } - /** - * Initialize the RR with the same radii for all four corners. - */ + /** Sets to rounded rectangle with the same radii for all four corners. + If rect is empty, sets to kEmpty_Type. + Otherwise, if xRad or yRad is zero, sets to kRect_Type. + Otherwise, if xRad is at least half rect.width() and yRad is at least half + rect.height(), sets to kOval_Type. + Otherwise, sets to kSimple_Type. + + @param rect bounds of rounded rectangle + @param xRad x-axis radius of corners + @param yRad y-axis radius of corners + */ void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad); - /** - * Initialize the rr with one radius per-side. - */ + /** Sets bounds to rect. Sets radii to (leftRad, topRad), (rightRad, topRad), + (rightRad, bottomRad), (leftRad, bottomRad). + + If rect is empty, sets to kEmpty_Type. + Otherwise, if leftRad and rightRad are zero, sets to kRect_Type. + Otherwise, if topRad and bottomRad are zero, sets to kRect_Type. + Otherwise, if leftRad and rightRad are equal and at least half rect.width(), and + topRad and bottomRad are equal at least half rect.height(), sets to kOval_Type. + Otherwise, if leftRad and rightRad are equal, and topRad and bottomRad are equal, + sets to kSimple_Type. Otherwise, sets to kNinePatch_Type. + + Nine patch refers to the nine parts defined by the radii: one center rectangle, + four edge patches, and four corner patches. + + @param rect bounds of rounded rectangle + @param leftRad left-top and left-bottom x-axis radius + @param topRad left-top and right-top y-axis radius + @param rightRad right-top and right-bottom x-axis radius + @param bottomRad left-bottom and right-bottom y-axis radius + */ void setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad); - /** - * Initialize the RR with potentially different radii for all four corners. - */ + /** Sets bounds to rect. Sets radii array for individual control of all for corners. + + If rect is empty, sets to kEmpty_Type. + Otherwise, if one of each corner radii are zero, sets to kRect_Type. + Otherwise, if all x-axis radii are equal and at least half rect.width(), and + all y-axis radii are equal at least half rect.height(), sets to kOval_Type. + Otherwise, if all x-axis radii are equal, and all y-axis radii are equal, + sets to kSimple_Type. Otherwise, sets to kNinePatch_Type. + + @param rect bounds of rounded rectangle + @param radii corner x-axis and y-axis radii + */ void setRectRadii(const SkRect& rect, const SkVector radii[4]); - // The radii are stored in UL, UR, LR, LL order. + /** \enum SkRRect::Corner + The radii are stored: top-left, top-right, bottom-right, bottom-left. + */ enum Corner { - kUpperLeft_Corner, - kUpperRight_Corner, - kLowerRight_Corner, - kLowerLeft_Corner, + kUpperLeft_Corner, //!< index of top-left corner radii + kUpperRight_Corner, //!< index of top-right corner radii + kLowerRight_Corner, //!< index of bottom-right corner radii + kLowerLeft_Corner, //!< index of bottom-left corner radii }; + /** Returns bounds. Bounds may have zero width or zero height. Bounds right is + greater than or equal to left; bounds bottom is greater than or equal to top. + Result is identical to getBounds(). + + @return bounding box + */ const SkRect& rect() const { return fRect; } + + /** Returns scalar pair for radius of curve on x-axis and y-axis for one corner. + Both radii may be zero. If not zero, both are positive and finite. + + @param corner one of: kUpperLeft_Corner, kUpperRight_Corner, + kLowerRight_Corner, kLowerLeft_Corner + @return x-axis and y-axis radii for one corner + */ SkVector radii(Corner corner) const { return fRadii[corner]; } + + /** Returns bounds. Bounds may have zero width or zero height. Bounds right is + greater than or equal to left; bounds bottom is greater than or equal to top. + Result is identical to rect(). + + @return bounding box + */ const SkRect& getBounds() const { return fRect; } + /** Returns true if bounds and radii in a are equal to bounds and radii in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes width different signs. + + @param a SkRect bounds and radii to compare + @param b SkRect bounds and radii to compare + @return true if members are equal + */ friend bool operator==(const SkRRect& a, const SkRRect& b) { return a.fRect == b.fRect && SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8); } + /** Returns true if bounds and radii in a are not equal to bounds and radii in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes width different signs. + + @param a SkRect bounds and radii to compare + @param b SkRect bounds and radii to compare + @return true if members are not equal + */ friend bool operator!=(const SkRRect& a, const SkRRect& b) { return a.fRect != b.fRect || !SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8); } - /** - * Call inset on the bounds, and adjust the radii to reflect what happens - * in stroking: If the corner is sharp (no curvature), leave it alone, - * otherwise we grow/shrink the radii by the amount of the inset. If a - * given radius becomes negative, it is pinned to 0. - * - * If the inset amount is larger than the width/height then the rrect collapses to - * a degenerate line or point. - * - * If the inset is sufficiently negative to cause the bounds to become infinite then - * the result is a default initialized rrect. - * - * It is valid for dst == this. - */ + /** Copies SkRRect to dst, then insets dst bounds by dx and dy, and adjusts dst + radii by dx and dy. dx and dy may be positive, negative, or zero. dst may be + SkRRect. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half dst bounds width, dst bounds left and right are set to + bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, dst bounds is zeroed. + + @param dx added to rect().fLeft, and subtracted from rect().fRight + @param dy added to rect().fTop, and subtracted from rect().fBottom + @param dst insets bounds and radii + */ void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const; + /** Insets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half bounds width, bounds left and right are set to + bounds x-axis center. If dy exceeds half bounds height, bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, bounds is zeroed. + + @param dx added to rect().fLeft, and subtracted from rect().fRight + @param dy added to rect().fTop, and subtracted from rect().fBottom + */ void inset(SkScalar dx, SkScalar dy) { this->inset(dx, dy, this); } - /** - * Call outset on the bounds, and adjust the radii to reflect what happens - * in stroking: If the corner is sharp (no curvature), leave it alone, - * otherwise we grow/shrink the radii by the amount of the inset. If a - * given radius becomes negative, it is pinned to 0. - * - * It is valid for dst == this. - */ + /** Outsets dst bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half dst bounds width, dst bounds left and right are set to + bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, dst bounds is zeroed. + + @param dx subtracted from rect().fLeft, and added to rect().fRight + @param dy subtracted from rect().fTop, and added to rect().fBottom + @param dst outset bounds and radii + */ void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const { this->inset(-dx, -dy, dst); } + + /** Outsets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half bounds width, bounds left and right are set to + bounds x-axis center. If dy exceeds half bounds height, bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, bounds is zeroed. + + @param dx subtracted from rect().fLeft, and added to rect().fRight + @param dy subtracted from rect().fTop, and added to rect().fBottom + */ void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy, this); } - /** - * Translate the rrect by (dx, dy). - */ + /** Translates SkRRect by (dx, dy). + + @param dx offset added to rect().fLeft and rect().fRight + @param dy offset added to rect().fTop and rect().fBottom + */ void offset(SkScalar dx, SkScalar dy) { fRect.offset(dx, dy); } + /** Returns SkRRect translated by (dx, dy). + + @param dx offset added to rect().fLeft and rect().fRight + @param dy offset added to rect().fTop and rect().fBottom + @return SkRRect bounds offset by (dx, dy), with unchanged corner radii + */ SkRRect SK_WARN_UNUSED_RESULT makeOffset(SkScalar dx, SkScalar dy) const { return SkRRect(fRect.makeOffset(dx, dy), fRadii, fType); } - /** - * Returns true if 'rect' is wholy inside the RR, and both - * are not empty. - */ + /** Returns true if rect is inside the bounds and corner radii, and if + SkRRect and rect are not empty. + + @param rect area tested for containment + @return true if SkRRect contains rect + */ bool contains(const SkRect& rect) const; + /** Returns true if bounds and radii values are finite and describe a SkRRect + SkRRect::Type that matches getType(). All SkRRect methods construct valid types, + even if the input values are not valid. Invalid SkRRect data can only + be generated by corrupting memory. + + @return true if bounds and radii match type() + */ bool isValid() const; static constexpr size_t kSizeInMemory = 12 * sizeof(SkScalar); - /** - * Write the rrect into the specified buffer. This is guaranteed to always - * write kSizeInMemory bytes, and that value is guaranteed to always be - * a multiple of 4. Return kSizeInMemory. - */ + /** Writes SkRRect to buffer. Writes kSizeInMemory bytes, and returns + kSizeInMemory, the number of bytes written. + + @param buffer storage for SkRRect + @return bytes written, kSizeInMemory + */ size_t writeToMemory(void* buffer) const; - /** - * Reads the rrect from the specified buffer - * - * If the specified buffer is large enough, this will read kSizeInMemory bytes, - * and that value is guaranteed to always be a multiple of 4. - * - * @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 - */ + /** Reads SkRRect from buffer, reading kSizeInMemory bytes. + Returns kSizeInMemory, bytes read if length is at least kSizeInMemory. + Otherwise, returns zero. + + @param buffer memory to read from + @param length size of buffer + @return bytes read, or 0 if length is less than kSizeInMemory + */ size_t readFromMemory(const void* buffer, size_t length); - /** - * Transform by the specified matrix, and put the result in dst. - * - * @param matrix SkMatrix specifying the transform. Must only contain - * scale and/or translate, or this call will fail. - * @param dst SkRRect to store the result. It is an error to use this, - * which would make this function no longer const. - * @return true on success, false on failure. - */ + /** Transforms by SkRRect by matrix, storing result in dst. + Returns true if SkRRect transformed can be represented by another SkRRect. + Returns false if matrix contains transformations other than scale and translate. + + Asserts in debug builds if SkRRect equals dst. + + @param matrix SkMatrix specifying the transform + @param dst SkRRect to store the result + @return true if transformation succeeded. + */ bool transform(const SkMatrix& matrix, SkRRect* dst) const; + /** Writes text representation of SkRRect to standard output. + Set asHex true to generate exact binary representations + of floating point numbers. + + @param asHex true if SkScalar values are written as hexadecimal + */ void dump(bool asHex) const; + + /** Writes text representation of SkRRect to standard output. The representation + may be directly compiled as C++ code. Floating point values are written + with limited precision; it may not be possible to reconstruct original + SkRRect from output. + */ void dump() const { this->dump(false); } + + /** Writes text representation of SkRRect to standard output. The representation + may be directly compiled as C++ code. Floating point values are written + in hexadecimal to preserve their exact bit pattern. The output reconstructs the + original SkRRect. + */ void dumpHex() const { this->dump(true); } private: |