fail on extremely large coincident curves

TBR=
BUG=418381

Author: caryclark@google.com

Review URL: https://codereview.chromium.org/607913007
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index 2dda11a..95046e2 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -1211,7 +1211,7 @@
     } while (++index < endIndex);
 }
 
-void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
+bool SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
         SkTArray<SkPoint, true>* outsideTs) {
     int index = *indexPtr;
     int oWindValue = oTest.fWindValue;
@@ -1223,12 +1223,16 @@
     SkOpSpan* end = test;
     const SkPoint& oStartPt = oTest.fPt;
     do {
+        if (end->fDone && !end->fTiny && !end->fSmall) {  // extremely large paths trigger this
+            return false;
+        }
         if (bumpSpan(end, oWindValue, oOppValue)) {
             TrackOutside(outsideTs, oStartPt);
         }
         end = &fTs[++index];
     } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && end->fT < 1);
     *indexPtr = index;
+    return true;
 }
 
 void SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) {
@@ -1329,10 +1333,14 @@
             } while (*oTestPt == other->fTs[oIndex].fPt);
         } else {
             if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
-                bumpCoincidentThis(*oTest, binary, &index, &outsidePts);
+                if (!bumpCoincidentThis(*oTest, binary, &index, &outsidePts)) {
+                    return false;
+                }
                 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
             } else {
-                other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
+                if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts)) {
+                    return false;
+                }
                 bumpCoincidentOther(*oTest, &index, &outsidePts);
             }
         }
@@ -1396,7 +1404,9 @@
                 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
                     other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
                 } else {
-                    other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
+                    if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts)) {
+                        return false;
+                    }
                 }
                 oTest = &other->fTs[oIndex];
                 oTestPt = &oTest->fPt;
diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h
index 24d08bd..4c35ac7 100644
--- a/src/pathops/SkOpSegment.h
+++ b/src/pathops/SkOpSegment.h
@@ -407,7 +407,7 @@
                    const SkOpSegment* other2, SkOpSpan* oSpan, SkTDArray<AlignedSpan>* );
     bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const;
     void bumpCoincidentBlind(bool binary, int index, int last);
-    void bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index,
+    bool bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index,
                            SkTArray<SkPoint, true>* outsideTs);
     void bumpCoincidentOBlind(int index, int last);
     void bumpCoincidentOther(const SkOpSpan& oTest, int* index,
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 4977b28..f0fea76 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -3899,7 +3899,34 @@
     testPathFailOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
+static void fuzz714(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path;
+    path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x430c0000), SkBits2Float(0x42200000));
+path.lineTo(SkBits2Float(0x43480000), SkBits2Float(0x43520000));
+path.lineTo(SkBits2Float(0x42200000), SkBits2Float(0x42c80000));
+path.lineTo(SkBits2Float(0x64969569), SkBits2Float(0x42c80000));
+path.lineTo(SkBits2Float(0x64969569), SkBits2Float(0x43520000));
+path.lineTo(SkBits2Float(0x430c0000), SkBits2Float(0x42200000));
+path.close();
+
+    SkPath path1(path);
+    path.reset();
+    path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x43200000), SkBits2Float(0x42700000));
+path.lineTo(SkBits2Float(0x435c0000), SkBits2Float(0x43660000));
+path.lineTo(SkBits2Float(0x42700000), SkBits2Float(0x42f00000));
+path.lineTo(SkBits2Float(0x64969569), SkBits2Float(0x42f00000));
+path.lineTo(SkBits2Float(0x64969569), SkBits2Float(0x43660000));
+path.lineTo(SkBits2Float(0x43200000), SkBits2Float(0x42700000));
+path.close();
+
+    SkPath path2(path);
+    testPathFailOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
 static struct TestDesc failTests[] = {
+    TEST(fuzz714),
     TEST(fuzz487a),
     TEST(fuzz487b),
     TEST(fuzz433b),