31 if (!this->initializeRect(oval)) {
38 if (xRad == 0.0f || yRad == 0.0f) {
40 memset(fRadii, 0,
sizeof(fRadii));
43 for (
int i = 0; i < 4; ++i) {
44 fRadii[i].
set(xRad, yRad);
53 if (!this->initializeRect(
rect)) {
61 if (fRect.
width() < xRad+xRad || fRect.
height() < yRad+yRad) {
70 if (xRad <= 0 || yRad <= 0) {
76 for (
int i = 0; i < 4; ++i) {
77 fRadii[i].
set(xRad, yRad);
89 bool allCornersSquare =
true;
92 for (
int i = 0; i < 4; ++i) {
93 if (radii[i].fX <= 0 || radii[i].fY <= 0) {
101 allCornersSquare =
false;
105 return allCornersSquare;
117 if (!this->initializeRect(
rect)) {
121 if (!
SkIsFinite(leftRad, topRad, rightRad, bottomRad)) {
126 leftRad = std::max(leftRad, 0.0f);
127 topRad = std::max(topRad, 0.0f);
128 rightRad = std::max(rightRad, 0.0f);
129 bottomRad = std::max(bottomRad, 0.0f);
132 if (leftRad + rightRad > fRect.
width()) {
135 if (topRad + bottomRad > fRect.
height()) {
146 if (leftRad == rightRad && topRad == bottomRad) {
149 }
else if (0 == leftRad || 0 == topRad) {
183 if ((rad1 + rad2) > limit) {
184 return std::min(curMin, limit / (rad1 + rad2));
190 if (!this->initializeRect(
rect)) {
199 memcpy(fRadii,
radii,
sizeof(fRadii));
214bool SkRRect::initializeRect(
const SkRect& rect) {
222 memset(fRadii, 0,
sizeof(fRadii));
237 }
else if (
a +
b ==
b) {
242bool SkRRect::scaleRadii() {
339 return dist <=
SkScalarSquare(fRadii[index].fX * fRadii[index].fY);
382void SkRRect::computeType() {
385 for (
size_t i = 0; i < std::size(fRadii); ++i) {
393 bool allRadiiEqual =
true;
394 bool allCornersSquare = 0 == fRadii[0].
fX || 0 == fRadii[0].
fY;
396 for (
int i = 1; i < 4; ++i) {
397 if (0 != fRadii[i].fX && 0 != fRadii[i].fY) {
400 allCornersSquare =
false;
402 if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) {
403 allRadiiEqual =
false;
407 if (allCornersSquare) {
437 if (
nullptr == dst) {
446 if (matrix.isIdentity()) {
451 if (!matrix.preservesAxisAlignment()) {
456 if (!matrix.mapRect(&newRect, fRect)) {
469 dst->fRect = newRect;
480 for (
int i = 0; i < 4; ++i) {
489 SkScalar xScale = matrix.getScaleX();
490 SkScalar yScale = matrix.getScaleY();
495 if (!matrix.isScaleTranslate()) {
496 const bool isClockwise = matrix.getSkewX() < 0;
499 xScale = matrix.getSkewY() * (isClockwise ? 1 : -1);
500 yScale = matrix.getSkewX() * (isClockwise ? -1 : 1);
502 const int dir = isClockwise ? 3 : 1;
503 for (
int i = 0; i < 4; ++i) {
504 const int src = (i + dir) >= 4 ? (i + dir) % 4 : (i + dir);
506 dst->fRadii[i].fX = fRadii[src].
fY;
507 dst->fRadii[i].fY = fRadii[src].
fX;
510 for (
int i = 0; i < 4; ++i) {
511 dst->fRadii[i].fX = fRadii[i].
fX;
512 dst->fRadii[i].fY = fRadii[i].
fY;
516 const bool flipX = xScale < 0;
521 const bool flipY = yScale < 0;
527 for (
int i = 0; i < 4; ++i) {
528 dst->fRadii[i].fX *= xScale;
529 dst->fRadii[i].fY *= yScale;
550 if (!AreRectAndRadiiValid(dst->fRect, dst->fRadii)) {
564 bool degenerate =
false;
575 memset(dst->fRadii, 0,
sizeof(dst->fRadii));
586 for (
int i = 0; i < 4; ++i) {
594 dst->setRectRadii(r,
radii);
636 SkString line(
"const SkPoint corners[] = {\n");
637 for (
int i = 0; i < 4; ++i) {
641 line.appendf(
" { %s, %s },", strX.
c_str(), strY.
c_str());
643 line.appendf(
" /* %f %f */", fRadii[i].
x(), fRadii[i].
y());
664 if (!AreRectAndRadiiValid(fRect, fRadii)) {
668 bool allRadiiZero = (0 == fRadii[0].
fX && 0 == fRadii[0].
fY);
669 bool allCornersSquare = (0 == fRadii[0].
fX || 0 == fRadii[0].
fY);
670 bool allRadiiSame =
true;
672 for (
int i = 1; i < 4; ++i) {
673 if (0 != fRadii[i].fX || 0 != fRadii[i].fY) {
674 allRadiiZero =
false;
677 if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) {
678 allRadiiSame =
false;
681 if (0 != fRadii[i].fX && 0 != fRadii[i].fY) {
682 allCornersSquare =
false;
693 if (!fRect.
isEmpty() || !allRadiiZero || !allRadiiSame || !allCornersSquare) {
698 if (fRect.
isEmpty() || !allRadiiZero || !allRadiiSame || !allCornersSquare) {
703 if (fRect.
isEmpty() || allRadiiZero || !allRadiiSame || allCornersSquare) {
707 for (
int i = 0; i < 4; ++i) {
715 if (fRect.
isEmpty() || allRadiiZero || !allRadiiSame || allCornersSquare) {
720 if (fRect.
isEmpty() || allRadiiZero || allRadiiSame || allCornersSquare ||
726 if (fRect.
isEmpty() || allRadiiZero || allRadiiSame || allCornersSquare ||
736bool SkRRect::AreRectAndRadiiValid(
const SkRect& rect,
const SkVector radii[4]) {
740 for (
int i = 0; i < 4; ++i) {
774 SkScalar dw = leftShift + rightShift;
775 SkScalar dh = topShift + bottomShift;
789 if (horizArea > vertArea && horizArea > innerArea) {
791 innerBounds.
fLeft += leftShift;
792 innerBounds.
fRight -= rightShift;
793 }
else if (vertArea > innerArea) {
795 innerBounds.
fTop += topShift;
796 innerBounds.
fBottom -= bottomShift;
797 }
else if (innerArea > 0.f) {
838 SkPoint aCorner = getCorner(
a.rect(), corner);
839 SkPoint bCorner = getCorner(
b.rect(), corner);
841 if (
test == aCorner &&
test == bCorner) {
847 if (aRadii.
fX >= bRadii.
fX && aRadii.
fY >= bRadii.
fY) {
850 }
else if (bRadii.
fX >= aRadii.
fX && bRadii.
fY >= aRadii.
fY) {
856 }
else if (
test == aCorner) {
860 *radii =
a.radii(corner);
861 if (*radii ==
b.radii(corner)) {
862 return insideCorner(corner, aCorner, bCorner);
864 return b.checkCornerContainment(aCorner.
fX, aCorner.
fY);
866 }
else if (
test == bCorner) {
868 *radii =
b.radii(corner);
869 if (*radii ==
a.radii(corner)) {
870 return insideCorner(corner, bCorner, aCorner);
872 return a.checkCornerContainment(bCorner.
fX, bCorner.
fY);
878 return a.checkCornerContainment(
test.fX,
test.fY) &&
879 b.checkCornerContainment(
test.fX,
test.fY);
886 if (!intersection.fRect.
intersect(
a.rect(),
b.rect())) {
903 for (
auto c : corners) {
904 if (!getIntersectionRadii(intersection.fRect, c, &intersection.fRadii[c])) {
914 if (!SkRRect::AreRectAndRadiiValid(intersection.fRect, intersection.fRadii) ||
915 intersection.scaleRadii()) {
921 intersection.computeType();
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool SkIsFinite(T x, Pack... values)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static bool clamp_to_zero(SkVector radii[4])
static bool are_radius_check_predicates_valid(SkScalar rad, SkScalar min, SkScalar max)
static void flush_to_zero(SkScalar &a, SkScalar &b)
static bool radii_are_nine_patch(const SkVector radii[4])
static double compute_min_scale(double rad1, double rad2, double limit, double curMin)
void swap(sk_sp< T > &a, sk_sp< T > &b)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SkScalarAve(a, b)
#define SK_ScalarRoot2Over2
static SkScalar SkScalarSquare(SkScalar x)
void SkAppendScalar(SkString *str, SkScalar value, SkScalarAsStringType asType)
@ kHex_SkScalarAsStringType
@ kDec_SkScalarAsStringType
static bool ReadFromBuffer(SkRBuffer *buffer, SkRRect *rr)
static SkRect InnerBounds(const SkRRect &rr)
static SkRRect ConservativeIntersect(const SkRRect &a, const SkRRect &b)
static bool IsNearlySimpleCircular(const SkRRect &rr, SkScalar tolerance=SK_ScalarNearlyZero)
static bool AllCornersCircular(const SkRRect &rr, SkScalar tolerance=SK_ScalarNearlyZero)
static void WriteToBuffer(const SkRRect &rr, SkWBuffer *buffer)
const SkRect & rect() const
SkVector radii(Corner corner) const
@ kOval_Type
non-zero width and height filled with radii
@ kLastType
largest Type value
@ kSimple_Type
non-zero width and height with equal radii
@ kEmpty_Type
zero width or height
@ kNinePatch_Type
non-zero width and height with axis-aligned radii
@ kRect_Type
non-zero width and height, and zeroed radii
@ kComplex_Type
non-zero width and height with arbitrary radii
SkString dumpToString(bool asHex) const
void inset(SkScalar dx, SkScalar dy, SkRRect *dst) const
size_t readFromMemory(const void *buffer, size_t length)
@ kUpperLeft_Corner
index of top-left corner radii
@ kLowerRight_Corner
index of bottom-right corner radii
@ kUpperRight_Corner
index of top-right corner radii
@ kLowerLeft_Corner
index of bottom-left corner radii
bool transform(const SkMatrix &matrix, SkRRect *dst) const
size_t writeToMemory(void *buffer) const
void setOval(const SkRect &oval)
void setRectRadii(const SkRect &rect, const SkVector radii[4])
bool contains(const SkRect &rect) const
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
void setNinePatch(const SkRect &rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad)
static constexpr size_t kSizeInMemory
const SkRect & getBounds() const
void setRect(const SkRect &rect)
static SkRRect MakeEmpty()
static constexpr float HalfWidth(const SkRect &r)
static constexpr float HalfHeight(const SkRect &r)
static void AdjustRadii(double limit, double scale, SkScalar *a, SkScalar *b)
const char * c_str() const
static const uint8_t buffer[]
static float max(float r, float g, float b)
static float min(float r, float g, float b)
void set(float x, float y)
SkRect makeSorted() const
static constexpr SkRect MakeEmpty()
SkScalar fBottom
larger y-axis bounds
bool intersect(const SkRect &r)
SkScalar fLeft
smaller x-axis bounds
SkRect makeInset(float dx, float dy) const
SkScalar fRight
larger x-axis bounds
constexpr float centerX() const
constexpr float height() const
constexpr float centerY() const
constexpr float width() const
void dump(bool asHex) const
SkScalar fTop
smaller y-axis bounds
static constexpr int kScale