From 848148ec109172f9eef9a26fa23a520cf9072b5c Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Tue, 15 Jan 2013 15:51:59 +0000 Subject: [PATCH] Fix bug in cubic-clipper (SkEdgeClipper). When we chop the cubic on Top/Bottom of the cliprect, we (correctly) clamp the Y coordinate of the control-point right next to the on-curve point that was chopped (this ensures we don't go slightly outside of the clip-rect due to imperfect T value calculation). However, the code was also clamping the other control-point as well, resulting in warping the cubic, which could sometimes force it outside of the clip. The fix is to just remove the line of code that clampped the 2nd control-point. unittest added to reproduce a test cubic that triggered an assert, due to the cubic being outside of the cliprect. The test (w/o the fix) will assert in a SK_DEBUG build. Review URL: https://codereview.appspot.com/7100056 git-svn-id: http://skia.googlecode.com/svn/trunk@7184 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/core/SkEdgeClipper.cpp | 4 +--- tests/PathTest.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/core/SkEdgeClipper.cpp b/src/core/SkEdgeClipper.cpp index 9fd6a0e..84d6e9b 100644 --- a/src/core/SkEdgeClipper.cpp +++ b/src/core/SkEdgeClipper.cpp @@ -282,12 +282,11 @@ static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) { SkPoint tmp[7]; SkChopCubicAt(pts, tmp, t); - // tmp[3, 4, 5].fY should all be to the below clip.fTop, and + // tmp[3, 4].fY should all be to the below clip.fTop, and // still be monotonic in Y. 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); - clamp_ge(tmp[5].fY, tmp[4].fY); pts[0] = tmp[3]; pts[1] = tmp[4]; @@ -309,7 +308,6 @@ static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) { SkChopCubicAt(pts, tmp, t); tmp[3].fY = clip.fBottom; clamp_le(tmp[2].fY, clip.fBottom); - clamp_le(tmp[1].fY, tmp[2].fY); pts[1] = tmp[1]; pts[2] = tmp[2]; diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index a83a0a4..11829d4 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -52,6 +52,45 @@ static void test_addrect_isfinite(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, path.isFinite()); } +static void build_big_path(SkPath* path, bool reducedCase) { + if (reducedCase) { + path->moveTo(577330, 1971.72f); + path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f); + } else { + path->moveTo(60.1631f, 7.70567f); + path->quadTo(60.1631f, 7.70567f, 0.99474f, 0.901199f); + path->lineTo(577379, 1977.77f); + path->quadTo(577364, 1979.57f, 577325, 1980.26f); + path->quadTo(577286, 1980.95f, 577245, 1980.13f); + path->quadTo(577205, 1979.3f, 577187, 1977.45f); + path->quadTo(577168, 1975.6f, 577183, 1973.8f); + path->quadTo(577198, 1972, 577238, 1971.31f); + path->quadTo(577277, 1970.62f, 577317, 1971.45f); + path->quadTo(577330, 1971.72f, 577341, 1972.11f); + path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f); + path->moveTo(306.718f, -32.912f); + path->cubicTo(30.531f, 10.0005f, 1502.47f, 13.2804f, 84.3088f, 9.99601f); + } +} + +static void test_clipped_cubic(skiatest::Reporter* reporter) { + SkAutoTUnref surface(new_surface(640, 480)); + + // This path used to assert, because our cubic-chopping code incorrectly + // moved control points after the chop. This test should be run in SK_DEBUG + // mode to ensure that we no long assert. + SkPath path; + for (int doReducedCase = 0; doReducedCase <= 1; ++doReducedCase) { + build_big_path(&path, SkToBool(doReducedCase)); + + SkPaint paint; + for (int doAA = 0; doAA <= 1; ++doAA) { + paint.setAntiAlias(SkToBool(doAA)); + surface->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 @@ -2214,6 +2253,7 @@ static void TestPath(skiatest::Reporter* reporter) { test_arb_round_rect_is_convex(reporter); test_arb_zero_rad_round_rect_is_rect(reporter); test_addrect_isfinite(reporter); + test_clipped_cubic(reporter); } #include "TestClassDef.h" -- 2.7.4