shape ops work in progress

git-svn-id: http://skia.googlecode.com/svn/trunk@6537 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp
index 3f4adf5..366aa8b 100644
--- a/experimental/Intersection/Simplify.cpp
+++ b/experimental/Intersection/Simplify.cpp
@@ -43,6 +43,7 @@
 #define DEBUG_CROSS 0
 #define DEBUG_MARK_DONE 0
 #define DEBUG_PATH_CONSTRUCTION 0
+#define DEBUG_SHOW_WINDING 0
 #define DEBUG_SORT 0
 #define DEBUG_WIND_BUMP 0
 #define DEBUG_WINDING 0
@@ -59,6 +60,7 @@
 #define DEBUG_CROSS 0
 #define DEBUG_MARK_DONE 1
 #define DEBUG_PATH_CONSTRUCTION 1
+#define DEBUG_SHOW_WINDING 0
 #define DEBUG_SORT 1
 #define DEBUG_WIND_BUMP 0
 #define DEBUG_WINDING 1
@@ -1470,8 +1472,8 @@
     }
 
     int bumpCoincidentThis(const Span* oTest, const bool transfer, const bool decrementThis,
-            const bool thisXor, const bool opp, int index, SkTDArray<double>& outsideTs,
-            SkTDArray<double>& xOutsideTs)
+            const bool thisXor, const int oXorMask, const bool opp, int index,
+            SkTDArray<double>& outsideTs, SkTDArray<double>& xOutsideTs)
     {
         Span* const test = &fTs[index];
         Span* end = test;
@@ -1481,11 +1483,18 @@
             if (transfer) {
                 if (opp) {
                     if (decrementThis) {
-                        zeroSpan(end);
+                        zeroSpan(end, oStartT);
                         TrackOutside(outsideTs, end->fT, oStartT);
                     } else {
                         end->fWindValue += oTest->fOppValue;
-                        end->fOppValue += oTest->fWindValue;
+                        end->fOppValue = (end->fOppValue + oTest->fWindValue) & oXorMask;
+                        if (thisXor) {
+                            SkASSERT(end->fWindValue);
+                            if (!(end->fWindValue & 1)) {
+                                zeroSpan(end, oStartT);
+                                TrackOutside(outsideTs, end->fT, oStartT);
+                            }
+                        }
                     }
                 } else if (!decrementThis & !thisXor) {
             #ifdef SK_DEBUG
@@ -1511,8 +1520,8 @@
     // intermediate T values (using this as the master, other as the follower)
     // and walk other conditionally -- hoping that it catches up in the end
     int bumpCoincidentOther(const Span* test, const bool transfer, const bool decrementThis,
-            const bool otherXor, const bool opp, const double tRatio, const double oEndT,
-            int& oIndex, SkTDArray<double>& oOutsideTs)
+            const bool otherXor, const int xorMask, const bool opp, const double tRatio,
+            const double oEndT, int& oIndex, SkTDArray<double>& oOutsideTs)
     {
         Span* const oTest = &fTs[oIndex];
         Span* oEnd = oTest;
@@ -1526,12 +1535,19 @@
                 if (opp) {
                     if (decrementThis) {
                         oEnd->fWindValue += test->fOppValue;
-                        oEnd->fOppValue += test->fWindValue;
+                        oEnd->fOppValue = (oEnd->fOppValue + test->fWindValue) & xorMask;
+                        if (otherXor) {
+                            SkASSERT(oEnd->fWindValue);
+                            if (!(oEnd->fWindValue & 1)) {
+                                zeroSpan(oEnd, startT);
+                                TrackOutside(oOutsideTs, oEnd->fT, startT);
+                            }
+                        }
                     } else {
-                        zeroSpan(oEnd);
+                        zeroSpan(oEnd, startT);
                         TrackOutside(oOutsideTs, oEnd->fT, startT);
                     }
-                } else if (decrementThis & !otherXor & !opp) {
+                } else if (decrementThis & !otherXor) {
              #ifdef SK_DEBUG
                    SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue);
             #endif
@@ -1581,19 +1597,22 @@
         SkTDArray<double> outsideTs;
         SkTDArray<double> xOutsideTs;
         SkTDArray<double> oOutsideTs;
+        int xorMask = thisXor ? 1 : -1;
+        int oXorMask = otherXor ? 1 : -1;
         do {
             bool transfer = test->fWindValue && oTest->fWindValue;
-            bool decrementThis = test->fWindValue < oTest->fWindValue;
+            bool decrementThis = test->fWindValue < oTest->fWindValue ||
+                    (test->fWindValue == oTest->fWindValue && thisXor);
             if (decrementThis) {
-                oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, opp,
-                        tRatio, oEndT, oIndex, oOutsideTs);
-                index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, opp,
+                oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, xorMask,
+                        opp, tRatio, oEndT, oIndex, oOutsideTs);
+                index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, oXorMask, opp,
                         index, outsideTs, xOutsideTs);
             } else {
-                index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, opp,
+                index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, oXorMask, opp,
                         index, outsideTs, xOutsideTs);
-                oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, opp,
-                        tRatio, oEndT, oIndex, oOutsideTs);
+                oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, xorMask,
+                        opp, tRatio, oEndT, oIndex, oOutsideTs);
             }
             test = &fTs[index];
             oTest = &other.fTs[oIndex];
@@ -1735,9 +1754,11 @@
         if (inner) {
             winding += spanWinding;
         }
