Index: src/core/SkPath.cpp |
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp |
index 738edd9d232c79ea40e9aab40653f5396e971e2f..b92b47f5c6b00f20315618c766b15aff89f0d609 100644 |
--- a/src/core/SkPath.cpp |
+++ b/src/core/SkPath.cpp |
@@ -2099,30 +2099,11 @@ static bool almost_equal(SkScalar compA, SkScalar compB) { |
return aBits < bBits + epsilon && bBits < aBits + epsilon; |
} |
-static DirChange direction_change(const SkPoint& lastPt, const SkVector& curPt, |
- const SkVector& lastVec, const SkVector& curVec) { |
- SkScalar cross = SkPoint::CrossProduct(lastVec, curVec); |
- |
- SkScalar smallest = SkTMin(curPt.fX, SkTMin(curPt.fY, SkTMin(lastPt.fX, lastPt.fY))); |
- SkScalar largest = SkTMax(curPt.fX, SkTMax(curPt.fY, SkTMax(lastPt.fX, lastPt.fY))); |
- largest = SkTMax(largest, -smallest); |
- |
- if (!almost_equal(largest, largest + cross)) { |
- int sign = SkScalarSignAsInt(cross); |
- if (sign) { |
- return (1 == sign) ? kRight_DirChange : kLeft_DirChange; |
- } |
- } |
- |
- if (!SkScalarNearlyZero(lastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) && |
- !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) && |
- lastVec.dot(curVec) < 0.0f) { |
- return kBackwards_DirChange; |
- } |
- |
- return kStraight_DirChange; |
+static bool approximately_zero_when_compared_to(double x, double y) { |
+ return x == 0 || fabs(x) < fabs(y * FLT_EPSILON); |
} |
+ |
// only valid for a single contour |
struct Convexicator { |
Convexicator() |
@@ -2161,6 +2142,7 @@ struct Convexicator { |
if (!SkScalarIsFinite(lengthSqd)) { |
fIsFinite = false; |
} else if (!SkScalarNearlyZero(lengthSqd, SK_ScalarNearlyZero*SK_ScalarNearlyZero)) { |
+ fPriorPt = fLastPt; |
fLastPt = fCurrPt; |
fCurrPt = pt; |
if (++fPtCount == 2) { |
@@ -2190,6 +2172,44 @@ struct Convexicator { |
} |
} |
+ DirChange directionChange(const SkVector& curVec) { |
+ SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec); |
+ |
+ SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY))); |
+ SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY))); |
+ largest = SkTMax(largest, -smallest); |
+ |
+ if (!almost_equal(largest, largest + cross)) { |
+ int sign = SkScalarSignAsInt(cross); |
+ if (sign) { |
+ return (1 == sign) ? kRight_DirChange : kLeft_DirChange; |
+ } |
+ } |
+ |
+ if (cross) { |
+ double dLastVecX = SkScalarToDouble(fLastPt.fX) - SkScalarToDouble(fPriorPt.fX); |
+ double dLastVecY = SkScalarToDouble(fLastPt.fY) - SkScalarToDouble(fPriorPt.fY); |
+ double dCurrVecX = SkScalarToDouble(fCurrPt.fX) - SkScalarToDouble(fLastPt.fX); |
+ double dCurrVecY = SkScalarToDouble(fCurrPt.fY) - SkScalarToDouble(fLastPt.fY); |
+ double dCross = dLastVecX * dCurrVecY - dLastVecY * dCurrVecX; |
+ if (!approximately_zero_when_compared_to(dCross, SkScalarToDouble(largest))) { |
+ int sign = SkScalarSignAsInt(SkDoubleToScalar(dCross)); |
+ if (sign) { |
+ return (1 == sign) ? kRight_DirChange : kLeft_DirChange; |
+ } |
+ } |
+ } |
+ |
+ if (!SkScalarNearlyZero(fLastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) && |
+ !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) && |
+ fLastVec.dot(curVec) < 0.0f) { |
+ return kBackwards_DirChange; |
+ } |
+ |
+ return kStraight_DirChange; |
+ } |
+ |
+ |
bool isFinite() const { |
return fIsFinite; |
} |
@@ -2201,7 +2221,7 @@ struct Convexicator { |
private: |
void addVec(const SkVector& vec) { |
SkASSERT(vec.fX || vec.fY); |
- DirChange dir = direction_change(fLastPt, fCurrPt, fLastVec, vec); |
+ DirChange dir = this->directionChange(vec); |
switch (dir) { |
case kLeft_DirChange: // fall through |
case kRight_DirChange: |
@@ -2230,6 +2250,7 @@ private: |
} |
} |
+ SkPoint fPriorPt; |
SkPoint fLastPt; |
SkPoint fCurrPt; |
// fLastVec does not necessarily start at fLastPt. We only advance it when the cross product |