http://code.google.com/p/skia/issues/detail?id=32
Detect when we no longer have a valid range for chopping due to finite float
precision, and just return a degenerate cubic at the end.
git-svn-id: http://skia.googlecode.com/svn/trunk/src@341 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/core/SkGeometry.cpp b/core/SkGeometry.cpp
index 229c3d8..2775543 100644
--- a/core/SkGeometry.cpp
+++ b/core/SkGeometry.cpp
@@ -505,6 +505,29 @@
interp_cubic_coords(&src[0].fY, &dst[0].fY, t);
}
+/* http://code.google.com/p/skia/issues/detail?id=32
+
+ This test code would fail when we didn't check the return result of
+ valid_unit_divide in SkChopCubicAt(... tValues[], int roots). The reason is
+ that after the first chop, the parameters to valid_unit_divide are equal
+ (thanks to finite float precision and rounding in the subtracts). Thus
+ even though the 2nd tValue looks < 1.0, after we renormalize it, we end
+ up with 1.0, hence the need to check and just return the last cubic as
+ a degenerate clump of 4 points in the sampe place.
+
+ static void test_cubic() {
+ SkPoint src[4] = {
+ { 556.25000, 523.03003 },
+ { 556.23999, 522.96002 },
+ { 556.21997, 522.89001 },
+ { 556.21997, 522.82001 }
+ };
+ SkPoint dst[10];
+ SkScalar tval[] = { 0.33333334f, 0.99999994f };
+ SkChopCubicAt(src, dst, tval, 2);
+ }
+ */
+
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[], const SkScalar tValues[], int roots)
{
#ifdef SK_DEBUG
@@ -533,12 +556,18 @@
if (i == roots - 1)
break;
- SkDEBUGCODE(int valid =) valid_unit_divide(tValues[i+1] - tValues[i], SK_Scalar1 - tValues[i], &t);
- SkASSERT(valid);
-
dst += 3;
+ // have src point to the remaining cubic (after the chop)
memcpy(tmp, dst, 4 * sizeof(SkPoint));
src = tmp;
+
+ // watch out in case the renormalized t isn't in range
+ if (!valid_unit_divide(tValues[i+1] - tValues[i],
+ SK_Scalar1 - tValues[i], &t)) {
+ // if we can't, just create a degenerate cubic
+ dst[4] = dst[5] = dst[6] = src[3];
+ break;
+ }
}
}
}