aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkLineClipper.cpp
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-03-21 20:33:42 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-03-21 20:33:42 +0000
commit160f2c0e1724003767dbbea05bc8046ac5dd78d4 (patch)
tree3e1a94922a7c6974652b54e60706d8395f1ce89a /src/core/SkLineClipper.cpp
parent918261018f7a7754a5e7f0fbb6ec96f9b269fd26 (diff)
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
Diffstat (limited to 'src/core/SkLineClipper.cpp')
-rw-r--r--src/core/SkLineClipper.cpp43
1 files 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 {