add convexity logic and tests for scalar max, Inf, and NaN
PathOps relies on isConvex() only returning true for trivially
convex paths. The old logic also returns true if the paths that
contain NaNs and Infinities. Return kUnknown_Convexity instead
in those cases and in cases where the convexity logic computes
intermediaries that overflow.
Review URL: https://codereview.chromium.org/784593002
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 25fd058..a08abbd 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -2215,7 +2215,8 @@
Convexicator()
: fPtCount(0)
, fConvexity(SkPath::kConvex_Convexity)
- , fDirection(SkPath::kUnknown_Direction) {
+ , fDirection(SkPath::kUnknown_Direction)
+ , fIsFinite(true) {
fExpectedDir = kInvalid_DirChange;
// warnings
fLastPt.set(0, 0);
@@ -2233,7 +2234,7 @@
SkPath::Direction getDirection() const { return fDirection; }
void addPt(const SkPoint& pt) {
- if (SkPath::kConcave_Convexity == fConvexity) {
+ if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) {
return;
}
@@ -2242,7 +2243,10 @@
++fPtCount;
} else {
SkVector vec = pt - fCurrPt;
- if (!SkScalarNearlyZero(vec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero)) {
+ SkScalar lengthSqd = vec.lengthSqd();
+ if (!SkScalarIsFinite(lengthSqd)) {
+ fIsFinite = false;
+ } else if (!SkScalarNearlyZero(lengthSqd, SK_ScalarNearlyZero*SK_ScalarNearlyZero)) {
fLastPt = fCurrPt;
fCurrPt = pt;
if (++fPtCount == 2) {
@@ -2272,6 +2276,10 @@
}
}
+ bool isFinite() const {
+ return fIsFinite;
+ }
+
private:
void addVec(const SkVector& vec) {
SkASSERT(vec.fX || vec.fY);
@@ -2310,6 +2318,7 @@
SkPath::Convexity fConvexity;
SkPath::Direction fDirection;
int fDx, fDy, fSx, fSy;
+ bool fIsFinite;
};
SkPath::Convexity SkPath::internalGetConvexity() const {
@@ -2322,6 +2331,9 @@
int count;
Convexicator state;
+ if (!isFinite()) {
+ return kUnknown_Convexity;
+ }
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case kMove_Verb:
@@ -2350,6 +2362,9 @@
state.addPt(pts[i]);
}
// early exit
+ if (!state.isFinite()) {
+ return kUnknown_Convexity;
+ }
if (kConcave_Convexity == state.getConvexity()) {
fConvexity = kConcave_Convexity;
return kConcave_Convexity;