diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h index e8c7a7fb65..3c1787ed2d 100644 --- a/include/core/SkScalar.h +++ b/include/core/SkScalar.h @@ -128,7 +128,23 @@ static inline bool SkScalarIsFinite(SkScalar x) { // 0 * NaN --> NaN SkScalar prod = x * 0; // At this point, prod will either be NaN or 0 - // Therefore we can return (prod == prod) or (0 == prod). + return !SkScalarIsNaN(prod); +} + +static inline bool SkScalarsAreFinite(SkScalar a, SkScalar b) { + SkScalar prod = 0; + prod *= a; + prod *= b; + // At this point, prod will either be NaN or 0 + return !SkScalarIsNaN(prod); +} + +static inline bool SkScalarsAreFinite(const SkScalar array[], int count) { + SkScalar prod = 0; + for (int i = 0; i < count; ++i) { + prod *= array[i]; + } + // At this point, prod will either be NaN or 0 return !SkScalarIsNaN(prod); } diff --git a/src/core/SkRRect.cpp b/src/core/SkRRect.cpp index 52b1486a75..d3dce98ad5 100644 --- a/src/core/SkRRect.cpp +++ b/src/core/SkRRect.cpp @@ -11,11 +11,14 @@ /////////////////////////////////////////////////////////////////////////////// void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { - if (rect.isEmpty()) { + if (rect.isEmpty() || !rect.isFinite()) { this->setEmpty(); return; } + if (!SkScalarsAreFinite(xRad, yRad)) { + xRad = yRad = 0; // devolve into a simple rect + } if (xRad <= 0 || yRad <= 0) { // all corners are square in this case this->setRect(rect); @@ -45,11 +48,17 @@ void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad) { - if (rect.isEmpty()) { + if (rect.isEmpty() || !rect.isFinite()) { this->setEmpty(); return; } + const SkScalar array[4] = { leftRad, topRad, rightRad, bottomRad }; + if (!SkScalarsAreFinite(array, 4)) { + this->setRect(rect); // devolve into a simple rect + return; + } + leftRad = SkMaxScalar(leftRad, 0); topRad = SkMaxScalar(topRad, 0); rightRad = SkMaxScalar(rightRad, 0); @@ -125,11 +134,16 @@ static SkScalar clamp_radius_sub(SkScalar rad, SkScalar min, SkScalar max) { } void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { - if (rect.isEmpty()) { + if (rect.isEmpty() || !rect.isFinite()) { this->setEmpty(); return; } + if (!SkScalarsAreFinite(&radii[0].fX, 8)) { + this->setRect(rect); // devolve into a simple rect + return; + } + fRect = rect; memcpy(fRadii, radii, sizeof(fRadii)); diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index a852bf0d10..d1c28ec0fb 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -3113,10 +3113,12 @@ static void test_rrect(skiatest::Reporter* reporter) { rr.setRectRadii(largeR, radii); p.addRRect(rr); test_rrect_convexity_is_unknown(reporter, &p, SkPath::kCW_Direction); + + // we check for non-finites SkRect infR = {0, 0, SK_ScalarMax, SK_ScalarInfinity}; rr.setRectRadii(infR, radii); - p.addRRect(rr); - test_rrect_convexity_is_unknown(reporter, &p, SkPath::kCW_Direction); + REPORTER_ASSERT(reporter, rr.isEmpty()); + SkRect tinyR = {0, 0, 1e-9f, 1e-9f}; p.addRoundRect(tinyR, 5e-11f, 5e-11f); test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);