diff options
author | 2014-12-15 12:28:33 -0800 | |
---|---|---|
committer | 2014-12-15 12:28:33 -0800 | |
commit | 5bcbe91304ec2515208b5218517579f48874e928 (patch) | |
tree | e81f9b0521dc20726c30f99a3bba50f54c50624a /src | |
parent | c97570cfb38a90ad36b4dce1ca82e809d3fb9ef0 (diff) |
Fix rrects that are large enough that we lose/gain a bit when we add the radius to a bounds coordinate.
add test that triggers assert in addRRect
BUG=skia:3239
Review URL: https://codereview.chromium.org/803153003
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkPath.cpp | 1 | ||||
-rw-r--r-- | src/core/SkRRect.cpp | 46 |
2 files changed, 45 insertions, 2 deletions
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index f8280bd6d2..6dc056e81f 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -1118,6 +1118,7 @@ void SkPath::addRRect(const SkRRect& rrect, Direction dir) { } this->close(); } + SkDEBUGCODE(fPathRef->validate();) } bool SkPath::hasOnlyMoveTos() const { diff --git a/src/core/SkRRect.cpp b/src/core/SkRRect.cpp index d3a571fe99..58e7de7910 100644 --- a/src/core/SkRRect.cpp +++ b/src/core/SkRRect.cpp @@ -97,6 +97,32 @@ void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad SkDEBUGCODE(this->validate();) } +/* + * TODO: clean this guy up and possibly add to SkScalar.h + */ +static inline SkScalar SkScalarDecULP(SkScalar value) { +#if SK_SCALAR_IS_FLOAT + return SkBits2Float(SkFloat2Bits(value) - 1); +#else + #error "need impl for doubles" +#endif +} + +static SkScalar clamp_radius_add(SkScalar rad, SkScalar min, SkScalar max) { + SkASSERT(rad <= max - min); + if (min + rad > max) { + rad = SkScalarDecULP(rad); + } + return rad; +} + +static SkScalar clamp_radius_sub(SkScalar rad, SkScalar min, SkScalar max) { + SkASSERT(rad <= max - min); + if (max - rad < min) { + rad = SkScalarDecULP(rad); + } + return rad; +} void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { if (rect.isEmpty()) { @@ -159,11 +185,27 @@ void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { if (scale < SK_Scalar1) { for (int i = 0; i < 4; ++i) { - fRadii[i].fX = SkScalarMul(fRadii[i].fX, scale); - fRadii[i].fY = SkScalarMul(fRadii[i].fY, scale); + fRadii[i].fX *= scale; + fRadii[i].fY *= scale; } } + // skbug.com/3239 -- its possible that we can hit the following inconsistency: + // rad == bounds.bottom - bounds.top + // bounds.bottom - radius < bounds.top + // YIKES + // We need to detect and "fix" this now, otherwise we can have the following wackiness: + // path.addRRect(rrect); + // rrect.rect() != path.getBounds() + fRadii[0].fX = clamp_radius_add(fRadii[0].fX, rect.fLeft, rect.fRight); + fRadii[0].fY = clamp_radius_add(fRadii[0].fY, rect.fTop, rect.fBottom); + fRadii[1].fX = clamp_radius_sub(fRadii[1].fX, rect.fLeft, rect.fRight); + fRadii[1].fY = clamp_radius_add(fRadii[1].fY, rect.fTop, rect.fBottom); + fRadii[2].fX = clamp_radius_sub(fRadii[2].fX, rect.fLeft, rect.fRight); + fRadii[2].fY = clamp_radius_sub(fRadii[2].fY, rect.fTop, rect.fBottom); + fRadii[3].fX = clamp_radius_add(fRadii[3].fX, rect.fLeft, rect.fRight); + fRadii[3].fY = clamp_radius_sub(fRadii[3].fY, rect.fTop, rect.fBottom); + // At this point we're either oval, simple, or complex (not empty or rect) // but we lazily resolve the type to avoid the work if the information // isn't required. |