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
This commit is contained in:
reed@google.com 2011-03-21 20:33:42 +00:00
parent 918261018f
commit 160f2c0e17

View File

@ -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 {