diff options
-rw-r--r-- | src/core/SkEdgeClipper.cpp | 20 | ||||
-rw-r--r-- | tests/PathTest.cpp | 16 |
2 files changed, 34 insertions, 2 deletions
diff --git a/src/core/SkEdgeClipper.cpp b/src/core/SkEdgeClipper.cpp index 85c519d364..b5ac27ae59 100644 --- a/src/core/SkEdgeClipper.cpp +++ b/src/core/SkEdgeClipper.cpp @@ -263,9 +263,25 @@ static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) { if (pts[0].fY < clip.fTop) { SkPoint tmp[7]; chop_mono_cubic_at_y(pts, clip.fTop, tmp); + + /* + * For a large range in the points, we can do a poor job of chopping, such that the t + * we computed resulted in the lower cubic still being partly above the clip. + * + * If just the first or first 2 Y values are above the fTop, we can just smash them + * down. If the first 3 Ys are above fTop, we can't smash all 3, as that can really + * distort the cubic. In this case, we take the first output (tmp[3..6] and treat it as + * a guess, and re-chop against fTop. Then we fall through to checking if we need to + * smash the first 1 or 2 Y values. + */ + if (tmp[3].fY < clip.fTop && tmp[4].fY < clip.fTop && tmp[5].fY < clip.fTop) { + SkPoint tmp2[4]; + memcpy(tmp2, &tmp[3].fX, 4 * sizeof(SkPoint)); + chop_mono_cubic_at_y(tmp2, clip.fTop, tmp); + } + // tmp[3, 4].fY should all be to the below clip.fTop. - // Since we can't trust the numerics of - // the chopper, we force those conditions now + // Since we can't trust the numerics of the chopper, we force those conditions now tmp[3].fY = clip.fTop; clamp_ge(tmp[4].fY, clip.fTop); diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index 44b6786019..8f98e6abaa 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -4129,6 +4129,21 @@ public: } }; +static void test_crbug_629455(skiatest::Reporter* reporter) { + SkPath path; + path.moveTo(0, 0); + path.cubicTo(SkBits2Float(0xcdcdcd00), SkBits2Float(0xcdcdcdcd), + SkBits2Float(0xcdcdcdcd), SkBits2Float(0xcdcdcdcd), + SkBits2Float(0x423fcdcd), SkBits2Float(0x40ed9341)); +// AKA: cubicTo(-4.31596e+08f, -4.31602e+08f, -4.31602e+08f, -4.31602e+08f, 47.951f, 7.42423f); + path.lineTo(0, 0); + + auto surface = SkSurface::MakeRasterN32Premul(100, 100); + SkPaint paint; + paint.setAntiAlias(true); + surface->getCanvas()->drawPath(path, paint); +} + static void test_interp(skiatest::Reporter* reporter) { SkPath p1, p2, out; REPORTER_ASSERT(reporter, p1.isInterpolatable(p2)); @@ -4177,6 +4192,7 @@ DEF_TEST(PathContains, reporter) { } DEF_TEST(Paths, reporter) { + test_crbug_629455(reporter); test_fuzz_crbug_627414(reporter); test_path_crbug364224(); |