diff options
author | Mike Reed <reed@google.com> | 2018-06-21 10:51:35 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-21 16:47:42 +0000 |
commit | 1e259cda4fb7f12e98dd611bd651f40ebef2d14a (patch) | |
tree | adac538d508415080ebb2a5204944566b221b49b /src | |
parent | f7dcdb0283ea50bbb0731c780ddd37aebbe750a9 (diff) |
use double to compute root to avoid overflow
Bug: 850350
Change-Id: Iac04fc62e69f51b68c5fc7f55ac1be930133cc74
Reviewed-on: https://skia-review.googlesource.com/136597
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkGeometry.cpp | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp index a53450949d..ace8a7d4d8 100644 --- a/src/core/SkGeometry.cpp +++ b/src/core/SkGeometry.cpp @@ -60,6 +60,15 @@ static int valid_unit_divide(SkScalar numer, SkScalar denom, SkScalar* ratio) { return 1; } +// Just returns its argument, but makes it easy to set a break-point to know when +// SkFindUnitQuadRoots is going to return 0 (an error). +static int return_check_zero(int value) { + if (value == 0) { + return 0; + } + return value; +} + /** From Numerical Recipes in C. Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C]) @@ -70,22 +79,21 @@ int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) { SkASSERT(roots); if (A == 0) { - return valid_unit_divide(-C, B, roots); + return return_check_zero(valid_unit_divide(-C, B, roots)); } SkScalar* r = roots; - SkScalar R = B*B - 4*A*C; - if (R < 0 || !SkScalarIsFinite(R)) { // complex roots - // if R is infinite, it's possible that it may still produce - // useful results if the operation was repeated in doubles - // the flipside is determining if the more precise answer - // isn't useful because surrounding machinery (e.g., subtracting - // the axis offset from C) already discards the extra precision - // more investigation and unit tests required... - return 0; + // use doubles so we don't overflow temporarily trying to compute R + double dr = (double)B * B - 4 * (double)A * C; + if (dr < 0) { + return return_check_zero(0); + } + dr = sqrt(dr); + SkScalar R = SkDoubleToScalar(dr); + if (!SkScalarIsFinite(R)) { + return return_check_zero(0); } - R = SkScalarSqrt(R); SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2; r += valid_unit_divide(Q, A, r); @@ -98,7 +106,7 @@ int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) { r -= 1; // skip the double root } } - return (int)(r - roots); + return return_check_zero((int)(r - roots)); } /////////////////////////////////////////////////////////////////////////////// |