shape ops work in progress
authorcaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 2 Aug 2012 20:08:21 +0000 (20:08 +0000)
committercaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 2 Aug 2012 20:08:21 +0000 (20:08 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@4939 2bbb7eff-a529-9590-31e7-b0007b416f81

experimental/Intersection/Simplify.cpp
experimental/Intersection/SimplifyFindTop_Test.cpp
experimental/Intersection/SimplifyNew_Test.cpp
experimental/Intersection/op.htm

index 53abe8b..80846c2 100644 (file)
@@ -27,7 +27,7 @@ int gDebugMaxWindValue = SK_MaxS32;
 
 #define DEBUG_UNUSED 0 // set to expose unused functions
 
-#if 0 // set to 1 for multiple thread -- no debugging
+#if 01 // set to 1 for multiple thread -- no debugging
 
 const bool gRunTestsInOneThread = false;
 
@@ -51,7 +51,7 @@ const bool gRunTestsInOneThread = true;
 #define DEBUG_ADD_INTERSECTING_TS 0
 #define DEBUG_ADD_T_PAIR 0
 #define DEBUG_CONCIDENT 0
-#define DEBUG_CROSS 1
+#define DEBUG_CROSS 0
 #define DEBUG_DUMP 1
 #define DEBUG_MARK_DONE 1
 #define DEBUG_PATH_CONSTRUCTION 1
@@ -61,7 +61,7 @@ const bool gRunTestsInOneThread = true;
 
 #endif
 
-#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT) && !DEBUG_DUMP
+#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT || DEBUG_SORT) && !DEBUG_DUMP
 #undef DEBUG_DUMP
 #define DEBUG_DUMP 1
 #endif
@@ -492,6 +492,7 @@ public:
     }
 
     bool firstBump(int sumWinding) const {
+        SkDebugf("%s sign=%d sumWinding=%d\n", __FUNCTION__, sign(), sumWinding);
         return sign() * sumWinding > 0;
     }
 
@@ -1237,6 +1238,57 @@ public:
         SkASSERT(0); // incomplete
         return false;
     }
+    
+    int computeSum(int startIndex, int endIndex) {
+        SkTDArray<Angle> angles;
+        addTwoAngles(startIndex, endIndex, angles);
+        buildAngles(endIndex, angles);
+        SkTDArray<Angle*> sorted;
+        sortAngles(angles, sorted);
+        int angleCount = angles.count();
+        const Angle* angle;
+        const Segment* base;
+        int winding;
+        int firstIndex = 0;
+        do {
+            angle = sorted[firstIndex];
+            base = angle->segment();
+            winding = base->windSum(angle);
+            if (winding != SK_MinS32) {
+                break;
+            }
+            if (++firstIndex == angleCount) {
+                return SK_MinS32;
+            }
+        } while (true);
+        // turn winding into contourWinding
+        int spanWinding = base->spanSign(angle->start(), angle->end());
+        if (spanWinding * winding < 0) {
+            winding += spanWinding;
+        }
+    #if DEBUG_SORT
+        base->debugShowSort(sorted, firstIndex, winding);
+    #endif
+        int nextIndex = firstIndex + 1;
+        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
+        winding -= base->windBump(angle);
+        do {
+            if (nextIndex == angleCount) {
+                nextIndex = 0;
+            }
+            angle = sorted[nextIndex];
+            Segment* segment = angle->segment();
+            int maxWinding = winding;
+            winding -= segment->windBump(angle);
+            if (segment->windSum(nextIndex) == SK_MinS32) {
+                if (abs(maxWinding) < abs(winding) || maxWinding * winding < 0) {
+                    maxWinding = winding;
+                }
+                segment->markAndChaseWinding(angle, maxWinding);
+            }
+        } while (++nextIndex != lastIndex);
+        return windSum(SkMin32(startIndex, endIndex));
+    }
 
     int crossedSpan(const SkPoint& basePt, SkScalar& bestY, double& hitT) const {
         int bestT = -1;
@@ -1277,6 +1329,40 @@ public:
         return bestT;
     }
 
