aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2017-11-08 17:04:47 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-11-09 16:08:44 +0000
commitfc31be40cede4dfd5b06ecaffb551b06aea85693 (patch)
treee4eeb8ba07f58f12eb8c17bfea66676b82efbacc /src/core
parentfdab576a75c636dbcd5ff44c3f5f57205cc26a6f (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.cpp41
-rw-r--r--src/core/SkGeometry.h2
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,