Bug 941585: Better dealing with degenerate beziers. r=jrmuizel

This commit is contained in:
Bas Schouten 2014-01-09 17:04:17 +01:00
parent 2d18c11e26
commit 7bf6b36b0e

View File

@ -219,17 +219,6 @@ SplitBezier(const BezierControlPoints &aControlPoints,
aSecondSegmentControlPoints->mCP1 = cp1aaa; aSecondSegmentControlPoints->mCP1 = cp1aaa;
aSecondSegmentControlPoints->mCP2 = cp2aa; aSecondSegmentControlPoints->mCP2 = cp2aa;
aSecondSegmentControlPoints->mCP3 = cp3a; aSecondSegmentControlPoints->mCP3 = cp3a;
// Ensure the result is a nice cubic bezier.
if (aSecondSegmentControlPoints->mCP1 == aSecondSegmentControlPoints->mCP2 ||
aSecondSegmentControlPoints->mCP2 == aSecondSegmentControlPoints->mCP3) {
aSecondSegmentControlPoints->mCP2 = aSecondSegmentControlPoints->mCP1 +
(aSecondSegmentControlPoints->mCP3 - aSecondSegmentControlPoints->mCP1) *
Float(2. / 3.);
aSecondSegmentControlPoints->mCP3 = aControlPoints.mCP4 +
(aSecondSegmentControlPoints->mCP3 - aControlPoints.mCP4) *
Float(2. / 3.);
}
} }
static void static void
@ -278,9 +267,16 @@ FindInflectionApproximationRange(BezierControlPoints aControlPoints,
Point cp21 = aControlPoints.mCP2 - aControlPoints.mCP1; Point cp21 = aControlPoints.mCP2 - aControlPoints.mCP1;
Point cp41 = aControlPoints.mCP4 - aControlPoints.mCP1; Point cp41 = aControlPoints.mCP4 - aControlPoints.mCP1;
Float s4 = (cp41.x * cp21.y - cp41.y * cp21.x) / hypotf(cp21.x, cp21.y); if (!cp21.x && !cp21.y) {
// In this case s3 becomes lim[n->0] (cp41.x * n) / n - (cp41.y * n) / n = cp41.x - cp41.y.
*aMin = aT - pow(aTolerance / (cp41.x - cp41.y), Float(1. / 3.));
*aMax = aT + pow(aTolerance / (cp41.x - cp41.y), Float(1. / 3.));;
return;
}
Float tf = pow(abs(aTolerance / s4), Float(1. / 3.)); Float s3 = (cp41.x * cp21.y - cp41.y * cp21.x) / hypotf(cp21.x, cp21.y);
Float tf = pow(abs(aTolerance / s3), Float(1. / 3.));
*aMin = aT - tf * (1 - aT); *aMin = aT - tf * (1 - aT);
*aMax = aT + tf * (1 - aT); *aMax = aT + tf * (1 - aT);
@ -367,6 +363,9 @@ FindInflectionPoints(const BezierControlPoints &aControlPoints,
if (discriminant < 0) { if (discriminant < 0) {
// No inflection points. // No inflection points.
*aCount = 0; *aCount = 0;
} else if (discriminant == 0) {
*aCount = 1;
*aT1 = -b / (2 * a);
} else { } else {
/* Use the following formula for computing the roots: /* Use the following formula for computing the roots:
* *
@ -419,10 +418,10 @@ FlattenBezier(const BezierControlPoints &aControlPoints,
// For both inflection points, calulate the range where they can be linearly // For both inflection points, calulate the range where they can be linearly
// approximated if they are positioned within [0,1] // approximated if they are positioned within [0,1]
if (count > 0 && t1 >= 0 && t1 <= 1.0) { if (count > 0 && t1 >= 0 && t1 < 1.0) {
FindInflectionApproximationRange(aControlPoints, &t1min, &t1max, t1, aTolerance); FindInflectionApproximationRange(aControlPoints, &t1min, &t1max, t1, aTolerance);
} }
if (count > 1 && t2 >= 0 && t2 <= 1.0) { if (count > 1 && t2 >= 0 && t2 < 1.0) {
FindInflectionApproximationRange(aControlPoints, &t2min, &t2max, t2, aTolerance); FindInflectionApproximationRange(aControlPoints, &t2min, &t2max, t2, aTolerance);
} }
BezierControlPoints nextCPs = aControlPoints; BezierControlPoints nextCPs = aControlPoints;
@ -430,7 +429,6 @@ FlattenBezier(const BezierControlPoints &aControlPoints,
// Process ranges. [t1min, t1max] and [t2min, t2max] are approximated by line // Process ranges. [t1min, t1max] and [t2min, t2max] are approximated by line
// segments. // segments.
if (t1min < 1.0 && t1max > 0) {
if (t1min > 0) { if (t1min > 0) {
// Flatten the Bezier up until the first inflection point's approximation // Flatten the Bezier up until the first inflection point's approximation
// point. // point.
@ -446,7 +444,7 @@ FlattenBezier(const BezierControlPoints &aControlPoints,
aSink->LineTo(nextCPs.mCP1); aSink->LineTo(nextCPs.mCP1);
if (count > 1 && t2min > 1.0) { if (count == 1 || (count > 1 && t2min >= 1.0)) {
// No more inflection points to deal with, flatten the rest of the curve. // No more inflection points to deal with, flatten the rest of the curve.
FlattenBezierCurveSegment(nextCPs, aSink, aTolerance); FlattenBezierCurveSegment(nextCPs, aSink, aTolerance);
} }
@ -457,7 +455,7 @@ FlattenBezier(const BezierControlPoints &aControlPoints,
aSink->LineTo(aControlPoints.mCP4); aSink->LineTo(aControlPoints.mCP4);
return; return;
} }
}
if (count > 1 && t2min < 1.0 && t2max > 0) { if (count > 1 && t2min < 1.0 && t2max > 0) {
if (t2min > 0 && t2min < t1max) { if (t2min > 0 && t2min < t1max) {
// In this case the t2 approximation range starts inside the t1 // In this case the t2 approximation range starts inside the t1