aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkLineClipper.cpp
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-04-17 14:43:38 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-04-17 14:43:38 +0000
commitbddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1 (patch)
tree1571a776af36d2e08fc169d32cbdc4223a9a34da /src/core/SkLineClipper.cpp
parent8a189b0632364ae0afda7d3a0e7e4aae7fce2ffe (diff)
we have to explicitly pin the results from sect_with_horizontal, since even with
doubles we can get the wrong results (computed X value outside of [start...stop]. added regression test inside the code fixes bug in Fuzzer samplecode git-svn-id: http://skia.googlecode.com/svn/trunk@3704 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkLineClipper.cpp')
-rw-r--r--src/core/SkLineClipper.cpp48
1 files changed, 47 insertions, 1 deletions
diff --git a/src/core/SkLineClipper.cpp b/src/core/SkLineClipper.cpp
index 708d3a9bd8..ebd3bfa593 100644
--- a/src/core/SkLineClipper.cpp
+++ b/src/core/SkLineClipper.cpp
@@ -7,6 +7,21 @@
*/
#include "SkLineClipper.h"
+template <typename T> T pin_unsorted(T value, T limit0, T limit1) {
+ if (limit1 < limit0) {
+ SkTSwap(limit0, limit1);
+ }
+ // now the limits are sorted
+ SkASSERT(limit0 <= limit1);
+
+ if (value < limit0) {
+ value = limit0;
+ } else if (value > limit1) {
+ value = limit1;
+ }
+ return value;
+}
+
// return X coordinate of intersection with horizontal line at Y
static SkScalar sect_with_horizontal(const SkPoint src[2], SkScalar Y) {
SkScalar dy = src[1].fY - src[0].fY;
@@ -21,7 +36,11 @@ static SkScalar sect_with_horizontal(const SkPoint src[2], SkScalar Y) {
double X1 = src[1].fX;
double Y1 = src[1].fY;
double result = X0 + ((double)Y - Y0) * (X1 - X0) / (Y1 - Y0);
- return (float)result;
+
+ // The computed X value might still exceed [X0..X1] due to quantum flux
+ // when the doubles were added and subtracted, so we have to pin the
+ // answer :(
+ return (float)pin_unsorted(result, X0, X1);
#else
return src[0].fX + SkScalarMulDiv(Y - src[0].fY, src[1].fX - src[0].fX,
dy);
@@ -148,8 +167,35 @@ static bool is_between_unsorted(SkScalar value,
}
#endif
+#ifdef SK_SCALAR_IS_FLOAT
+// This is an example of why we need to pin the result computed in
+// sect_with_horizontal. If we didn't explicitly pin, is_between_unsorted would
+// fail.
+//
+static void sect_with_horizontal_test_for_pin_results() {
+ const SkPoint pts[] = {
+ { -540000, -720000 },
+ { -9.10000017e-05, 9.99999996e-13 }
+ };
+ float x = sect_with_horizontal(pts, 0);
+ SkASSERT(is_between_unsorted(x, pts[0].fX, pts[1].fX));
+}
+#endif
+
int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
SkPoint lines[]) {
+#ifdef SK_SCALAR_IS_FLOAT
+#ifdef SK_DEBUG
+ {
+ static bool gOnce;
+ if (!gOnce) {
+ sect_with_horizontal_test_for_pin_results();
+ gOnce = true;
+ }
+ }
+#endif
+#endif
+
int index0, index1;
if (pts[0].fY < pts[1].fY) {