shape ops work in progress
authorcaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 27 Jul 2012 18:26:38 +0000 (18:26 +0000)
committercaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 27 Jul 2012 18:26:38 +0000 (18:26 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@4815 2bbb7eff-a529-9590-31e7-b0007b416f81

experimental/Intersection/EdgeWalker_Test.h
experimental/Intersection/Simplify.cpp
experimental/Intersection/SimplifyFindNext_Test.cpp
experimental/Intersection/SimplifyNew_Test.cpp
experimental/Intersection/SimplifyRect4x4_Test.cpp
experimental/Intersection/op.htm

index e07e708..6a316f6 100644 (file)
@@ -26,6 +26,7 @@ struct State4 {
     int b;
     int c;
     int d;
+    int testsRun;
     char filename[256];
     pthread_t threadID;
     SkCanvas* canvas;
index 7f1e7c7..c6236d5 100644 (file)
@@ -50,7 +50,7 @@ const bool gRunTestsInOneThread = true;
 #define DEBUG_ACTIVE_SPANS 1
 #define DEBUG_ADD_INTERSECTING_TS 0
 #define DEBUG_ADD_T_PAIR 0
-#define DEBUG_CONCIDENT 01
+#define DEBUG_CONCIDENT 0
 #define DEBUG_CROSS 1
 #define DEBUG_DUMP 1
 #define DEBUG_MARK_DONE 1
@@ -656,7 +656,7 @@ struct Bounds : public SkRect {
 
 struct Span {
     Segment* fOther;
-    mutable SkPoint const* fPt; // lazily computed as needed
+    mutable SkPoint fPt; // lazily computed as needed
     double fT;
     double fOtherT; // value at fOther[fOtherIndex].fT
     int fOtherIndex;  // can't be used during intersection
@@ -792,10 +792,10 @@ public:
     #if DEBUG_CONCIDENT
                 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
                         __FUNCTION__, fID, other.fID, tIndexStart - 1,
-                        fTs[tIndexStart - 1].fT, xyAtT(tIndexStart - 1).fX,
-                        xyAtT(tIndexStart - 1).fY);
+                        fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
+                        xyAtT(tIndexStart).fY);
     #endif
-                SkASSERT(0); // incomplete
+                addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT);
             }
             if (nextT < 1 && fTs[tIndex].fWindValue) {
     #if DEBUG_CONCIDENT
@@ -812,10 +812,10 @@ public:
     #if DEBUG_CONCIDENT
                 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
                         __FUNCTION__, fID, other.fID, oIndexStart - 1,
-                        other.fTs[oIndexStart - 1].fT, other.xyAtT(oIndexStart - 1).fX,
-                        other.xyAtT(oIndexStart - 1).fY);
+                        other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX,
+                        other.xyAtT(oIndexStart).fY);
+                other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
     #endif
-                SkASSERT(0); // incomplete
             }
             if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
     #if DEBUG_CONCIDENT
@@ -965,7 +965,7 @@ public:
         }
         span->fT = newT;
         span->fOther = other;
