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
#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;
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[] = {
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
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) {