+    bool crossedSpanHalves(const SkPoint& basePt, bool leftHalf, bool rightHalf) {
+        // if a segment is connected to this one, consider it crossing
+        int tIndex;
+        if (fPts[0].fX == basePt.fX) {
+            tIndex = 0;
+            do {
+                const Span& sSpan = fTs[tIndex];
+                const Segment* sOther = sSpan.fOther;
+                if (!sOther->fTs[sSpan.fOtherIndex].fWindValue) {
+                    continue;
+                }
+                if (leftHalf ? sOther->fBounds.fLeft < basePt.fX
+                        : sOther->fBounds.fRight > basePt.fX) {
+                    return true;
+                }
+            } while (fTs[++tIndex].fT == 0);
+        }
+        if (fPts[fVerb].fX == basePt.fX) {
+            tIndex = fTs.count() - 1;
+            do {
+                const Span& eSpan = fTs[tIndex];
+                const Segment* eOther = eSpan.fOther;
+                if (!eOther->fTs[eSpan.fOtherIndex].fWindValue) {
+                    continue;
+                }
+                if (leftHalf ? eOther->fBounds.fLeft < basePt.fX
+                        : eOther->fBounds.fRight > basePt.fX) {
+                    return true;
+                }
+            } while (fTs[--tIndex].fT == 1);
+        }
+        return false;
+    }
+    
     bool decrementSpan(Span* span) {
         SkASSERT(span->fWindValue > 0);
         if (--(span->fWindValue) == 0) {
@@ -1327,19 +1413,16 @@ public:
     Segment* findNext(SkTDArray<Span*>& chase, bool firstFind, bool active,
             const int startIndex, const int endIndex, int& nextStart,
             int& nextEnd, int& winding, int& spanWinding) {
-        int sumWinding = winding + spanWinding;
-        if (sumWinding == 0) {
-            sumWinding = spanWinding;
-        }
-        bool insideContour = active && winding && winding * sumWinding < 0;
-        if (insideContour) {
-            sumWinding = winding;
-        }
-
+        int outerWinding = winding;
+        int innerWinding = winding + spanWinding;
     #if DEBUG_WINDING
-        SkDebugf("%s winding=%d spanWinding=%d sumWinding=%d\n",
-                __FUNCTION__, winding, spanWinding, sumWinding);
+        SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n",
+                __FUNCTION__, winding, spanWinding, outerWinding, innerWinding);
     #endif
+        if (abs(outerWinding) < abs(innerWinding)
+                || outerWinding * innerWinding < 0) {
+            outerWinding = innerWinding;
+        }
         SkASSERT(startIndex != endIndex);
         int count = fTs.count();
         SkASSERT(startIndex < endIndex ? startIndex < count - 1
@@ -1352,7 +1435,10 @@ public:
         if (isSimple(end)) {
         // mark the smaller of startIndex, endIndex done, and all adjacent
         // spans with the same T value (but not 'other' spans)
-            markDone(SkMin32(startIndex, endIndex), sumWinding);
+    #if DEBUG_WINDING
+            SkDebugf("%s simple\n", __FUNCTION__);
+    #endif
+            markDone(SkMin32(startIndex, endIndex), outerWinding);
             other = endSpan->fOther;
             nextStart = endSpan->fOtherIndex;
             double startT = other->fTs[nextStart].fT;
@@ -1375,25 +1461,19 @@ public:
         int firstIndex = findStartingEdge(sorted, startIndex, end);
         SkASSERT(firstIndex >= 0);
     #if DEBUG_SORT
-        debugShowSort(sorted, firstIndex, winding, sumWinding);
+        debugShowSort(sorted, firstIndex, winding);
     #endif
-        bool doBump = sorted[firstIndex]->firstBump(sumWinding);
+        SkASSERT(sorted[firstIndex]->segment() == this);
     #if DEBUG_WINDING
-        SkDebugf("%s sumWinding=%d sign=%d (%sbump)\n", __FUNCTION__,
-                sumWinding, sorted[firstIndex]->sign(), doBump ? "" : "no ");
+        SkDebugf("%s sign=%d\n", __FUNCTION__, sorted[firstIndex]->sign());
     #endif
-        bool innerSwap = active && (doBump || insideContour);
-        int startWinding = sumWinding;
-   //     SkASSERT(SkSign32(sumWinding) == SkSign32(winding) || winding == 0);
-        if (doBump || insideContour) {
-            sumWinding -= windBump(sorted[firstIndex]);
-        }
+        int sumWinding = winding - windBump(sorted[firstIndex]);
         int nextIndex = firstIndex + 1;
         int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
         const Angle* foundAngle = NULL;
         bool foundDone = false;
         // iterate through the angle, and compute everyone's winding
-        bool toggleWinding = false;
+        int toggleWinding = SK_MinS32;
         bool flipFound = false;
         int flipped = 1;
         Segment* nextSegment;
@@ -1413,13 +1493,13 @@ public:
             if (maxWinding * sumWinding < 0) {
                 flipFound ^= true;
     #if DEBUG_WINDING
-                SkDebugf("flipFound maxWinding=%d sumWinding=%d\n",
-                        maxWinding, sumWinding);
+                SkDebugf("%s flipFound=%d maxWinding=%d sumWinding=%d\n",
+                        __FUNCTION__, flipFound, maxWinding, sumWinding);
     #endif
             }
             if (!sumWinding) {
                 if (!active) {
-                    markDone(SkMin32(startIndex, endIndex), startWinding);
+                    markDone(SkMin32(startIndex, endIndex), outerWinding);
                     nextSegment->markWinding(SkMin32(nextAngle->start(),
                                 nextAngle->end()), maxWinding);
     #if DEBUG_WINDING
@@ -1430,30 +1510,42 @@ public:
                 if (!foundAngle || foundDone) {
                     foundAngle = nextAngle;
                     foundDone = nextSegment->done(*nextAngle);
-                    if (flipFound || (maxWinding * startWinding < 0)) {
+                    if (flipFound || (maxWinding * outerWinding < 0)) {
                         flipped = -flipped;
             #if DEBUG_WINDING
-                        SkDebugf("flipped flipFound=%d maxWinding=%d startWinding=%d\n",
-                                flipFound, maxWinding, startWinding);
+                        SkDebugf("%s flipped=%d flipFound=%d maxWinding=%d"
+                                " outerWinding=%d\n", __FUNCTION__, flipped,
+                                flipFound, maxWinding, outerWinding);
             #endif
                     }
                 }
                 continue;
             }
-            if (!maxWinding && innerSwap && !foundAngle) {
-                if (sumWinding * startWinding < 0 && flipped > 0) {
+            if (!maxWinding && !foundAngle) {
+        #if DEBUG_WINDING
+                if (flipped > 0) {
+                    SkDebugf("%s sumWinding=%d * outerWinding=%d < 0 (%s)\n",
+                            __FUNCTION__, sumWinding, outerWinding, 
+                            sumWinding * outerWinding < 0 ? "true" : "false");
+                }
+        #endif
+                if (sumWinding * outerWinding < 0 && flipped > 0) {
+        #if DEBUG_WINDING
+                    SkDebugf("%s toggleWinding=%d\n", __FUNCTION__, sumWinding);
+        #endif
+                    toggleWinding = sumWinding;
+                } else if (outerWinding != sumWinding) {
         #if DEBUG_WINDING
-                    SkDebugf("%s toggleWinding\n");
+                    SkDebugf("%s outerWinding=%d != sumWinding=%d winding=%d\n",
+                            __FUNCTION__, outerWinding, sumWinding, winding);
         #endif
-                    toggleWinding = true;
-                } else if (startWinding != sumWinding) {
                     winding = sumWinding;
                 }
                 foundAngle = nextAngle;
                 if (flipFound) {
-                    flipped = -1;
+                    flipped = -flipped;
         #if DEBUG_WINDING
-                    SkDebugf("flipped flipFound=%d\n", flipFound);
+                    SkDebugf("%s flipped flipFound=%d\n", __FUNCTION__, flipFound);
         #endif
                 }
             }
@@ -1465,11 +1557,12 @@ public:
             // as done, record the winding value, and mark connected unambiguous
             // segments as well.
             if (nextSegment->windSum(nextAngle) == SK_MinS32) {
-                if (abs(maxWinding) < abs(sumWinding)) {
+                if (abs(maxWinding) < abs(sumWinding)
+                        || maxWinding * sumWinding < 0) {
                     maxWinding = sumWinding;
                 }
                 Span* last;
-                if (foundAngle || innerSwap) {
+                if (foundAngle) {
                     last = nextSegment->markAndChaseWinding(nextAngle, maxWinding);
                 } else {
                     last = nextSegment->markAndChaseDone(nextAngle, maxWinding);
@@ -1480,7 +1573,7 @@ public:
             }
         } while (++nextIndex != lastIndex);
         SkASSERT(sorted[firstIndex]->segment() == this);
-        markDone(SkMin32(startIndex, endIndex), startWinding);
+        markDone(SkMin32(startIndex, endIndex), outerWinding);
         if (!foundAngle) {
             return NULL;
         }
@@ -1489,20 +1582,10 @@ public:
         nextSegment = foundAngle->segment();
         spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
                 SkMin32(nextStart, nextEnd));
-        if (toggleWinding) {
-            if (winding) {
-                winding = 0;
-            } else {
-                winding = -startWinding;
-            }
+        if (toggleWinding != SK_MinS32) {
+            winding = toggleWinding;
+            spanWinding = -spanWinding;
         }
-    #if 0
-        int min = SkMin32(nextStart, nextEnd);
-        int sign = foundAngle->sign();
-        int windSum = nextSegment->windSum(min);
-        int windValue = nextSegment->windValue(min);
-        SkASSERT(winding + sign * windValue == windSum); 
-    #endif
     #if DEBUG_WINDING
         SkDebugf("%s spanWinding=%d\n", __FUNCTION__, spanWinding);
     #endif
@@ -1694,6 +1777,17 @@ public:
         } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
         return leftSegment;
     }
+    
+    bool firstBump(const Angle* angle, int sumWinding) const {
+        int winding = spanSign(angle->start(), angle->end());
+        sumWinding -= winding;
+        if (sumWinding == 0) {
+            sumWinding = winding;
+        }
+        bool result = angle->sign() * sumWinding > 0;
+        SkASSERT(result == angle->firstBump(sumWinding));
+        return result;
+    }
 
     // FIXME: not crazy about this
     // when the intersections are performed, the other index is into an
@@ -1862,7 +1956,7 @@ public:
             }
         #if DEBUG_MARK_DONE
             const SkPoint& pt = xyAtT(&span);
-            SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
+            SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
                     __FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding);
         #endif
             span.fDone = true;
@@ -1879,7 +1973,7 @@ public:
             }
         #if DEBUG_MARK_DONE
             const SkPoint& pt = xyAtT(&span);
-            SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
+            SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
                     __FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding);
         #endif
             span.fDone = true;
@@ -1903,7 +1997,7 @@ public:
             SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
         #if DEBUG_MARK_DONE
             const SkPoint& pt = xyAtT(&span);
-            SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
+            SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
                     __FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding);
         #endif
             SkASSERT(abs(winding) <= gDebugMaxWindSum);
@@ -1919,7 +2013,7 @@ public:
             SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
         #if DEBUG_MARK_DONE
             const SkPoint& pt = xyAtT(&span);
-            SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
+            SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
                     __FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding);
         #endif
             SkASSERT(abs(winding) <= gDebugMaxWindSum);
@@ -2081,7 +2175,7 @@ public:
 
 #if DEBUG_CONCIDENT
     // assert if pair has not already been added
-     void debugAddTPair(double t, const Segment& other, double otherT) {
+     void debugAddTPair(double t, const Segment& other, double otherT) const {
         for (int i = 0; i < fTs.count(); ++i) {
             if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
                 return;
@@ -2091,8 +2185,14 @@ public:
      }
 #endif
 
+#if DEBUG_DUMP
+    int debugID() const {
+        return fID;
+    }
+#endif
+
 #if DEBUG_CONCIDENT
-    void debugShowTs() {
+    void debugShowTs() const {
         SkDebugf("%s %d", __FUNCTION__, fID);
         for (int i = 0; i < fTs.count(); ++i) {
             SkDebugf(" [o=%d %1.9g (%1.9g,%1.9g) w=%d]", fTs[i].fOther->fID,
@@ -2103,7 +2203,7 @@ public:
 #endif
 
 #if DEBUG_ACTIVE_SPANS
-    void debugShowActiveSpans(int contourID, int segmentIndex) {
+    void debugShowActiveSpans() const {
         if (done()) {
             return;
         }
@@ -2111,8 +2211,7 @@ public:
             if (fTs[i].fDone) {
                 continue;
             }
-            SkDebugf("%s contour=%d segment=%d (%d)", __FUNCTION__, contourID,
-                     segmentIndex, fID);
+            SkDebugf("%s id=%d", __FUNCTION__, fID);
             SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
             for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
                 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
@@ -2121,27 +2220,26 @@ public:
             SkDebugf(") fT=%d (%1.9g) (%1.9g,%1.9g)", i, fTs[i].fT, 
                      xAtT(span), yAtT(i));
             const Segment* other = fTs[i].fOther;
-            SkDebugf(" other=%d otherT=%1.9g otherIndex=%d", other->fID,
-                     fTs[i].fOtherT, fTs[i].fOtherIndex);
-            SkDebugf(" windSum=%d windValue=%d\n", fTs[i].fWindSum,
-                     fTs[i].fWindValue);
+            SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
+                    other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
+            if (fTs[i].fWindSum == SK_MinS32) {
+                SkDebugf("?");
+            } else {
+                SkDebugf("%d", fTs[i].fWindSum);
+            }
+            SkDebugf(" windValue=%d\n", fTs[i].fWindValue);
         }
     }
 #endif
 
 #if DEBUG_SORT
     void debugShowSort(const SkTDArray<Angle*>& angles, int first,
-            int contourWinding, int sumWinding) {
+            const int contourWinding) const {
         SkASSERT(angles[first]->segment() == this);
-        bool doBump = angles[first]->firstBump(sumWinding);
-        bool insideContour = contourWinding && contourWinding * sumWinding < 0;
-        int windSum = insideContour ? contourWinding : sumWinding;
-        int lastSum = windSum;
-        if (insideContour || doBump) {
-            windSum -= windBump(angles[first]);
-        } else {
-            lastSum += windBump(angles[first]);
-        }
+        int lastSum = contourWinding;
+        int windSum = lastSum - windBump(angles[first]);
+        SkDebugf("%s contourWinding=%d bump=%d\n", __FUNCTION__,
+                contourWinding, windBump(angles[first]));
         int index = first;
         bool firstTime = true;
         do {
@@ -2152,9 +2250,7 @@ public:
             const Span& sSpan = segment.fTs[start];
             const Span& eSpan = segment.fTs[end];
             const Span& mSpan = segment.fTs[SkMin32(start, end)];
-            if (firstTime) {
-                firstTime = false;
-            } else {
+            if (!firstTime) {
                 lastSum = windSum;
                 windSum -= segment.windBump(&angle);
             }
@@ -2169,10 +2265,29 @@ public:
             if (index == angles.count()) {
                 index = 0;
             }
+            if (firstTime) {
+                firstTime = false;
+            }
         } while (index != first);
     }
 #endif
 
+#if DEBUG_WINDING
+    bool debugVerifyWinding(int start, int end, int winding) const {
+        const Span& span = fTs[SkMin32(start, end)];
+        int spanWinding = span.fWindSum;
+        if (spanWinding == SK_MinS32) {
+            return true;
+        }
+        int spanSign = SkSign32(start - end);
+        int signedVal = spanSign * span.fWindValue;
+        if (signedVal < 0) {
+            spanWinding -= signedVal;
+        }
+        return span.fWindSum == winding;
+    }
+#endif
+
 private:
     const SkPoint* fPts;
     SkPath::Verb fVerb;
@@ -2274,10 +2389,10 @@ public:
         for (int test = 0; test < segmentCount; ++test) {
             Segment* testSegment = &fSegments[test];
             const SkRect& bounds = testSegment->bounds();
-            if (bounds.fTop < bestY) {
+            if (bounds.fBottom <= bestY) {
                 continue;
             }
-            if (bounds.fTop > basePt.fY) {
+            if (bounds.fTop >= basePt.fY) {
                 continue;
             }
             if (bounds.fLeft > basePt.fX) {
@@ -2286,6 +2401,17 @@ public:
             if (bounds.fRight < basePt.fX) {
                 continue;
             }
+            if (bounds.fLeft == bounds.fRight) {
+                continue;
+            }
+     #if 0
+            bool leftHalf = bounds.fLeft == basePt.fX;
+            bool rightHalf = bounds.fRight == basePt.fX;
+            if ((leftHalf || rightHalf) && !testSegment->crossedSpanHalves(
+                    basePt, leftHalf, rightHalf)) {
+                continue;
+            }
+     #endif
             double testHitT;
             int testT = testSegment->crossedSpan(basePt, bestY, testHitT);
             if (testT >= 0) {
@@ -2324,7 +2450,6 @@ public:
         fSegments.reset();
         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
         fContainsCurves = fContainsIntercepts = false;
-        fWindingSum = SK_MinS32;
     }
 
     void resolveCoincidence(int winding) {
@@ -2382,11 +2507,6 @@ public:
         return fSegments;
     }
     
-    void setWinding(int winding) {
-        SkASSERT(fWindingSum < 0 || fWindingSum == winding);
-        fWindingSum = winding;
-    }
-
     // OPTIMIZATION: feel pretty uneasy about this. It seems like once again
     // we need to sort and walk edges in y, but that on the surface opens the
     // same can of worms as before. But then, this is a rough sort based on 
@@ -2433,22 +2553,6 @@ public:
         return segment.verb() + 1;
     }
 
-    int windSum() {
-        if (fWindingSum >= 0) {
-            return fWindingSum;
-        }
-        // check peers
-        int count = fCrosses.count();
-        for (int index = 0; index < count; ++index) {
-            const Contour* crosser = fCrosses[index];
-            if (0 <= crosser->fWindingSum) {
-                fWindingSum = crosser->fWindingSum;
-                break;
-            }
-        }
-        return fWindingSum;
-    }
-
 #if DEBUG_TEST
     SkTArray<Segment>& debugSegments() {
         return fSegments;
@@ -2480,7 +2584,7 @@ public:
 #if DEBUG_ACTIVE_SPANS
     void debugShowActiveSpans() {
         for (int index = 0; index < fSegments.count(); ++index) {
-            fSegments[index].debugShowActiveSpans(fID, index);
+            fSegments[index].debugShowActiveSpans();
         }
     }
 #endif
@@ -2507,7 +2611,6 @@ private:
     Bounds fBounds;
     bool fContainsIntercepts;
     bool fContainsCurves;
-    int fWindingSum; // initial winding number outside
 #if DEBUG_DUMP
     int fID;
 #endif
@@ -3041,14 +3144,14 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList, int winding) {
 // two contours touch, so we need only look at contours not touching this one.
 // OPTIMIZATION: sort contourList vertically to avoid linear walk
 static int innerContourCheck(SkTDArray<Contour*>& contourList,
-        Contour* baseContour, const Segment* current, int index, int endIndex) {
+        const Segment* current, int index, int endIndex) {
     const SkPoint& basePt = current->xyAtT(endIndex);
     int contourCount = contourList.count();
     SkScalar bestY = SK_ScalarMin;
     const Segment* test = NULL;
     int tIndex;
     double tHit;
-    bool checkCrosses = true;
//   bool checkCrosses = true;
     for (int cTest = 0; cTest < contourCount; ++cTest) {
         Contour* contour = contourList[cTest];
         if (basePt.fY < contour->bounds().fTop) {
@@ -3057,6 +3160,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
         if (bestY > contour->bounds().fBottom) {
             continue;
         }
+#if 0
         // even though the contours crossed, if spans cancel through concidence,
         // the contours may be not have any span links to chase, and the current
         // segment may be isolated. Detect this by seeing if current has
@@ -3071,19 +3175,20 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
             }
             checkCrosses = false;
         }
+#endif
         const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit);
         if (next) {
             test = next;
         }
     }
     if (!test) {
-        baseContour->setWinding(0);
         return 0;
     }
     int winding, windValue;
     // If the ray hit the end of a span, we need to construct the wheel of
     // angles to find the span closest to the ray -- even if there are just
     // two spokes on the wheel.
+    const Angle* angle = NULL;
     if (fabs(tHit - test->t(tIndex)) < FLT_EPSILON) {
         SkTDArray<Angle> angles;
         int end = test->nextSpan(tIndex, 1);
@@ -3099,7 +3204,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
         // hour after 6 o'clock
         sortAngles(angles, sorted);
 #if DEBUG_SORT
-        sorted[0]->segment()->debugShowSort(sorted, 0, 0, 0);  
+        sorted[0]->segment()->debugShowSort(sorted, 0, 0);  
 #endif
         // walk the sorted angle fan to find the lowest angle
         // above the base point. Currently, the first angle in the sorted array
@@ -3130,20 +3235,18 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
         SkASSERT(left >= 0 || right >= 0);
         if (left < 0) {
             left = right;
+        } else if (left >= 0 && mid >= 0 && right >= 0
+                && sorted[mid]->sign() == sorted[right]->sign()) {
+            left = right;
         }
-        const Angle* angle = sorted[left];
+        angle = sorted[left];
         test = angle->segment();
         winding = test->windSum(angle);
         SkASSERT(winding != SK_MinS32);
         windValue = test->windValue(angle);
-    #if 0
-        if (angle->firstBump(winding)) {
-            winding -= test->windBump(angle);
-        }
-    #endif
 #if DEBUG_WINDING
-        SkDebugf("%s angle winding=%d windValue=%d\n", __FUNCTION__, winding,
-                windValue);
+        SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding,
+                windValue, angle->sign());
 #endif
     } else {
         winding = test->windSum(tIndex);
@@ -3159,19 +3262,19 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
 #if DEBUG_WINDING
     SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
 #endif
-    SkASSERT(dx != 0);
-    if (winding * dx > 0) { // if same signs, result is negative
+    if (dx == 0) {
+        SkASSERT(angle);
+        if (test->firstBump(angle, winding)) {
+            winding -= test->windBump(angle);
+        }
+    } else if (winding * dx > 0) { // if same signs, result is negative
         winding += dx > 0 ? -windValue : windValue;
 #if DEBUG_WINDING
         SkDebugf("%s final winding=%d\n", __FUNCTION__, winding);
 #endif
     }
-    start here;
//   start here;
     // we're broken because we find a vertical span
-    // also, does it make sense to compute a contour's winding? Won't it 
-    // depend on coincidence and (e.g. a figure eight) self intersection?
-    // (hopefully no one uses this) so remove it
-    baseContour->setWinding(winding);
     return winding;
 }
     
@@ -3181,8 +3284,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
 // Once the segment array is built, there's no reason I can think of not to
 // sort it in Y. hmmm
 // FIXME: return the contour found to pass to inner contour check
-static Segment* findTopContour(SkTDArray<Contour*>& contourList,
-        Contour*& topContour) {
+static Segment* findTopContour(SkTDArray<Contour*>& contourList) {
     int contourCount = contourList.count();
     int cIndex = 0;
     Segment* topStart;
@@ -3195,7 +3297,6 @@ static Segment* findTopContour(SkTDArray<Contour*>& contourList,
     if (!topStart) {
         return NULL;
     }
-    topContour = contour;
     while (++cIndex < contourCount) {
         contour = contourList[cIndex];
         if (bestY < contour->bounds().fTop) {
@@ -3206,7 +3307,6 @@ static Segment* findTopContour(SkTDArray<Contour*>& contourList,
         if (!test || bestY <= testY) {
             continue;
         }
-        topContour = contour;
         topStart = test;
         bestY = testY;
     }
@@ -3237,18 +3337,24 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
         // find first angle, initialize winding to computed fWindSum
         int firstIndex = -1;
         const Angle* angle;
-        int spanWinding;
+        int winding;
         do {
             angle = sorted[++firstIndex];
-            spanWinding = angle->segment()->windSum(angle);
-        } while (spanWinding == SK_MinS32);
-    #if DEBUG_SORT
-        angle->segment()->debugShowSort(sorted, firstIndex, contourWinding,
-                spanWinding);  
+            segment = angle->segment();
+            winding = segment->windSum(angle);
+        } while (winding == SK_MinS32);
+        int spanWinding = segment->spanSign(angle->start(), angle->end());
+    #if DEBUG_WINDING
+        SkDebugf("%s winding=%d spanWinding=%d contourWinding=%d\n",
+                __FUNCTION__, winding, spanWinding, contourWinding);
     #endif
-        if (angle->firstBump(spanWinding)) {
-            spanWinding -= angle->segment()->windBump(angle);
+        // turn swinding into contourWinding
+        if (spanWinding * winding < 0) {
+            winding += spanWinding;
         }
+    #if DEBUG_SORT
+        segment->debugShowSort(sorted, firstIndex, winding);  
+    #endif
         // we care about first sign and whether wind sum indicates this
         // edge is inside or outside. Maybe need to pass span winding
         // or first winding or something into this function?
@@ -3257,30 +3363,35 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
         int nextIndex = firstIndex + 1;
         int angleCount = sorted.count();
         int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
+        angle = sorted[firstIndex];
+        winding -= angle->segment()->windBump(angle);
         do {
             SkASSERT(nextIndex != firstIndex);
             if (nextIndex == angleCount) {
                 nextIndex = 0;
             }
-            const Angle* angle = sorted[nextIndex];
+            angle = sorted[nextIndex];
             segment = angle->segment();
-            int maxWinding = spanWinding;
-            spanWinding -= segment->windBump(angle);
-            if (maxWinding * spanWinding < 0) {
-                SkDebugf("%s flipped sign %d %d\n", __FUNCTION__, maxWinding, spanWinding);
-            }
+            int maxWinding = winding;
+            winding -= segment->windBump(angle);
+    #if DEBUG_SORT
+            SkDebugf("%s id=%d maxWinding=%d winding=%d\n", __FUNCTION__,
+                    segment->debugID(), maxWinding, winding);
+    #endif
             tIndex = angle->start();
             endIndex = angle->end();
             int lesser = SkMin32(tIndex, endIndex);
             const Span& nextSpan = segment->span(lesser);
             if (!nextSpan.fDone) {
+#if 1
             // FIXME: this be wrong. assign startWinding if edge is in
             // same direction. If the direction is opposite, winding to
             // assign is flipped sign or +/- 1?
-                if (abs(maxWinding) < abs(spanWinding)) {
-                    maxWinding = spanWinding;
+                if (abs(maxWinding) < abs(winding)) {
+                    maxWinding = winding;
                 }
                 segment->markWinding(lesser, maxWinding);
+#endif
                 break;
             }
         } while (++nextIndex != lastIndex);
@@ -3314,8 +3425,7 @@ static bool windingIsActive(int winding, int spanWinding) {
 static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
     bool firstContour = true;
     do {
-        Contour* topContour;
-        Segment* topStart = findTopContour(contourList, topContour);
+        Segment* topStart = findTopContour(contourList);
         if (!topStart) {
             break;
         }
@@ -3328,9 +3438,17 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
             contourWinding = 0;
             firstContour = false;
         } else {
-            contourWinding = innerContourCheck(contourList, topContour, current,
-                    index, endIndex);
+            contourWinding = current->windSum(SkMin32(index, endIndex));
+            // FIXME: don't I have to adjust windSum to get contourWinding?
+            if (contourWinding == SK_MinS32) {
+                contourWinding = current->computeSum(index, endIndex);
+                if (contourWinding == SK_MinS32) {
+                    contourWinding = innerContourCheck(contourList, current,
+                            index, endIndex);
+                }
+            }
 #if DEBUG_WINDING
+         //   SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding));
             SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
 #endif
         }
@@ -3338,16 +3456,6 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
         bool firstTime = true;
         int winding = contourWinding;
         int spanWinding = current->spanSign(index, endIndex);
-        int spanWindSum = current->windSum(SkMin32(index, endIndex));
-        if (spanWindSum != SK_MinS32) {
-            int calcWinding = spanWindSum;
-            if (spanWinding > 0) {
-     //           calcWinding -= spanWinding;
-            }
-            SkDebugf("%s *** winding=%d calcWinding=%d\n", __FUNCTION__, 
-                    winding, calcWinding);
-            winding = calcWinding;
-        }
         // FIXME: needs work. While it works in limited situations, it does
         // not always compute winding correctly. Active should be removed and instead
         // the initial winding should be correctly passed in so that if the
@@ -3395,32 +3503,12 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
                 break;
             }
             int lesser = SkMin32(index, endIndex);
-            spanWinding = current->windSum(lesser);
-            int spanValue = current->windValue(lesser);
-            SkASSERT(spanWinding != SK_MinS32);
-        #if DEBUG_WINDING
-            SkDebugf("%s spanWinding=%d winding=%d spanValue=%d\n",
-                    __FUNCTION__, spanWinding, winding, spanValue);
-        #endif
-            if (abs(spanWinding) != spanValue) {
-                winding = spanWinding;
-                spanWinding = spanValue * SkSign32(spanWinding);
+            spanWinding = current->spanSign(index, endIndex);
+            winding = current->windSum(lesser);
+            if (spanWinding * winding > 0) {
                 winding -= spanWinding;
-        #if DEBUG_WINDING
-                SkDebugf("%s != spanWinding=%d winding=%d\n", __FUNCTION__,
-                        spanWinding, winding);
-        #endif
-                active = windingIsActive(winding, spanWinding);
-            } else if (winding) {
-        #if DEBUG_WINDING
-                SkDebugf("%s ->0 contourWinding=%d winding=%d\n", __FUNCTION__,
-                        contourWinding, winding);
-        #endif
-           //     start here;
-                // set active=false if it was false when chase was created
-                active = abs(winding) <= abs(spanWinding);
-                winding = 0;
             }
+            active = windingIsActive(winding, spanWinding);
         } while (true);
     } while (true);
 }
index 9e8d2bb..0c9c2e0 100644 (file)
@@ -27,8 +27,7 @@ static const SimplifyFindTopTest::Segment* testCommon(
         addIntersectTs(contourList[1], contourList[1]);
     }
     fixOtherTIndex(contourList);
-    SimplifyFindTopTest::Contour* top;
-    SimplifyFindTopTest::Segment* topStart = findTopContour(contourList, top);
+    SimplifyFindTopTest::Segment* topStart = findTopContour(contourList);
     const SimplifyFindTopTest::Segment* topSegment = topStart->findTop(index,
             end);
     return topSegment;
index 2b7d4e4..eeae035 100644 (file)
@@ -62,6 +62,20 @@ static void testLine3() {
     testSimplifyx(path);
 }
 
+static void testLine3a() {
+    SkPath path, simple;
+    addInnerCWTriangle(path);
+    addOuterCCWTriangle(path);
+    testSimplifyx(path);
+}
+
+static void testLine3b() {
+    SkPath path, simple;
+    addInnerCCWTriangle(path);
+    addOuterCCWTriangle(path);
+    testSimplifyx(path);
+}
+
 static void testLine4() {
     SkPath path, simple;
     addOuterCCWTriangle(path);
@@ -641,12 +655,127 @@ static void testLine66() {
     testSimplifyx(path);
 }
 
+static void testLine67() {
+    SkPath path, simple;
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(10, 40, 30, 30, (SkPath::Direction) 0);
+    path.addRect(24, 20, 36, 30, (SkPath::Direction) 0);
+    path.addRect(32, 0, 36, 41, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68a() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
+    path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68b() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68c() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
+    path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68d() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68e() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68f() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68g() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine68h() {
+    SkPath path, simple;
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine69() {
+    SkPath path, simple;
+    path.addRect(0, 20, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 20, 12, 30, (SkPath::Direction) 0);
+    path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine70() {
+    SkPath path, simple;
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 24, 12, 12, (SkPath::Direction) 0);
+    path.addRect(12, 32, 21, 36, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine71() {
+    SkPath path, simple;
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(12, 0, 24, 24, (SkPath::Direction) 0);
+    path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
 static void (*firstTest)() = 0;
 
 static struct {
     void (*fun)();
     const char* str;
 } tests[] = {
+    TEST(testLine71),
+    TEST(testLine70),
+    TEST(testLine69),
+    TEST(testLine68h),
+    TEST(testLine68g),
+    TEST(testLine68f),
+    TEST(testLine68e),
+    TEST(testLine68d),
+    TEST(testLine68c),
+    TEST(testLine68b),
+    TEST(testLine68a),
+    TEST(testLine67),
     TEST(testLine66),
     TEST(testLine65),
     TEST(testLine64),
@@ -713,6 +842,8 @@ static struct {
     TEST(testLine6),
     TEST(testLine5),
     TEST(testLine4),
+    TEST(testLine3b),
+    TEST(testLine3a),
     TEST(testLine3),
     TEST(testLine2),
     TEST(testLine1),
@@ -720,7 +851,24 @@ static struct {
 
 static const size_t testCount = sizeof(tests) / sizeof(tests[0]);
 
+static struct {
+    void (*fun)();
+    const char* str;
+} subTests[] = {
+    TEST(testLine68h),
+    TEST(testLine68g),
+    TEST(testLine68f),
+    TEST(testLine68e),
+    TEST(testLine68d),
+    TEST(testLine68c),
+    TEST(testLine68b),
+    TEST(testLine68a),
+};
+
+static const size_t subTestCount = sizeof(subTests) / sizeof(subTests[0]);
+
 static bool skipAll = false;
+static bool runSubTests = false;
 
 void SimplifyNew_Test() {
     if (skipAll) {
@@ -729,8 +877,16 @@ void SimplifyNew_Test() {
 #ifdef SK_DEBUG
     gDebugMaxWindSum = 4;
     gDebugMaxWindValue = 4;
+    size_t index;
 #endif
-    size_t index = testCount - 1;
+    if (runSubTests) {
+        index = subTestCount - 1;
+        do {
+            SkDebugf("  %s [%s]\n", __FUNCTION__, subTests[index].str);
+            (*subTests[index].fun)();
+        } while (index--);
+    }
+    index = testCount - 1;
     if (firstTest) {
         while (index > 0 && tests[index].fun != firstTest) {
             --index;
index 531812e..7049f02 100644 (file)
@@ -632,11 +632,84 @@ path.close();
     path.addRect(12, 20, 24, 30, (SkPath::Direction) 0);
 </div>
 
+<div id="testLine67">
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(10, 40, 30, 30, (SkPath::Direction) 0);
+    path.addRect(24, 20, 36, 30, (SkPath::Direction) 0);
+    path.addRect(32, 0, 36, 41, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine68a">
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
+    path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine68b">
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine68c">
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
+    path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine68d">
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine68e">
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine68f">
+    path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
+    path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine69">
+    path.addRect(0, 20, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 20, 12, 30, (SkPath::Direction) 0);
+    path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine70">
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 24, 12, 12, (SkPath::Direction) 0);
+    path.addRect(12, 32, 21, 36, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine71">
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(12, 0, 24, 24, (SkPath::Direction) 0);
+    path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
+</div>
+
 </div>
 
 <script type="text/javascript">
 
 var testDivs = [
+    testLine71,
+    testLine70,
+    testLine69,
+    testLine68f,
+    testLine68e,
+    testLine68d,
+    testLine68c,
+    testLine68b,
+    testLine68a,
+    testLine67,
     testLine66,
     testLine65,
     testLine64,
@@ -671,9 +744,9 @@ var testDivs = [
     testLine35,
     testLine34,
     testLine33,
-    testLine30,
     testLine32,
     testLine31,
+    testLine30,
     testLine29,
     testLine28,
     testLine24,
@@ -805,8 +878,8 @@ function parseRect(test, title) {
 function init(test) {
     var canvas = document.getElementById('canvas');
     if (!canvas.getContext) return;
-    canvas.width = document.width;
-    canvas.height = document.height;
+    canvas.width = window.innerWidth - at_x;
+    canvas.height = window.innerHeight - at_y;
     ctx = canvas.getContext('2d');
     var xmin = Infinity;
     var xmax = -Infinity;
@@ -982,6 +1055,7 @@ function doKeyPress(evt) {
     var char = String.fromCharCode(evt.charCode);
     switch (char) {
     case 'N':
+        testIndex += 9;
     case 'n':
         if (++testIndex >= tests.length)
             testIndex = 0;
@@ -989,6 +1063,7 @@ function doKeyPress(evt) {
         drawTop();
         break;
     case 'P':
+        testIndex -= 9;
     case 'p':
         if (--testIndex < 0)
             testIndex = tests.length - 1;
@@ -999,15 +1074,19 @@ function doKeyPress(evt) {
     case 't':
         break;
     case '-':
-            redraw();
+        drawTop();
         break;
     case '=':
     case '+':
-        redraw();
+        drawTop();
         break;
     }
 }
 
+function doResize(evt) {
+    drawTop();
+}
+
 function start() {
     for (i = 0; i < testDivs.length; ++i) {
         var title = testDivs[i].id.toString();
@@ -1020,6 +1099,9 @@ function start() {
     }
     drawTop();
     window.addEventListener('keypress', doKeyPress, true);
+    window.onresize = function() {
+        drawTop();
+    }
 }
 
 </script>