From 160f2c0e1724003767dbbea05bc8046ac5dd78d4 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Mon, 21 Mar 2011 20:33:42 +0000 Subject: [PATCH] increase intermediate precision when chopping lines. This avoids returning a computed value that is accidentally outside of the original range. git-svn-id: http://skia.googlecode.com/svn/trunk@971 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/core/SkLineClipper.cpp | 43 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/core/SkLineClipper.cpp b/src/core/SkLineClipper.cpp index 057f546d77..ab497731cc 100644 --- a/src/core/SkLineClipper.cpp +++ b/src/core/SkLineClipper.cpp @@ -6,8 +6,19 @@ static SkScalar sect_with_horizontal(const SkPoint src[2], SkScalar Y) { if (SkScalarNearlyZero(dy)) { return SkScalarAve(src[0].fX, src[1].fX); } else { +#ifdef SK_SCALAR_IS_FLOAT + // need the extra precision so we don't compute a value that exceeds + // our original limits + double X0 = src[0].fX; + double Y0 = src[0].fY; + double X1 = src[1].fX; + double Y1 = src[1].fY; + double result = X0 + ((double)Y - Y0) * (X1 - X0) / (Y1 - Y0); + return (float)result; +#else return src[0].fX + SkScalarMulDiv(Y - src[0].fY, src[1].fX - src[0].fX, dy); +#endif } } @@ -17,8 +28,19 @@ static SkScalar sect_with_vertical(const SkPoint src[2], SkScalar X) { if (SkScalarNearlyZero(dx)) { return SkScalarAve(src[0].fY, src[1].fY); } else { +#ifdef SK_SCALAR_IS_FLOAT + // need the extra precision so we don't compute a value that exceeds + // our original limits + double X0 = src[0].fX; + double Y0 = src[0].fY; + double X1 = src[1].fX; + double Y1 = src[1].fY; + double result = Y0 + ((double)X - X0) * (Y1 - Y0) / (X1 - X0); + return (float)result; +#else return src[0].fY + SkScalarMulDiv(X - src[0].fX, src[1].fY - src[0].fY, dx); +#endif } } @@ -106,6 +128,19 @@ bool SkLineClipper::IntersectLine(const SkPoint src[2], const SkRect& clip, return true; } +#ifdef SK_DEBUG +// return value between the two limits, where the limits are either ascending +// or descending. +static bool is_between_unsorted(SkScalar value, + SkScalar limit0, SkScalar limit1) { + if (limit0 < limit1) { + return limit0 <= value && value <= limit1; + } else { + return limit1 <= value && value <= limit0; + } +} +#endif + int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip, SkPoint lines[]) { int index0, index1; @@ -135,9 +170,11 @@ int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip, // now compute intersections if (pts[index0].fY < clip.fTop) { tmp[index0].set(sect_with_horizontal(pts, clip.fTop), clip.fTop); + SkASSERT(is_between_unsorted(tmp[index0].fX, pts[0].fX, pts[1].fX)); } if (tmp[index1].fY > clip.fBottom) { tmp[index1].set(sect_with_horizontal(pts, clip.fBottom), clip.fBottom); + SkASSERT(is_between_unsorted(tmp[index1].fX, pts[0].fX, pts[1].fX)); } // Chop it into 1..3 segments that are wholly within the clip in X. @@ -173,14 +210,16 @@ int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip, if (tmp[index0].fX < clip.fLeft) { r->set(clip.fLeft, tmp[index0].fY); r += 1; - r->set(clip.fLeft, sect_with_vertical(pts, clip.fLeft)); + r->set(clip.fLeft, sect_with_vertical(tmp, clip.fLeft)); + SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY)); } else { *r = tmp[index0]; } r += 1; if (tmp[index1].fX > clip.fRight) { - r->set(clip.fRight, sect_with_vertical(pts, clip.fRight)); + r->set(clip.fRight, sect_with_vertical(tmp, clip.fRight)); + SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY)); r += 1; r->set(clip.fRight, tmp[index1].fY); } else {