Enabling the canvas bit to turn the clip stack into a flat replace exposed around 100 failures when testing the 800K skp set generated from the top 1M web sites.

This fixes all but one of those failures.

Major changes include:
- Replace angle indices with angle pointers. This was motivated by the need to add angles later but not renumber existing angles.
- Aggressive segment chase. When the winding is known on a segment, more aggressively passing that winding to adjacent segments allows fragmented data sets to succeed.
- Line segments with ends nearly the same are treated as coincident first.
- Transfer partial coincidence by observing that if segment A is partially coincident to B and C then B and C may be partially coincident.

TBR=reed

Author: caryclark@google.com

Review URL: https://codereview.chromium.org/272153002
diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h
index 7fad7a4..d1b3cd0 100644
--- a/src/pathops/SkOpContour.h
+++ b/src/pathops/SkOpContour.h
@@ -22,7 +22,8 @@
     SkOpContour* fOther;
     int fSegments[2];
     double fTs[2][2];
-    SkPoint fPts[2];
+    SkPoint fPts[2][2];
+    int fNearly[2];
 };
 
 class SkOpContour {
@@ -86,6 +87,28 @@
         return fSegments[segIndex].addSelfT(pt, newT);
     }
 
+    void align(const SkOpSegment::AlignedSpan& aligned, bool swap, SkCoincidence* coincidence);
+    void alignCoincidence(const SkOpSegment::AlignedSpan& aligned,
+            SkTArray<SkCoincidence, true>* coincidences);
+
+    void alignCoincidence(const SkOpSegment::AlignedSpan& aligned) {
+        alignCoincidence(aligned, &fCoincidences);
+        alignCoincidence(aligned, &fPartialCoincidences);
+    }
+
+    void alignMultiples(SkTDArray<SkOpSegment::AlignedSpan>* aligned) {
+        int segmentCount = fSegments.count();
+        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
+            SkOpSegment& segment = fSegments[sIndex];
+            if (segment.hasMultiples()) {
+                segment.alignMultiples(aligned);
+            }
+        }
+    }
+
+    void alignTPt(int segmentIndex, const SkOpContour* other, int otherIndex,
+                  bool swap, int tIndex, SkIntersections* ts, SkPoint* point) const;
+
     const SkPathOpsBounds& bounds() const {
         return fBounds;
     }
@@ -127,6 +150,7 @@
             SkOpSegment& segment = fSegments[sIndex];
             if (segment.count() > 2) {
                 segment.checkMultiples();
+                fMultiples |= segment.hasMultiples();
             }
         }
     }
@@ -135,6 +159,7 @@
         int segmentCount = fSegments.count();
         for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
             SkOpSegment& segment = fSegments[sIndex];
+            // OPTIMIZATION : skip segments that are done?
             if (segment.hasSmall()) {
                 segment.checkSmall();
             }
@@ -189,6 +214,10 @@
         }
     }
 
+    bool hasMultiples() const {
+        return fMultiples;
+    }
+
     void joinCoincidence() {
         joinCoincidence(fCoincidences, false);
         joinCoincidence(fPartialCoincidences, true);
@@ -203,9 +232,11 @@
     void reset() {
         fSegments.reset();
         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
-        fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
+        fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = fMultiples = false;
     }
 
+    void resolveNearCoincidence();
+
     SkTArray<SkOpSegment>& segments() {
         return fSegments;
     }
@@ -284,11 +315,19 @@
     // available to test routines only
     void dump() const;
     void dumpAngles() const;
+    void dumpCoincidence(const SkCoincidence& ) const;
+    void dumpCoincidences() const;
+    void dumpPt(int ) const;
     void dumpPts() const;
+    void dumpSpan(int ) const;
     void dumpSpans() const;
 
 private:
+    void alignPt(int index, SkPoint* point, int zeroPt) const;
+    int alignT(bool swap, int tIndex, SkIntersections* ts) const;
     void calcCommonCoincidentWinding(const SkCoincidence& );
+    void checkCoincidentPair(const SkCoincidence& oneCoin, int oneIdx,
+                             const SkCoincidence& twoCoin, int twoIdx, bool partial);
     void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial);
     void setBounds();
 
@@ -303,6 +342,7 @@
     bool fContainsCubics;
     bool fContainsCurves;
     bool fDone;
+    bool fMultiples;  // set if some segment has multiple identical intersections with other curves
     bool fOperand;  // true for the second argument to a binary operator
     bool fXor;
     bool fOppXor;