diff options
author | Chris Dalton <csmartdalton@google.com> | 2017-11-08 17:04:47 -0700 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-11-09 16:08:44 +0000 |
commit | fc31be40cede4dfd5b06ecaffb551b06aea85693 (patch) | |
tree | e4eeb8ba07f58f12eb8c17bfea66676b82efbacc /src/core | |
parent | fdab576a75c636dbcd5ff44c3f5f57205cc26a6f (diff) |
Harden SkClassifyCubic
BUG=chromium:743617
Change-Id: Idfb89832b48ebd60fd9109cd526bdd5cd5931ada
Reviewed-on: https://skia-review.googlesource.com/68980
Reviewed-by: Cary Clark <caryclark@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkGeometry.cpp | 41 | ||||
-rw-r--r-- | src/core/SkGeometry.h | 2 |
2 files changed, 26 insertions, 17 deletions
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp index 09f304bc31..7717a37073 100644 --- a/src/core/SkGeometry.cpp +++ b/src/core/SkGeometry.cpp @@ -536,8 +536,8 @@ int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10]) { // Assumes the third component of points is 1. // Calcs p0 . (p1 x p2) static double calc_dot_cross_cubic(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) { - const double xComp = (double) p0.fX * (double) (p1.fY - p2.fY); - const double yComp = (double) p0.fY * (double) (p2.fX - p1.fX); + const double xComp = (double) p0.fX * ((double) p1.fY - (double) p2.fY); + const double yComp = (double) p0.fY * ((double) p2.fX - (double) p1.fX); const double wComp = (double) p1.fX * (double) p2.fY - (double) p1.fY * (double) p2.fX; return (xComp + yComp + wComp); } @@ -565,24 +565,32 @@ static void calc_cubic_inflection_func(const SkPoint p[4], double d[4]) { static void normalize_t_s(double t[], double s[], int count) { // Keep the exponents at or below zero to avoid overflow down the road. for (int i = 0; i < count; ++i) { - SkASSERT(0 != s[i]); + SkASSERT(0 != s[i]); // classify_cubic should not call this method when s[i] is 0 or NaN. - int64_t expT; - memcpy(&expT, &t[i], sizeof(double)); - expT = ((expT >> 52) & 0x7ff) - 1023; + uint64_t bitsT, bitsS; + memcpy(&bitsT, &t[i], sizeof(double)); + memcpy(&bitsS, &s[i], sizeof(double)); - int64_t expS; - memcpy(&expS, &s[i], sizeof(double)); - expS = ((expS >> 52) & 0x7ff) - 1023; + uint64_t maxExponent = SkTMax(bitsT & 0x7ff0000000000000, bitsS & 0x7ff0000000000000); - double norm; - int64_t expNorm = -SkTMax(expT, expS) + 1023; - SkASSERT(expNorm > 0 && expNorm < 2047); // ensure we have a valid non-zero exponent. - expNorm = expNorm << 52; - memcpy(&norm, &expNorm, sizeof(double)); +#ifdef SK_DEBUG + uint64_t maxExponentValue = maxExponent >> 52; + // Ensure max(absT,absS) is NOT in denormalized form. SkClassifyCubic is given fp32 points, + // and does not call this method when s==0, so this should never happen. + SkASSERT(0 != maxExponentValue); + // Ensure 1/max(absT,absS) will NOT be in denormalized form. SkClassifyCubic is given fp32 + // points, so this should never happen. + SkASSERT(2046 != maxExponentValue); +#endif + + // Pick a normalizer that scales the larger exponent to 1 (aka 1023 in biased form), but + // does NOT change the mantissa (thus preserving accuracy). + double normalizer; + uint64_t normalizerExponent = (uint64_t(1023 * 2) << 52) - maxExponent; + memcpy(&normalizer, &normalizerExponent, sizeof(double)); - t[i] *= norm; - s[i] *= norm; + t[i] *= normalizer; + s[i] *= normalizer; } } @@ -652,7 +660,6 @@ static SkCubicType classify_cubic(const double d[4], double t[2], double s[2]) { } return SkCubicType::kLoop; } else { - SkASSERT(0 == discr); // Detect NaN. if (t && s) { t[0] = d[2]; s[0] = 2 * d[1]; diff --git a/src/core/SkGeometry.h b/src/core/SkGeometry.h index 675ee80ae0..176ba4ef1f 100644 --- a/src/core/SkGeometry.h +++ b/src/core/SkGeometry.h @@ -196,6 +196,8 @@ static inline bool SkCubicIsDegenerate(SkCubicType type) { d[] is filled with the cubic inflection function coefficients. See "Resolution Independent Curve Rendering using Programmable Graphics Hardware", 4.2 Curve Categorization: + If the input points contain infinities or NaN, the return values are undefined. + https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf */ SkCubicType SkClassifyCubic(const SkPoint p[4], double t[2] = nullptr, double s[2] = nullptr, |