Make cross_prod used in SkPath::cheapComputeDirection fallback to double computation...
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 17 Feb 2012 13:38:26 +0000 (13:38 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 17 Feb 2012 13:38:26 +0000 (13:38 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@3216 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkPath.cpp
tests/PathTest.cpp

index b37342f3c952db773023f67176c3e8ada8e17716..4b3505a1606bd41d0eb1699e8c41c7e02baee64d 100644 (file)
@@ -1909,8 +1909,26 @@ CONTOUR_END:
     SkDEBUGCODE(++fContourCounter;)
 }
 
+// returns cross product of (p1 - p0) and (p2 - p0)
 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
-    return SkPoint::CrossProduct(p1 - p0, p2 - p0);
+    SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
+    // We may get 0 when the above subtracts underflow. We expect this to be
+    // very rare and lazily promote to double.
+    if (0 == cross) {
+        double p0x = SkScalarToDouble(p0.fX);
+        double p0y = SkScalarToDouble(p0.fY);
+
+        double p1x = SkScalarToDouble(p1.fX);
+        double p1y = SkScalarToDouble(p1.fY);
+
+        double p2x = SkScalarToDouble(p2.fX);
+        double p2y = SkScalarToDouble(p2.fY);
+
+        cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
+                                 (p1y - p0y) * (p2x - p0x));
+
+    }
+    return cross;
 }
 
 // Returns the first pt with the maximum Y coordinate
index d156e5796d2a7dc609f8fb1b91224e7060ba987e..affc2232005f0d87f3e80a9e77e28aad78185305 100644 (file)
 #include "SkSize.h"
 #include "SkWriter32.h"
 
+/**
+ * cheapIsDirection can take a shortcut when a path is marked convex.
+ * This function ensures that we always test cheapIsDirection when the path
+ * is flagged with unknown convexity status.
+ */
+static void check_direction(SkPath* path,
+                            SkPath::Direction expectedDir,
+                            skiatest::Reporter* reporter) {
+    if (SkPath::kConvex_Convexity == path->getConvexity()) {
+        REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
+        path->setConvexity(SkPath::kUnknown_Convexity);
+    }
+    REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
+}
+
 static void test_direction(skiatest::Reporter* reporter) {
     size_t i;
     SkPath path;
@@ -46,7 +61,7 @@ static void test_direction(skiatest::Reporter* reporter) {
         path.reset();
         bool valid = SkParsePath::FromSVGString(gCW[i], &path);
         REPORTER_ASSERT(reporter, valid);
-        REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
+        check_direction(&path, SkPath::kCW_Direction, reporter);
     }
     
     static const char* gCCW[] = {
@@ -58,7 +73,7 @@ static void test_direction(skiatest::Reporter* reporter) {
         path.reset();
         bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
         REPORTER_ASSERT(reporter, valid);
-        REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
+        check_direction(&path, SkPath::kCCW_Direction, reporter);
     }
 
     // Test two donuts, each wound a different direction. Only the outer contour
@@ -66,12 +81,20 @@ static void test_direction(skiatest::Reporter* reporter) {
     path.reset();
     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
-    REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
-    
+    check_direction(&path, SkPath::kCW_Direction, reporter);
+
     path.reset();
     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
-    REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
+    check_direction(&path, SkPath::kCCW_Direction, reporter);
+
+    // triangle with one point really far from the origin.
+    path.reset();
+    // the first point is roughly 1.05e10, 1.05e10
+    path.moveTo(SkFloatToScalar(SkBits2Float(0x501c7652)), SkFloatToScalar(SkBits2Float(0x501c7652)));\r
+    path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);\r
+    path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);\r
+    check_direction(&path, SkPath::kCCW_Direction, reporter);\r
 }
 
 static void add_rect(SkPath* path, const SkRect& r) {