aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2016-07-13 10:56:53 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-07-13 10:56:53 -0700
commitb1b12f8666a48b8ff1367beed97bc84032552ac8 (patch)
treea28db558a027af8c1d26d873e42987017f4a0233
parent99f942e5505a663b0d355ad187484f15e3a9a83a (diff)
handle large conic weights
-rw-r--r--include/core/SkPoint.h4
-rw-r--r--src/core/SkGeometry.cpp11
-rw-r--r--tests/GeometryTest.cpp40
-rw-r--r--tests/PathTest.cpp14
4 files changed, 68 insertions, 1 deletions
diff --git a/include/core/SkPoint.h b/include/core/SkPoint.h
index 52d01ae88c..f5ecbab78c 100644
--- a/include/core/SkPoint.h
+++ b/include/core/SkPoint.h
@@ -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
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp
index 5d181a3a20..7dd5359b7d 100644
--- a/src/core/SkGeometry.cpp
+++ b/src/core/SkGeometry.cpp
@@ -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;
}
diff --git a/tests/GeometryTest.cpp b/tests/GeometryTest.cpp
index 17e4644857..b3bbb51bc0 100644
--- a/tests/GeometryTest.cpp
+++ b/tests/GeometryTest.cpp
@@ -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);
}
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index 5bc3d95b6f..44b6786019 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -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
@@ -4164,6 +4177,7 @@ DEF_TEST(PathContains, reporter) {
}
DEF_TEST(Paths, reporter) {
+ test_fuzz_crbug_627414(reporter);
test_path_crbug364224();
SkTSize<SkScalar>::Make(3,4);