cherry-pick fix for large conic weights
authorreed <reed@google.com>
Mon, 25 Jul 2016 16:37:27 +0000 (09:37 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 25 Jul 2016 16:37:28 +0000 (09:37 -0700)
https://codereview.chromium.org/2142393003

BUG=627414
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2174413002
NOTREECHECKS=true
NOTRY=true
NOPRESUBMIT=true

TBR=caryclark@google.com

Review-Url: https://codereview.chromium.org/2174413002

include/core/SkPoint.h
src/core/SkGeometry.cpp
tests/GeometryTest.cpp
tests/PathTest.cpp

index 52d01ae88ce532c1f3290bea5c7e0f97c9e65792..f5ecbab78c4e6d6b1ea440ba913bf0d7e8c40344 100644 (file)
@@ -549,4 +549,8 @@ struct SK_API SkPoint {
 
 typedef SkPoint SkVector;
 
+static inline bool SkPointsAreFinite(const SkPoint array[], int count) {
+    return SkScalarsAreFinite(&array[0].fX, count << 1);
+}
+
 #endif
index 5d181a3a20ae045598765a7b64be4c7340408781..7dd5359b7dea112e9c2280a39d902a5335b12489 100644 (file)
@@ -1170,9 +1170,18 @@ static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) {
 
 int SkConic::chopIntoQuadsPOW2(SkPoint pts[], int pow2) const {
     SkASSERT(pow2 >= 0);
+    const int quadCount = 1 << pow2;
+    const int ptCount = 2 * quadCount + 1;
     *pts = fPts[0];
     SkDEBUGCODE(SkPoint* endPts =) subdivide(*this, pts + 1, pow2);
-    SkASSERT(endPts - pts == (2 * (1 << pow2) + 1));
+    SkASSERT(endPts - pts == ptCount);
+    if (!SkPointsAreFinite(pts, ptCount)) {
+        // if we generated a non-finite, pin ourselves to the middle of the hull,
+        // as our first and last are already on the first/last pts of the hull.
+        for (int i = 1; i < ptCount - 1; ++i) {
+            pts[i] = fPts[1];
+        }
+    }
     return 1 << pow2;
 }
 
index 17e46448570ec45ff43faf92cfbef15deb16100a..b3bbb51bc0122ac1b81395ac2ad06ea68c9fa896 100644 (file)
@@ -145,6 +145,45 @@ static void test_conic_tangents(skiatest::Reporter* reporter) {
     }
 }
 
+static void test_this_conic_to_quad(skiatest::Reporter* r, const SkPoint pts[3], SkScalar w) {
+    SkAutoConicToQuads quadder;
+    const SkPoint* qpts = quadder.computeQuads(pts, w, 0.25);
+    const int qcount = quadder.countQuads();
+    const int pcount = qcount * 2 + 1;
+
+    REPORTER_ASSERT(r, SkPointsAreFinite(qpts, pcount));
+}
+
+/**
+ *  We need to ensure that when a conic is approximated by quads, that we always return finite
+ *  values in the quads.
+ *
+ *  Inspired by crbug_627414
+ */
+static void test_conic_to_quads(skiatest::Reporter* reporter) {
+    const SkPoint triples[] = {
+        { 0, 0 }, { 1, 0 }, { 1, 1 },
+        { 3.58732e-43f, 2.72084f }, { 3.00392f, 3.00392f },
+        { 0, 0 }, { 100000, 0 }, { 100000, 100000 },
+        { 0, 0 }, { 1e30f, 0 }, { 1e30f, 1e30f },
+    };
+    const int N = sizeof(triples) / sizeof(SkPoint);
+
+    for (int i = 0; i < N; i += 3) {
+        const SkPoint* pts = &triples[i];
+
+        SkRect bounds;
+        bounds.set(pts, 3);
+
+        SkScalar w = 1e30f;
+        do {
+            w *= 2;
+            test_this_conic_to_quad(reporter, pts, w);
+        } while (SkScalarIsFinite(w));
+        test_this_conic_to_quad(reporter, pts, SK_ScalarNaN);
+    }
+}
+
 static void test_cubic_tangents(skiatest::Reporter* reporter) {
     SkPoint pts[] = {
         { 10, 20}, {10, 20}, {20, 30}, {30, 40},
@@ -193,4 +232,5 @@ DEF_TEST(Geometry, reporter) {
     test_cubic_tangents(reporter);
     test_quad_tangents(reporter);
     test_conic_tangents(reporter);
+    test_conic_to_quads(reporter);
 }
index 03e3459966100cccc0b433039685e10d2bad15a9..8f98e6abaa05a1e03e377014144ef24c3eb3391d 100644 (file)
@@ -619,6 +619,19 @@ static void test_bounds_crbug_513799(skiatest::Reporter* reporter) {
 #endif
 }
 
+#include "SkSurface.h"
+static void test_fuzz_crbug_627414(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.conicTo(3.58732e-43f, 2.72084f, 3.00392f, 3.00392f, 8.46e+37f);
+
+    SkPaint paint;
+    paint.setAntiAlias(true);
+
+    auto surf = SkSurface::MakeRasterN32Premul(100, 100);
+    surf->getCanvas()->drawPath(path, paint);
+}
+
 // Inspired by http://ie.microsoft.com/testdrive/Performance/Chalkboard/
 // which triggered an assert, from a tricky cubic. This test replicates that
 // example, so we can ensure that we handle it (in SkEdge.cpp), and don't
@@ -4180,6 +4193,7 @@ DEF_TEST(PathContains, reporter) {
 
 DEF_TEST(Paths, reporter) {
     test_crbug_629455(reporter);
+    test_fuzz_crbug_627414(reporter);
     test_path_crbug364224();
 
     SkTSize<SkScalar>::Make(3,4);