-        int oppoWinding = base->oppSign(angle);
-        if (useInnerWinding(oWinding + oppoWinding, oWinding)) {
-            oWinding += oppoWinding;
+        if (oppoSum) {
+            int oppoWinding = base->oppSign(angle);
+            if (useInnerWinding(oWinding + oppoWinding, oWinding)) {
+                oWinding += oppoWinding;
+            }
         }
     #if DEBUG_SORT
         base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
@@ -1759,15 +1780,15 @@
             if (opp) {
                 oMaxWinding = oWinding;
                 oWinding -= spanSign;
+                maxWinding = winding;
                 if (oppoSign) {
-                    maxWinding = winding;
                     winding -= oppoSign;
                 }
             } else {
                 maxWinding = winding;
                 winding -= spanSign;
+                oMaxWinding = oWinding;
                 if (oppoSign) {
-                    oMaxWinding = oWinding;
                     oWinding -= oppoSign;
                 }
             }
@@ -1787,7 +1808,7 @@
                     if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
                         oMaxWinding = oWinding;
                     }
-                    segment->markAndChaseWinding(angle, maxWinding, oMaxWinding);
+                    segment->markAndChaseWinding(angle, maxWinding, oppoSum ? oMaxWinding : 0);
                 }
             }
         } while (++nextIndex != lastIndex);
@@ -2079,7 +2100,7 @@
                     foundFlipped = altFlipped;
                     foundSum = 0;
                     foundOpp = angleIsOp;
-                    foundOppWinding = oMaxWinding;
+                    foundOppWinding = oSumWinding;
                 }
                 continue;
             }
@@ -3135,7 +3156,7 @@
         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
         fTs.reset();
     }
-
+    
     // This marks all spans unsortable so that this info is available for early
     // exclusion in find top and others. This could be optimized to only mark
     // adjacent spans that unsortable. However, this makes it difficult to later
@@ -3288,14 +3309,21 @@
         return xyAtT(span).fY;
     }
 
-    void zeroSpan(Span* span) {
+    void zeroSpan(Span* span, double otherT) {
         SkASSERT(span->fWindValue > 0);
         span->fWindValue = 0;
-        span->fOppValue = 0;
         if (!span->fDone) {
             span->fDone = true;
             ++fDoneSpans;
         }
+        int oppValue = span->fOppValue;
+        if (!oppValue) {
+            return;
+        }
+        span->fOppValue = 0;
+        Segment* other = span->fOther;
+        Span& oSpan = other->fTs[span->fOtherIndex];
+        SkASSERT(0);
     }
 
 #if DEBUG_DUMP
@@ -3563,7 +3591,9 @@
     static char as_digit(int value) {
         return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
     }
+#endif
 
+#if DEBUG_SHOW_WINDING
     int debugShowWindingValues(int slotCount, int ofInterest) const {
         if (!(1 << fID & ofInterest)) {
             return 0;
@@ -3585,7 +3615,9 @@
                 slots.begin() + slotCount);
         return sum;
     }
+#endif
 
+#if DEBUG_WINDING
     bool debugVerifyWinding(int start, int end, int winding) const {
         const Span& span = fTs[SkMin32(start, end)];
         int spanWinding = span.fWindSum;
@@ -3786,13 +3818,12 @@
         fContainsCurves = fContainsIntercepts = false;
     }
 
-    // FIXME: for binary ops, need to keep both ops winding contributions separately
-    // in edge array
     void resolveCoincidence(SkTDArray<Contour*>& contourList) {
         int count = fCoincidences.count();
         for (int index = 0; index < count; ++index) {
             Coincidence& coincidence = fCoincidences[index];
             Contour* thisContour = coincidence.fContours[0];
+            SkASSERT(thisContour == this);
             Contour* otherContour = coincidence.fContours[1];
             int thisIndex = coincidence.fSegments[0];
             int otherIndex = coincidence.fSegments[1];
@@ -3845,7 +3876,7 @@
             thisOne.debugShowTs();
             other.debugShowTs();
         #endif
-        #if DEBUG_WINDING
+        #if DEBUG_SHOW_WINDING
             debugShowWindingValues(contourList);
         #endif
         }
@@ -4037,7 +4068,7 @@
     }
 #endif
 
-#if DEBUG_WINDING
+#if DEBUG_SHOW_WINDING
     int debugShowWindingValues(int totalSegments, int ofInterest) {
         int count = fSegments.count();
         int sum = 0;
@@ -4116,7 +4147,7 @@
 void init() {
     fCurrentContour = NULL;
     fOperand = false;
-    fXorMask = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
+    fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
 #if DEBUG_DUMP
     gContourID = 0;
     gSegmentID = 0;
@@ -4128,7 +4159,7 @@
     SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
     fPathVerbs.pop();
     fPath = &path;
-    fXorMask = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
+    fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
     preFetch();
 }
 
@@ -4158,7 +4189,7 @@
 }
 
 ShapeOpMask xorMask() const {
-    return fXorMask;
+    return fXorMask[fOperand];
 }
 
 protected:
@@ -4202,7 +4233,7 @@
                 if (!fCurrentContour) {
                     fCurrentContour = fContours.push_back_n(1);
                     fCurrentContour->setOperand(fOperand);
-                    fCurrentContour->setXor(fXorMask == kEvenOdd_Mask);
+                    fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
                     *fExtra.append() = -1; // start new contour
                 }
                 finalCurveEnd = pointsPtr++;
@@ -4277,7 +4308,7 @@
     SkTArray<Contour>& fContours;
     SkTDArray<SkPoint> fReducePts; // segments created on the fly
     SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
-    ShapeOpMask fXorMask;
+    ShapeOpMask fXorMask[2];
     int fSecondHalf;
     bool fOperand;
 };