-        span->fPt = NULL;
+        span->fPt.fX = SK_ScalarNaN;
         span->fWindSum = SK_MinS32;
         span->fWindValue = 1;
         if ((span->fDone = newT == 1)) {
@@ -1068,7 +1068,7 @@ public:
             do {
                 if (transfer) {
                     if (decrementOther) {
-                        SkASSERT(abs(end->fWindValue) < gDebugMaxWindValue);
+                        SkASSERT(abs(end->fWindValue) <= gDebugMaxWindValue);
                         ++(end->fWindValue);
                     } else if (decrementSpan(end)) {
                         TrackOutside(outsideTs, end->fT, oStartT);
@@ -1085,7 +1085,7 @@ public:
             do {
                 if (transfer) {
                     if (!decrementOther) {
-                        SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue);
+                        SkASSERT(abs(oEnd->fWindValue) <= gDebugMaxWindValue);
                         ++(oEnd->fWindValue);
                     } else if (other.decrementSpan(oEnd)) {
                         TrackOutside(oOutsideTs, oEnd->fT, startT);
@@ -1320,28 +1320,21 @@ public:
     // it is guaranteed to have an end which describes a non-zero length (?)
     // winding -1 means ccw, 1 means cw
     // firstFind allows coincident edges to be treated differently
-    Segment* findNext(SkTDArray<Span*>& chase, int winding,
-            int contourWinding, bool firstFind, bool active,
+    Segment* findNext(SkTDArray<Span*>& chase, bool firstFind, bool active,
             const int startIndex, const int endIndex, int& nextStart,
-            int& nextEnd, int& spanWinding) {
-            
-        start here;
-        // winding is a mess
-        // try to simplify what we got
-        
-        int flipped = 1; 
+            int& nextEnd, int& winding, int& spanWinding) {
         int sumWinding = winding + spanWinding;
-        if (sumWinding == 0 || (false && contourWinding && !firstFind)) {
+        if (sumWinding == 0) {
             sumWinding = spanWinding;
         }
-        bool insideContour = contourWinding && contourWinding * sumWinding < 0;
-        if (insideContour && (true || !firstFind)) {
-            sumWinding = contourWinding;
+        bool insideContour = active && winding && winding * sumWinding < 0;
+        if (insideContour) {
+            sumWinding = winding;
         }
 
     #if DEBUG_WINDING
-        SkDebugf("%s winding=%d contourWinding=%d spanWinding=%d sumWinding=%d\n",
-                __FUNCTION__, winding, contourWinding, spanWinding, sumWinding);
+        SkDebugf("%s winding=%d spanWinding=%d sumWinding=%d\n",
+                __FUNCTION__, winding, spanWinding, sumWinding);
     #endif
         SkASSERT(startIndex != endIndex);
         int count = fTs.count();
@@ -1378,7 +1371,7 @@ public:
         int firstIndex = findStartingEdge(sorted, startIndex, end);
         SkASSERT(firstIndex >= 0);
     #if DEBUG_SORT
-        debugShowSort(sorted, firstIndex, contourWinding, sumWinding);
+        debugShowSort(sorted, firstIndex, winding, sumWinding);
     #endif
         bool doBump = sorted[firstIndex]->firstBump(sumWinding);
     #if DEBUG_WINDING
@@ -1396,8 +1389,9 @@ public:
         const Angle* foundAngle = NULL;
         bool foundDone = false;
         // iterate through the angle, and compute everyone's winding
-        bool firstEdge = true;
-        bool flopped = false;
+        bool toggleWinding = false;
+        bool flipFound = false;
+        int flipped = 1;
         Segment* nextSegment;
         do {
             if (nextIndex == angleCount) {
@@ -1413,13 +1407,12 @@ public:
                     maxWinding, sumWinding, nextAngle->sign());
     #endif
             if (maxWinding * sumWinding < 0) {
-                flipped = -flipped;
-                flopped = true;
+                flipFound ^= true;
     #if DEBUG_WINDING
-                SkDebugf("flipped sign %d %d\n", maxWinding, sumWinding);
+                SkDebugf("flipFound maxWinding=%d sumWinding=%d\n",
+                        maxWinding, sumWinding);
     #endif
             }
-            firstEdge = false;
             if (!sumWinding) {
                 if (!active) {
                     markDone(SkMin32(startIndex, endIndex), startWinding);
@@ -1433,10 +1426,11 @@ public:
                 if (!foundAngle || foundDone) {
                     foundAngle = nextAngle;
                     foundDone = nextSegment->done(*nextAngle);
-                    if (!flopped && maxWinding * startWinding < 0) {
+                    if (flipFound || (maxWinding * startWinding < 0)) {
                         flipped = -flipped;
             #if DEBUG_WINDING
-                        SkDebugf("flopped sign %d %d\n", maxWinding, startWinding);
+                        SkDebugf("flipped flipFound=%d maxWinding=%d startWinding=%d\n",
+                                flipFound, maxWinding, startWinding);
             #endif
                     }
                 }
@@ -1444,10 +1438,20 @@ public:
             }
             if (!maxWinding && innerSwap && !foundAngle) {
                 if (sumWinding * startWinding < 0 && flipped > 0) {
-                    SkDebugf("%s flip?\n");
-        //            flipped = -flipped;
+        #if DEBUG_WINDING
+                    SkDebugf("%s toggleWinding\n");
+        #endif
+                    toggleWinding = true;
+                } else if (startWinding != sumWinding) {
+                    winding = sumWinding;
                 }
                 foundAngle = nextAngle;
+                if (flipFound) {
+                    flipped = -1;
+        #if DEBUG_WINDING
+                    SkDebugf("flipped flipFound=%d\n", flipFound);
+        #endif
+                }
             }
             if (nextSegment->done()) {
                 continue;
@@ -1481,9 +1485,23 @@ public:
         nextSegment = foundAngle->segment();
         spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
                 SkMin32(nextStart, nextEnd));
-        #if DEBUG_WINDING
-            SkDebugf("%s spanWinding=%d\n", __FUNCTION__, spanWinding);
-        #endif
+        if (toggleWinding) {
+            if (winding) {
+                winding = 0;
+            } else {
+                winding = -startWinding;
+            }
+        }
+    #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
         return nextSegment;
     }
 
@@ -2013,18 +2031,16 @@ public:
     }
 
     const SkPoint& xyAtT(const Span* span) const {
-        if (!span->fPt) {
+        if (SkScalarIsNaN(span->fPt.fX)) {
             if (span->fT == 0) {
-                span->fPt = &fPts[0];
+                span->fPt = fPts[0];
             } else if (span->fT == 1) {
-                span->fPt = &fPts[fVerb];
+                span->fPt = fPts[fVerb];
             } else {
-                SkPoint* pt = fIntersections.append(); 
-                (*SegmentXYAtT[fVerb])(fPts, span->fT, pt);
-                span->fPt = pt;
+                (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt);
             }
         }
-        return *span->fPt;
+        return span->fPt;
     }
     
     SkScalar yAtT(int index) const {
@@ -2153,10 +2169,6 @@ private:
     SkPath::Verb fVerb;
     Bounds fBounds;
     SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
-    // OPTIMIZATION:if intersections array is a pointer, the it could only
-    // be allocated as needed instead of always initialized -- though maybe
-    // the initialization is lightweight enough that it hardly matters
-    mutable SkTDArray<SkPoint> fIntersections;
     int fDoneSpans; // used for quick check that segment is finished
 #if DEBUG_DUMP
     int fID;
@@ -3250,6 +3262,11 @@ static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
 }
 #endif
 
+static bool windingIsActive(int winding, int spanWinding) {
+    return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
+            && (!winding || !spanWinding || winding == -spanWinding);
+}
+
 // Each segment may have an inside or an outside. Segments contained within
 // winding may have insides on either side, and form a contour that should be
 // ignored. Segments that are coincident with opposing direction segments may
@@ -3286,21 +3303,26 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
         bool firstTime = true;
         int winding = contourWinding;
         int spanWinding = current->spanSign(index, endIndex);
-     //   int firstWinding = contourWinding + spanWinding;
+        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
         // inner contour is wound the same way, it never finds an accumulated
         // winding of zero. Inside 'find next', we need to look for transitions
         // other than zero when resolving sorted angles. 
+        bool active = windingIsActive(winding, spanWinding);
         SkTDArray<Span*> chaseArray;
         do {
-            bool active = winding * spanWinding <= 0
-                    && abs(winding) <= abs(spanWinding);
         #if DEBUG_WINDING
-            if (abs(winding) > abs(spanWinding) && winding * spanWinding < 0) {
-                SkDebugf("%s *** unexpected active?\n", __FUNCTION__);
-            }
             SkDebugf("%s active=%s winding=%d spanWinding=%d\n",
                     __FUNCTION__, active ? "true" : "false",
                     winding, spanWinding);
@@ -3309,9 +3331,9 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
             do {
                 SkASSERT(!current->done());
                 int nextStart, nextEnd;
-                Segment* next = current->findNext(chaseArray, winding,
-                        contourWinding, firstTime, active, index, endIndex,
-                        nextStart, nextEnd, spanWinding);
+                Segment* next = current->findNext(chaseArray,
+                        firstTime, active, index, endIndex,
+                        nextStart, nextEnd, winding, spanWinding);
                 if (!next) {
                     break;
                 }
@@ -3341,30 +3363,27 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
             spanWinding = current->windSum(lesser);
             int spanValue = current->windValue(lesser);
             SkASSERT(spanWinding != SK_MinS32);
-            int spanSign = current->spanSign(index, endIndex);
         #if DEBUG_WINDING
-            SkDebugf("%s spanWinding=%d spanSign=%d winding=%d spanValue=%d\n",
-                    __FUNCTION__, spanWinding, spanSign, winding, spanValue);
+            SkDebugf("%s spanWinding=%d winding=%d spanValue=%d\n",
+                    __FUNCTION__, spanWinding, winding, spanValue);
         #endif
-            if (spanWinding * spanSign < 0) {
-        #if DEBUG_WINDING
-                SkDebugf("%s spanWinding * spanSign < 0\n", __FUNCTION__);
-        #endif
-   //             SkTSwap<int>(index, endIndex);
-            }
-            if (abs(spanWinding) > spanValue) {
+            if (abs(spanWinding) != spanValue) {
                 winding = spanWinding;
                 spanWinding = spanValue * SkSign32(spanWinding);
                 winding -= spanWinding;
         #if DEBUG_WINDING
-                SkDebugf("%s spanWinding=%d winding=%d\n", __FUNCTION__,
+                SkDebugf("%s != spanWinding=%d winding=%d\n", __FUNCTION__,
                         spanWinding, winding);
         #endif
-            } else {
+                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;
             }
         } while (true);
index 7ea716d..5fc6305 100644 (file)
@@ -18,7 +18,7 @@ namespace SimplifyFindNextTest {
 #include "Intersection_Tests.h"
 
 static const SimplifyFindNextTest::Segment* testCommon(
-        int winding, int startIndex, int endIndex,
+        int contourWinding, int spanWinding, int startIndex, int endIndex,
         SkTArray<SimplifyFindNextTest::Contour>& contours) {
     SkTDArray<SimplifyFindNextTest::Contour*> contourList;
     makeContourList(contours, contourList);
@@ -34,8 +34,9 @@ static const SimplifyFindNextTest::Segment* testCommon(
     pts[0] = segment.xyAtT(&segment.span(endIndex));
     int nextStart, nextEnd;
     SkTDArray<SimplifyFindNextTest::Span*> chaseArray;
-    SimplifyFindNextTest::Segment* next = segment.findNext(chaseArray, winding,
-            0, true, true, startIndex, endIndex, nextStart, nextEnd, winding);
+    SimplifyFindNextTest::Segment* next = segment.findNext(chaseArray,
+            true, true, startIndex, endIndex, nextStart, nextEnd,
+            contourWinding, spanWinding);
     pts[1] = next->xyAtT(&next->span(nextStart));
     SkASSERT(pts[0] == pts[1]);
     return next;
@@ -44,17 +45,19 @@ static const SimplifyFindNextTest::Segment* testCommon(
 static void test(const SkPath& path) {
     SkTArray<SimplifyFindNextTest::Contour> contours;
     SimplifyFindNextTest::EdgeBuilder builder(path, contours);
-    int winding = 0;
+    int contourWinding = 0;
+    int spanWinding = 1;
     int start = 0;
     int end = 1;
-    testCommon(winding, start, end, contours);
+    testCommon(contourWinding, spanWinding, start, end, contours);
 }
 
 static void test(const SkPath& path, int start, int end) {
     SkTArray<SimplifyFindNextTest::Contour> contours;
     SimplifyFindNextTest::EdgeBuilder builder(path, contours);
-    int winding = 0;
-    testCommon(winding, start, end, contours);
+    int contourWinding = 0;
+    int spanWinding = 1;
+    testCommon(contourWinding, spanWinding, start, end, contours);
 }
 
 static void testLine1() {
index ce59341..aa475c7 100644 (file)
@@ -582,12 +582,78 @@ static void testLine59() {
     testSimplifyx(path);
 }
 
-static void (*firstTest)() = 0;
+static void testLine60() {
+    SkPath path, simple;
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(6, 12, 18, 18, (SkPath::Direction) 1);
+    path.addRect(4, 12, 13, 13, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine61() {
+    SkPath path, simple;
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(12, 0, 24, 24, (SkPath::Direction) 1);
+    path.addRect(12, 0, 21, 21, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine62() {
+    SkPath path, simple;
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 12, 12, 12, (SkPath::Direction) 0);
+    path.addRect(4, 12, 13, 13, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine63() {
+    SkPath path, simple;
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(0, 10, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 6, 12, 12, (SkPath::Direction) 1);
+    path.addRect(0, 32, 9, 36, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine64() {
+    SkPath path, simple;
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(10, 40, 30, 30, (SkPath::Direction) 0);
+    path.addRect(18, 6, 30, 30, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine65() {
+    SkPath path, simple;
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(10, 0, 30, 30, (SkPath::Direction) 0);
+    path.addRect(24, 0, 36, 36, (SkPath::Direction) 0);
+    path.addRect(32, 6, 36, 41, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine66() {
+    SkPath path, simple;
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(0, 30, 20, 20, (SkPath::Direction) 0);
+    path.addRect(12, 20, 24, 30, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void (*firstTest)() = testLine66;
 
 static struct {
     void (*fun)();
     const char* str;
 } tests[] = {
+    TEST(testLine66),
+    TEST(testLine65),
+    TEST(testLine64),
+    TEST(testLine63),
+    TEST(testLine62),
+    TEST(testLine61),
+    TEST(testLine60),
     TEST(testLine59),
     TEST(testLine58),
     TEST(testLine57),
@@ -661,8 +727,8 @@ void SimplifyNew_Test() {
         return;
     }
 #ifdef SK_DEBUG
-    gDebugMaxWindSum = 3;
-    gDebugMaxWindValue = 3;
+    gDebugMaxWindSum = 4;
+    gDebugMaxWindValue = 4;
 #endif
     size_t index = testCount - 1;
     if (firstTest) {
index 1b87f3f..d97bdbd 100644 (file)
@@ -11,6 +11,7 @@
 #include "SkCanvas.h"
 #include "SkStream.h"
 #include <assert.h>
+#include <errno.h>
 #include <pthread.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -29,7 +30,11 @@ static const char marker[] =
     "\n"
     "var testDivs = [\n";
 static const char testLineStr[] = "    testLine";
+#if 0
 static const char filename[] = "../../experimental/Intersection/debugXX.txt";
+#else
+static const char filename[] = "/flash/debug/XX.txt";
+#endif
 static int testNumber;
 
 static void* testSimplify4x4RectsMain(void* data)
@@ -38,6 +43,7 @@ static void* testSimplify4x4RectsMain(void* data)
     bzero(pathStr, sizeof(pathStr));
     SkASSERT(data);
     State4& state = *(State4*) data;
+    state.testsRun = 0;
     int aShape = state.a & 0x03;
     int aCW = state.a >> 2;
     int bShape = state.b & 0x03;
@@ -179,6 +185,7 @@ static void* testSimplify4x4RectsMain(void* data)
             getcwd(pwd, sizeof(pwd));
             SkDebugf("%s\n", pwd);
     #endif
+    #if 1
             SkFILEWStream outFile(state.filename);
             if (!outFile.isValid()) {
                 continue;
@@ -211,8 +218,10 @@ static void* testSimplify4x4RectsMain(void* data)
             outFile.writeDecAsText(testNumber);
             outFile.writeText("),\n");
             outFile.flush();
+    #endif
         }
         testSimplifyx(path, out, state.bitmap, state.canvas);
+        state.testsRun++;
                                 }
                             }
                         }
@@ -229,15 +238,16 @@ const int maxThreadsAllocated = 32;
 void Simplify4x4RectsThreaded_Test()
 {
 #ifdef SK_DEBUG
-    gDebugMaxWindSum = 3;
-    gDebugMaxWindValue = 3;
+    gDebugMaxWindSum = 4;
+    gDebugMaxWindValue = 4;
 #endif
     int maxThreads = 1;
     if (!gRunTestsInOneThread) {
-        size_t size;
         int threads = -1;
+        size_t size = sizeof(threads);
         sysctlbyname("hw.logicalcpu_max", &threads, &size, NULL, 0);
-        SkDebugf("%s size=%d processors=%d\n", __FUNCTION__, size, threads);
+        SkDebugf("%s errno=%d size=%d processors=%d\n", __FUNCTION__, 
+                errno, size, threads);
         if (threads > 0) {
             maxThreads = threads;
         } else {
@@ -272,6 +282,7 @@ void Simplify4x4RectsThreaded_Test()
         statePtr->filename[sizeof(filename) - 6] = '0' + threadIndex % 10;
     }
     threadIndex = 0;
+    int testsRun = 0;
     for (int a = 0; a < 8; ++a) { // outermost
         for (int b = a ; b < 8; ++b) {
             for (int c = b ; c < 8; ++c) {
@@ -285,6 +296,9 @@ void Simplify4x4RectsThreaded_Test()
                         createThread(statePtr, testSimplify4x4RectsMain);
                         if (++threadIndex >= maxThreads) {
                             waitForCompletion(threadState, threadIndex);
+                            for (int index = 0; index < maxThreads; ++index) {
+                                testsRun += threadState[index].testsRun;
+                            }
                         }
                     } else {
                         testSimplify4x4RectsMain(statePtr);
@@ -298,6 +312,9 @@ void Simplify4x4RectsThreaded_Test()
         if (!gRunTestsInOneThread) SkDebugf("\n\n%d", a);
     }
     waitForCompletion(threadState, threadIndex);
+    for (int index = 0; index < maxThreads; ++index) {
+        testsRun += threadState[index].testsRun;
+    }
 #ifdef SK_DEBUG
     gDebugMaxWindSum = SK_MaxS32;
     gDebugMaxWindValue = SK_MaxS32;
index 73448b4..531812e 100644 (file)
@@ -587,11 +587,63 @@ path.close();
     path.addRect(4, 4, 13, 13, (SkPath::Direction) 1);
 </div>
 
+<div id="testLine60">
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(6, 12, 18, 18, (SkPath::Direction) 1);
+    path.addRect(4, 12, 13, 13, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine61">
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(12, 0, 24, 24, (SkPath::Direction) 1);
+    path.addRect(12, 0, 21, 21, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine62">
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 12, 12, 12, (SkPath::Direction) 0);
+    path.addRect(4, 12, 13, 13, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine63">
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(0, 10, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 6, 12, 12, (SkPath::Direction) 1);
+    path.addRect(0, 32, 9, 36, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine64">
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(10, 40, 30, 30, (SkPath::Direction) 0);
+    path.addRect(18, 6, 30, 30, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine65">
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(10, 0, 30, 30, (SkPath::Direction) 0);
+    path.addRect(24, 0, 36, 36, (SkPath::Direction) 0);
+    path.addRect(32, 6, 36, 41, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine66">
+    path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
+    path.addRect(0, 30, 20, 20, (SkPath::Direction) 0);
+    path.addRect(12, 20, 24, 30, (SkPath::Direction) 0);
+</div>
+
 </div>
 
 <script type="text/javascript">
 
 var testDivs = [
+    testLine66,
+    testLine65,
+    testLine64,
+    testLine63,
+    testLine62,
+    testLine61,
+    testLine60,
     testLine59,
     testLine58,
     testLine57,