diff options
author | reed <reed@google.com> | 2016-07-13 10:56:53 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-07-13 10:56:53 -0700 |
commit | b1b12f8666a48b8ff1367beed97bc84032552ac8 (patch) | |
tree | a28db558a027af8c1d26d873e42987017f4a0233 | |
parent | 99f942e5505a663b0d355ad187484f15e3a9a83a (diff) |
handle large conic weights
BUG=627414
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2142393003
Review-Url: https://codereview.chromium.org/2142393003
-rw-r--r-- | include/core/SkPoint.h | 4 | ||||
-rw-r--r-- | src/core/SkGeometry.cpp | 11 | ||||
-rw-r--r-- | tests/GeometryTest.cpp | 40 | ||||
-rw-r--r-- | tests/PathTest.cpp | 14 |
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); |