aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2014-07-18 05:08:14 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-07-18 05:08:14 -0700
commit19eb3b2f0aa6dce5c0335230a8930e90733e5d5d (patch)
treebb3bd2ef885609b5eda366f238cc31dfaae0884d
parent384b0202c040034ba1e8f2e3789a01e4b05a6a2b (diff)
update pathops core and tests
split out skpclip (the test of 1M pictures) into its own project TBR=reed Author: caryclark@google.com Review URL: https://codereview.chromium.org/400033002
-rw-r--r--gyp/most.gyp1
-rwxr-xr-xgyp/pathops_skpclip.gyp46
-rw-r--r--gyp/pathops_unittest.gyp1
-rw-r--r--src/pathops/SkDLineIntersection.cpp31
-rw-r--r--src/pathops/SkOpSegment.cpp78
-rw-r--r--src/pathops/SkPathOpsDebug.cpp1
-rw-r--r--src/pathops/SkPathOpsDebug.h1
-rwxr-xr-xtests/PathOpsDebug.cpp132
-rw-r--r--tests/PathOpsExtendedTest.cpp143
-rw-r--r--tests/PathOpsLineIntersectionTest.cpp4
-rw-r--r--tests/PathOpsOpTest.cpp26
-rw-r--r--tests/PathOpsSimplifyTest.cpp11
-rwxr-xr-xtests/PathOpsSkpClipTest.cpp1126
-rwxr-xr-xtests/PathOpsSkpTest.cpp226
-rw-r--r--tools/pathops_sorter.htm6
-rw-r--r--tools/pathops_visualizer.htm214
16 files changed, 1229 insertions, 818 deletions
diff --git a/gyp/most.gyp b/gyp/most.gyp
index 4675add4dd..6c791b7881 100644
--- a/gyp/most.gyp
+++ b/gyp/most.gyp
@@ -21,6 +21,7 @@
'tests.gyp:tests',
'tools.gyp:tools',
'pathops_unittest.gyp:*',
+ 'pathops_skpclip.gyp:*',
# 'pdfviewer.gyp:pdfviewer',
'dm.gyp:dm',
],
diff --git a/gyp/pathops_skpclip.gyp b/gyp/pathops_skpclip.gyp
new file mode 100755
index 0000000000..a1e51d65f8
--- /dev/null
+++ b/gyp/pathops_skpclip.gyp
@@ -0,0 +1,46 @@
+# GYP file to build pathops skp clip test.
+{
+ 'includes': [
+ 'apptype_console.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pathops_skpclip',
+ 'type': 'executable',
+ 'include_dirs': [
+ '../src/core',
+ '../src/effects',
+ '../src/lazy',
+ '../src/pathops',
+ '../src/pipe/utils',
+ '../src/utils',
+ ],
+ 'dependencies': [
+ 'flags.gyp:flags',
+ 'skia_lib.gyp:skia_lib',
+ 'tools.gyp:crash_handler',
+ 'tools.gyp:resources',
+ ],
+ 'sources': [
+ '../tests/PathOpsDebug.cpp',
+ '../tests/PathOpsSkpClipTest.cpp',
+ ],
+ 'conditions': [
+ [ 'skia_android_framework == 1', {
+ 'libraries': [
+ '-lskia',
+ ],
+ 'libraries!': [
+ '-lz',
+ '-llog',
+ ],
+ }],
+ [ 'skia_gpu == 1', {
+ 'include_dirs': [
+ '../src/gpu',
+ ],
+ }],
+ ],
+ },
+ ],
+}
diff --git a/gyp/pathops_unittest.gyp b/gyp/pathops_unittest.gyp
index 190b4f3816..b8f6835f48 100644
--- a/gyp/pathops_unittest.gyp
+++ b/gyp/pathops_unittest.gyp
@@ -16,7 +16,6 @@
'../tests/PathOpsCubicLineIntersectionIdeas.cpp',
'../tests/PathOpsDebug.cpp',
'../tests/PathOpsOpLoopThreadedTest.cpp',
- '../tests/PathOpsSkpClipTest.cpp',
'../tests/skia_test.cpp',
],
'conditions': [
diff --git a/src/pathops/SkDLineIntersection.cpp b/src/pathops/SkDLineIntersection.cpp
index 9ae0107173..b209474066 100644
--- a/src/pathops/SkDLineIntersection.cpp
+++ b/src/pathops/SkDLineIntersection.cpp
@@ -173,21 +173,24 @@ int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
nearCount += t >= 0;
}
if (nearCount > 0) {
- for (int iA = 0; iA < 2; ++iA) {
- if (!aNotB[iA]) {
- continue;
- }
- int nearer = aNearB[iA] > 0.5;
- if (!bNotA[nearer]) {
- continue;
+ // Skip if each segment contributes to one end point.
+ if (nearCount != 2 || aNotB[0] == aNotB[1]) {
+ for (int iA = 0; iA < 2; ++iA) {
+ if (!aNotB[iA]) {
+ continue;
+ }
+ int nearer = aNearB[iA] > 0.5;
+ if (!bNotA[nearer]) {
+ continue;
+ }
+ SkASSERT(a[iA] != b[nearer]);
+ SkASSERT(iA == (bNearA[nearer] > 0.5));
+ fNearlySame[iA] = true;
+ insertNear(iA, nearer, a[iA], b[nearer]);
+ aNearB[iA] = -1;
+ bNearA[nearer] = -1;
+ nearCount -= 2;
}
- SkASSERT(a[iA] != b[nearer]);
- SkASSERT(iA == (bNearA[nearer] > 0.5));
- fNearlySame[iA] = true;
- insertNear(iA, nearer, a[iA], b[nearer]);
- aNearB[iA] = -1;
- bNearA[nearer] = -1;
- nearCount -= 2;
}
if (nearCount > 0) {
for (int iA = 0; iA < 2; ++iA) {
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index 4e8b5d28d9..f6d989b18a 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -405,12 +405,14 @@ void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active
}
void SkOpSegment::addEndSpan(int endIndex) {
+ SkASSERT(span(endIndex).fT == 1 || (span(endIndex).fTiny
+ && approximately_greater_than_one(span(endIndex).fT)));
int spanCount = fTs.count();
int startIndex = endIndex - 1;
while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) {
- ++startIndex;
- SkASSERT(startIndex < spanCount - 1);
- ++endIndex;
+ --startIndex;
+ SkASSERT(startIndex > 0);
+ --endIndex;
}
SkOpAngle& angle = fAngles.push_back();
angle.set(this, spanCount - 1, startIndex);
@@ -815,7 +817,11 @@ int SkOpSegment::addSelfT(const SkPoint& pt, double newT) {
// FIXME? assert that only one other span has a valid windValue or oppValue
void SkOpSegment::addSimpleAngle(int index) {
SkOpSpan* span = &fTs[index];
- if (index == 0) {
+ int idx;
+ int start, end;
+ if (span->fT == 0) {
+ idx = 0;
+ span = &fTs[0];
do {
if (span->fToAngle) {
SkASSERT(span->fToAngle->loopCount() == 2);
@@ -823,13 +829,15 @@ void SkOpSegment::addSimpleAngle(int index) {
span->fFromAngle = span->fToAngle->next();
return;
}
- span = &fTs[++index];
+ span = &fTs[++idx];
} while (span->fT == 0);
- SkASSERT(index == 1);
- index = 0;
- SkASSERT(!fTs[0].fTiny && fTs[1].fT > 0);
- addStartSpan(1);
+ SkASSERT(!fTs[0].fTiny && fTs[idx].fT > 0);
+ addStartSpan(idx);
+ start = 0;
+ end = idx;
} else {
+ idx = count() - 1;
+ span = &fTs[idx];
do {
if (span->fFromAngle) {
SkASSERT(span->fFromAngle->loopCount() == 2);
@@ -837,29 +845,48 @@ void SkOpSegment::addSimpleAngle(int index) {
span->fToAngle = span->fFromAngle->next();
return;
}
- span = &fTs[--index];
+ span = &fTs[--idx];
} while (span->fT == 1);
- SkASSERT(index == count() - 2);
- index = count() - 1;
- SkASSERT(!fTs[index - 1].fTiny && fTs[index - 1].fT < 1);
- addEndSpan(index);
+ SkASSERT(!fTs[idx].fTiny && fTs[idx].fT < 1);
+ addEndSpan(++idx);
+ start = idx;
+ end = count();
}
- span = &fTs[index];
- SkOpSegment* other = span->fOther;
- SkOpSpan& oSpan = other->fTs[span->fOtherIndex];
+ SkOpSegment* other;
+ SkOpSpan* oSpan;
+ index = start;
+ do {
+ span = &fTs[index];
+ other = span->fOther;
+ int oFrom = span->fOtherIndex;
+ oSpan = &other->fTs[oFrom];
+ if (oSpan->fT < 1 && oSpan->fWindValue) {
+ break;
+ }
+ if (oSpan->fT == 0) {
+ continue;
+ }
+ oFrom = other->nextExactSpan(oFrom, -1);
+ SkOpSpan* oFromSpan = &other->fTs[oFrom];
+ SkASSERT(oFromSpan->fT < 1);
+ if (oFromSpan->fWindValue) {
+ break;
+ }
+ } while (++index < end);
SkOpAngle* angle, * oAngle;
- if (index == 0) {
+ if (span->fT == 0) {
SkASSERT(span->fOtherIndex - 1 >= 0);
SkASSERT(span->fOtherT == 1);
- SkDEBUGCODE(SkOpSpan& oPrior = other->fTs[span->fOtherIndex - 1]);
+ SkDEBUGCODE(int oPriorIndex = other->nextExactSpan(span->fOtherIndex, -1));
+ SkDEBUGCODE(const SkOpSpan& oPrior = other->span(oPriorIndex));
SkASSERT(!oPrior.fTiny && oPrior.fT < 1);
other->addEndSpan(span->fOtherIndex);
angle = span->fToAngle;
- oAngle = oSpan.fFromAngle;
+ oAngle = oSpan->fFromAngle;
} else {
SkASSERT(span->fOtherIndex + 1 < other->count());
SkASSERT(span->fOtherT == 0);
- SkASSERT(!oSpan.fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0
+ SkASSERT(!oSpan->fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0
|| (other->fTs[span->fOtherIndex + 1].fFromAngle == NULL
&& other->fTs[span->fOtherIndex + 1].fToAngle == NULL)));
int oIndex = 1;
@@ -873,7 +900,7 @@ void SkOpSegment::addSimpleAngle(int index) {
} while (true);
other->addStartSpan(oIndex);
angle = span->fFromAngle;
- oAngle = oSpan.fToAngle;
+ oAngle = oSpan->fToAngle;
}
angle->insert(oAngle);
}
@@ -1348,7 +1375,10 @@ void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
success = true;
break;
}
- oPeek = &other->fTs[++oPeekIndex];
+ if (++oPeekIndex == oCount) {
+ break;
+ }
+ oPeek = &other->fTs[oPeekIndex];
} while (endPt == oPeek->fPt);
}
if (success) {
@@ -3402,7 +3432,7 @@ SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding)
SkOpSegment* other = this;
while ((other = other->nextChase(&index, &step, &min, &last))) {
if (other->fTs[min].fWindSum != SK_MinS32) {
- SkASSERT(other->fTs[min].fWindSum == winding);
+// SkASSERT(other->fTs[min].fWindSum == winding);
SkASSERT(!last);
break;
}
diff --git a/src/pathops/SkPathOpsDebug.cpp b/src/pathops/SkPathOpsDebug.cpp
index 96029b340b..7db93f5e96 100644
--- a/src/pathops/SkPathOpsDebug.cpp
+++ b/src/pathops/SkPathOpsDebug.cpp
@@ -108,6 +108,7 @@ void SkOpAngle::debugLoop() const {
const SkOpAngle* next = this;
do {
next->dumpOne(true);
+ SkDebugf("\n");
next = next->fNext;
} while (next && next != first);
}
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index 9dc562fea1..211c503aad 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -169,6 +169,7 @@ public:
SkPathOpsDebug::DeleteNameStr)))
static void BumpTestName(char* );
#endif
+ static void ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration);
static void ShowPath(const SkPath& one, const SkPath& two, SkPathOp op, const char* name);
static void DumpCoincidence(const SkTArray<class SkOpContour, true>& contours);
static void DumpCoincidence(const SkTArray<class SkOpContour* , true>& contours);
diff --git a/tests/PathOpsDebug.cpp b/tests/PathOpsDebug.cpp
index af60318532..8ac38aaf6d 100755
--- a/tests/PathOpsDebug.cpp
+++ b/tests/PathOpsDebug.cpp
@@ -1,6 +1,7 @@
#include "SkOpContour.h"
#include "SkIntersectionHelper.h"
#include "SkOpSegment.h"
+#include "SkString.h"
inline void DebugDumpDouble(double x) {
if (x == floor(x)) {
@@ -18,6 +19,137 @@ inline void DebugDumpFloat(float x) {
}
}
+
+#if DEBUG_SHOW_TEST_NAME
+
+static void output_scalar(SkScalar num) {
+ if (num == (int) num) {
+ SkDebugf("%d", (int) num);
+ } else {
+ SkString str;
+ str.printf("%1.9g", num);
+ int width = (int) str.size();
+ const char* cStr = str.c_str();
+ while (cStr[width - 1] == '0') {
+ --width;
+ }
+ str.resize(width);
+ SkDebugf("%sf", str.c_str());
+ }
+}
+
+static void output_points(const SkPoint* pts, int count) {
+ for (int index = 0; index < count; ++index) {
+ output_scalar(pts[index].fX);
+ SkDebugf(", ");
+ output_scalar(pts[index].fY);
+ if (index + 1 < count) {
+ SkDebugf(", ");
+ }
+ }
+ SkDebugf(");\n");
+}
+
+static void showPathContours(SkPath::RawIter& iter, const char* pathName) {
+ uint8_t verb;
+ SkPoint pts[4];
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ SkDebugf(" %s.moveTo(", pathName);
+ output_points(&pts[0], 1);
+ continue;
+ case SkPath::kLine_Verb:
+ SkDebugf(" %s.lineTo(", pathName);
+ output_points(&pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ SkDebugf(" %s.quadTo(", pathName);
+ output_points(&pts[1], 2);
+ break;
+ case SkPath::kCubic_Verb:
+ SkDebugf(" %s.cubicTo(", pathName);
+ output_points(&pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ SkDebugf(" %s.close();\n", pathName);
+ break;
+ default:
+ SkDEBUGFAIL("bad verb");
+ return;
+ }
+ }
+}
+
+static const char* gFillTypeStr[] = {
+ "kWinding_FillType",
+ "kEvenOdd_FillType",
+ "kInverseWinding_FillType",
+ "kInverseEvenOdd_FillType"
+};
+
+void SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration) {
+ SkPath::RawIter iter(path);
+#define SUPPORT_RECT_CONTOUR_DETECTION 0
+#if SUPPORT_RECT_CONTOUR_DETECTION
+ int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
+ if (rectCount > 0) {
+ SkTDArray<SkRect> rects;
+ SkTDArray<SkPath::Direction> directions;
+ rects.setCount(rectCount);
+ directions.setCount(rectCount);
+ path.rectContours(rects.begin(), directions.begin());
+ for (int contour = 0; contour < rectCount; ++contour) {
+ const SkRect& rect = rects[contour];
+ SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
+ rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
+ ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
+ }
+ return;
+ }
+#endif
+ SkPath::FillType fillType = path.getFillType();
+ SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
+ if (includeDeclaration) {
+ SkDebugf(" SkPath %s;\n", name);
+ }
+ SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]);
+ iter.setPath(path);
+ showPathContours(iter, name);
+}
+
+static void show_function_header(const char* functionName) {
+ SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName);
+ if (strcmp("skphealth_com76", functionName) == 0) {
+ SkDebugf("found it\n");
+ }
+}
+
+static const char* gOpStrs[] = {
+ "kDifference_PathOp",
+ "kIntersect_PathOp",
+ "kUnion_PathOp",
+ "kXor_PathOp",
+ "kReverseDifference_PathOp",
+};
+
+static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) {
+ SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]);
+ SkDebugf("}\n");
+}
+
+SK_DECLARE_STATIC_MUTEX(gTestMutex);
+
+void SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp,
+ const char* testName) {
+ SkAutoMutexAcquire ac(gTestMutex);
+ show_function_header(testName);
+ ShowOnePath(a, "path", true);
+ ShowOnePath(b, "pathB", true);
+ show_op(shapeOp, "path", "pathB");
+}
+#endif
+
// if not defined by PathOpsDebug.cpp ...
#if !defined SK_DEBUG && FORCE_RELEASE
bool SkPathOpsDebug::ValidWind(int wind) {
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index fe3d24d6a0..2d741261a6 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -49,102 +49,6 @@ static bool gShowPath = false;
static bool gComparePathsAssert = true;
static bool gPathStrAssert = true;
-static const char* gFillTypeStr[] = {
- "kWinding_FillType",
- "kEvenOdd_FillType",
- "kInverseWinding_FillType",
- "kInverseEvenOdd_FillType"
-};
-
-static void output_scalar(SkScalar num) {
- if (num == (int) num) {
- SkDebugf("%d", (int) num);
- } else {
- SkString str;
- str.printf("%1.9g", num);
- int width = (int) str.size();
- const char* cStr = str.c_str();
- while (cStr[width - 1] == '0') {
- --width;
- }
- str.resize(width);
- SkDebugf("%sf", str.c_str());
- }
-}
-
-static void output_points(const SkPoint* pts, int count) {
- for (int index = 0; index < count; ++index) {
- output_scalar(pts[index].fX);
- SkDebugf(", ");
- output_scalar(pts[index].fY);
- if (index + 1 < count) {
- SkDebugf(", ");
- }
- }
- SkDebugf(");\n");
-}
-
-static void showPathContours(SkPath::RawIter& iter, const char* pathName) {
- uint8_t verb;
- SkPoint pts[4];
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- switch (verb) {
- case SkPath::kMove_Verb:
- SkDebugf(" %s.moveTo(", pathName);
- output_points(&pts[0], 1);
- continue;
- case SkPath::kLine_Verb:
- SkDebugf(" %s.lineTo(", pathName);
- output_points(&pts[1], 1);
- break;
- case SkPath::kQuad_Verb:
- SkDebugf(" %s.quadTo(", pathName);
- output_points(&pts[1], 2);
- break;
- case SkPath::kCubic_Verb:
- SkDebugf(" %s.cubicTo(", pathName);
- output_points(&pts[1], 3);
- break;
- case SkPath::kClose_Verb:
- SkDebugf(" %s.close();\n", pathName);
- break;
- default:
- SkDEBUGFAIL("bad verb");
- return;
- }
- }
-}
-
-static void showPath(const SkPath& path, const char* pathName, bool includeDeclaration) {
- SkPath::RawIter iter(path);
-#define SUPPORT_RECT_CONTOUR_DETECTION 0
-#if SUPPORT_RECT_CONTOUR_DETECTION
- int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
- if (rectCount > 0) {
- SkTDArray<SkRect> rects;
- SkTDArray<SkPath::Direction> directions;
- rects.setCount(rectCount);
- directions.setCount(rectCount);
- path.rectContours(rects.begin(), directions.begin());
- for (int contour = 0; contour < rectCount; ++contour) {
- const SkRect& rect = rects[contour];
- SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
- rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
- ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
- }
- return;
- }
-#endif
- SkPath::FillType fillType = path.getFillType();
- SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
- if (includeDeclaration) {
- SkDebugf(" SkPath %s;\n", pathName);
- }
- SkDebugf(" %s.setFillType(SkPath::%s);\n", pathName, gFillTypeStr[fillType]);
- iter.setPath(path);
- showPathContours(iter, pathName);
-}
-
#if DEBUG_SHOW_TEST_NAME
static void showPathData(const SkPath& path) {
SkPath::RawIter iter(path);
@@ -225,29 +129,6 @@ void showOp(const SkPathOp op) {
}
#if DEBUG_SHOW_TEST_NAME
-
-void ShowFunctionHeader(const char* functionName) {
- SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName);
- if (strcmp("skphealth_com76", functionName) == 0) {
- SkDebugf("found it\n");
- }
-}
-
-static const char* gOpStrs[] = {
- "kDifference_PathOp",
- "kIntersect_PathOp",
- "kUnion_PathOp",
- "kXor_PathOp",
- "kReverseDifference_PathOp",
-};
-
-void ShowOp(SkPathOp op, const char* pathOne, const char* pathTwo) {
- SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]);
- SkDebugf("}\n");
-}
-#endif
-
-#if DEBUG_SHOW_TEST_NAME
static char hexorator(int x) {
if (x < 10) {
return x + '0';
@@ -420,8 +301,10 @@ static void showPathOpPath(const char* testName, const SkPath& one, const SkPath
*gTestOp.append() = shapeOp;
++gTestNo;
SkDebugf(" SkPath path, pathB;\n");
- showPath(a, "path", false);
- showPath(b, "pathB", false);
+#if DEBUG_SHOW_TEST_NAME
+ SkPathOpsDebug::ShowOnePath(a, "path", false);
+ SkPathOpsDebug::ShowOnePath(b, "pathB", false);
+#endif
SkDebugf(" testPathOp(reporter, path, pathB, %s, filename);\n", opStrs[shapeOp]);
SkDebugf("}\n");
drawAsciiPaths(scaledOne, scaledTwo, true);
@@ -523,9 +406,11 @@ bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& st
const char* pathStr) {
SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
path.setFillType(fillType);
+#if DEBUG_SHOW_TEST_NAME
if (gShowPath) {
- showPath(path, "path", false);
+ SkPathOpsDebug::ShowOnePath(path, "path", false);
}
+#endif
if (!Simplify(path, &out)) {
SkDebugf("%s did not expect failure\n", __FUNCTION__);
REPORTER_ASSERT(state.fReporter, 0);
@@ -576,20 +461,6 @@ bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char*
}
#if DEBUG_SHOW_TEST_NAME
-
-SK_DECLARE_STATIC_MUTEX(gTestMutex);
-
-void SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp,
- const char* testName) {
- SkAutoMutexAcquire ac(gTestMutex);
- ShowFunctionHeader(testName);
- showPath(a, "path", true);
- showPath(b, "pathB", true);
- ShowOp(shapeOp, "path", "pathB");
-}
-#endif
-
-#if DEBUG_SHOW_TEST_NAME
static void showName(const SkPath& a, const SkPath& b, const SkPathOp shapeOp) {
SkDebugf("\n");
showPathData(a);
diff --git a/tests/PathOpsLineIntersectionTest.cpp b/tests/PathOpsLineIntersectionTest.cpp
index 379c2f16f9..0c6aac65d9 100644
--- a/tests/PathOpsLineIntersectionTest.cpp
+++ b/tests/PathOpsLineIntersectionTest.cpp
@@ -11,6 +11,10 @@
// FIXME: add tests for intersecting, non-intersecting, degenerate, coincident
static const SkDLine tests[][2] = {
+#if 0
+ // these do intersect at a pair of points, but not close enough for check results liking
+ {{{{365.848175,5081.15186}, {368,5103}}}, {{{367.967712,5102.61084}, {368.278717,5105.71045}}}},
+#endif
{{{{30,20}, {30,50}}}, {{{24,30}, {36,30}}}},
{{{{323,193}, {-317,193}}}, {{{0,994}, {0,0}}}},
{{{{90,230}, {160,60}}}, {{{60,120}, {260,120}}}},
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 1d63bd7ab6..b7babd3af6 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -3461,10 +3461,36 @@ static void rects4(skiatest::Reporter* reporter, const char* filename) {
testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
}
+#define TEST_ISSUE_2753 0
+#if TEST_ISSUE_2753
+static void issue2753(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(142.701f, 110.568f);
+ path1.lineTo(142.957f, 100);
+ path1.lineTo(153.835f, 100);
+ path1.lineTo(154.592f, 108.188f);
+ path1.cubicTo(154.592f, 108.188f, 153.173f, 108.483f, 152.83f, 109.412f);
+ path1.cubicTo(152.83f, 109.412f, 142.701f, 110.568f, 142.701f, 110.568f);
+ path1.close();
+
+ SkPath path2;
+ path2.moveTo(39, 124.001f);
+ path2.cubicTo(39, 124.001f, 50.6f, 117.001f, 50.6f, 117.001f);
+ path2.cubicTo(50.6f, 117.001f, 164.601f, 85.2f, 188.201f, 117.601f);
+ path2.cubicTo(188.201f, 117.601f, 174.801f, 93, 39, 124.001f);
+ path2.close();
+
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+#endif
+
static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static struct TestDesc tests[] = {
+#if TEST_ISSUE_2753 // FIXME: pair of cubics miss intersection
+ TEST(issue2753),
+#endif
#if CUBIC_OP_114 // FIXME: curve with inflection is ordered the wrong way
TEST(cubicOp114),
#endif
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index 4bfab14488..88547a0f04 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -4669,9 +4669,20 @@ static void testQuadralateral10(skiatest::Reporter* reporter, const char* filena
testSimplify(reporter, path, filename);
}
+static void testRect3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCCW_Direction);
+ path.addRect(10, 30, 40, 30, SkPath::kCCW_Direction);
+ path.addRect(24, 6, 36, 36, SkPath::kCCW_Direction);
+ path.addRect(32, 6, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
static TestDesc tests[] = {
+ TEST(testRect3),
TEST(testQuadralateral10),
TEST(testQuads61),
TEST(testQuads60),
diff --git a/tests/PathOpsSkpClipTest.cpp b/tests/PathOpsSkpClipTest.cpp
index da505451da..0e3cee9f4e 100755
--- a/tests/PathOpsSkpClipTest.cpp
+++ b/tests/PathOpsSkpClipTest.cpp
@@ -1,9 +1,13 @@
-
+#include "CrashHandler.h"
+// #include "OverwriteLine.h"
+#include "Resources.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkColorPriv.h"
+#include "SkCommandLineFlags.h"
#include "SkDevice.h"
+#include "SkForceLinking.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
@@ -16,209 +20,133 @@
#include "SkString.h"
#include "SkTArray.h"
#include "SkTDArray.h"
+#include "SkTemplates.h"
#include "SkThreadPool.h"
#include "SkTime.h"
-#include "Test.h"
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+/* add local exceptions here */
+/* TODO : add command flag interface */
+const struct SkipOverTest {
+ int directory;
+ const char* filename;
+ bool blamePathOps;
+} skipOver[] = {
+ { 2, "http___www_groupon_sg_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
+ { 6, "http___www_googleventures_com_.skp", true}, // addTCoincident SkASSERT(test->fT < 1);
+ { 7, "http___www_foxsports_nl_.skp", true}, // (no repro on mac) addT SkASSERT(this != other || fVerb == SkPath::kCubic_Verb)
+ {13, "http___www_modernqigong_com_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
+ {14, "http___www_devbridge_com_.skp", true}, // checkSmallCoincidence SkASSERT(!next->fSmall || checkMultiple);
+ {16, "http___www_1023world_net_.skp", true}, // bitmap decode assert (corrupt skp?)
+ {19, "http___www_alamdi_com_.skp", true}, // cubic/quad intersection
+ {26, "http___www_liveencounters_net_.skp", true}, // (no repro on mac) checkSmall addT:549 (line, expects cubic)
+ {28, "http___www_encros_fr_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
+ {37, "http___www_familysurvivalprotocol_wordpress_com_.skp", true}, // bumpSpan SkASSERT(span->fOppValue >= 0);
+ {39, "http___sufeinet_com_.skp", false}, // bitmap decode assert (corrupt skp?)
+ {41, "http___www_rano360_com_.skp", true}, // checkSmallCoincidence SkASSERT(!next->fSmall || checkMultiple);
+ {44, "http___www_firstunitedbank_com_.skp", true}, // addTCancel SkASSERT(oIndex > 0);
+ {46, "http___www_shinydemos_com_.skp", true}, // addSimpleAngle SkASSERT(index == count() - 2);
+ {48, "http___www_familysurvivalprotocol_com_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
+ {57, "http___www_lptemp_com_.skp", true}, // addTCoincident oPeek = &other->fTs[++oPeekIndex];
+ {71, "http___www_1milyonkahraman_org_.skp", true}, // addTCoincident SkASSERT(test->fT < 1);
+ {88, "http___www_apuntesdelechuza_wordpress_com_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
+ {89, "http___www_mobilizedconsulting_com_.skp", true}, // addTCancel SkASSERT(oIndex > 0);
+ {93, "http___www_simple_living_in_suffolk_co_uk_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
+};
+
+size_t skipOverCount = sizeof(skipOver) / sizeof(skipOver[0]);
+
+
+/* customize file in/out here */
+/* TODO : add command flag interface */
+#define CHROME_VERSION "1e5dfa4-4a995df"
+#define SUMMARY_RUN 1
#ifdef SK_BUILD_FOR_WIN
+ #define DRIVE_SPEC "D:"
#define PATH_SLASH "\\"
- #define IN_DIR "D:\\skp\\slave"
- #define OUT_DIR "D:\\skpOut\\1\\"
#else
+ #define DRIVE_SPEC ""
#define PATH_SLASH "/"
- #define IN_DIR "/skp/2311328-7fc2228/slave"
- #define OUT_DIR "/skpOut/4/"
#endif
-const struct {
- int directory;
- const char* filename;
-} skipOverSept[] = {
- { 3, "http___www_americascup_com_.skp"}, // !simple->closed()
- {18, "http___www_argus_presse_fr_.skp"}, // can't find winding of remaining vertical edge
- {31, "http___www_narayana_verlag_de_.skp"}, // !simple->closed()
- {36, "http___www_educationalcraft_com_.skp"}, // cubic / cubic near end / assert in SkIntersections::insert
- {44, "http___www_cooksnaps_com_.skp"}, // !simple->isClosed()
- {48, "http___www_narayana_publishers_com_.skp"}, // !simple->isClosed()
- {51, "http___www_freedominthe50states_org_.skp"}, // corrupt dash data
- {52, "http___www_aceinfographics_com_.skp"}, // right angle winding assert
- {53, "http___www_lojaanabotafogo_com_br_.skp"}, // rrect validate assert
- {57, "http___www_vantageproduction_com_.skp"}, // !isClosed()
- {64, "http___www_etiqadd_com_.skp"}, // !simple->closed()
- {84, "http___www_swapspacesystems_com_.skp"}, // !simple->closed()
- {90, "http___www_tcmevents_org_.skp"}, // !simple->closed()
- {96, "http___www_paseoitaigara_com_br_.skp"}, // !simple->closed()
- {98, "http___www_mortgagemarketguide_com_.skp"}, // !simple->closed()
- {99, "http___www_kitcheninspirations_wordpress_com_.skp"}, // checkSmall / bumpSpan
-};
+#define IN_DIR_PRE DRIVE_SPEC PATH_SLASH "skps" PATH_SLASH "slave"
+#define OUT_DIR_PRE DRIVE_SPEC PATH_SLASH "skpOut" PATH_SLASH "slave"
+#define OUT_DIR_SUM DRIVE_SPEC PATH_SLASH "skpOut" PATH_SLASH "summary"
+#define DIR_POST PATH_SLASH "All" PATH_SLASH CHROME_VERSION
+
+static const char outOpDir[] = "opClip";
+static const char outOldDir[] = "oldClip";
+static const char outStatusDir[] = "statusTest";
+
+static SkString get_in_path(int dirNo, const char* filename) {
+ SkString path;
+ SkASSERT(dirNo);
+ path.appendf("%s%d%s", IN_DIR_PRE, dirNo, DIR_POST);
+ if (!sk_exists(path.c_str())) {
+ SkDebugf("could not read %s\n", path.c_str());
+ return SkString();
+ }
+ if (filename) {
+ path.appendf("%s%s", PATH_SLASH, filename);
+ if (!sk_exists(path.c_str())) {
+ SkDebugf("could not read %s\n", path.c_str());
+ return SkString();
+ }
+ }
+ return path;
+}
+
+static void make_recursive_dir(const SkString& path) {
+ if (sk_exists(path.c_str())) {
+ return;
+ }
+ const char* pathStr = path.c_str();
+ int last = (int) path.size();
+ do {
+ while (last > 0 && pathStr[--last] != PATH_SLASH[0])
+ ;
+ SkASSERT(last > 0);
+ SkString shorter(pathStr, last);
+ if (sk_mkdir(shorter.c_str())) {
+ break;
+ }
+ } while (true);
+ do {
+ while (last < (int) path.size() && pathStr[++last] != PATH_SLASH[0])
+ ;
+ SkString shorter(pathStr, last);
+ SkAssertResult(sk_mkdir(shorter.c_str()));
+ } while (last < (int) path.size());
+}
+
+static SkString get_out_path(int dirNo, const char* dirName) {
+ SkString path;
+ SkASSERT(dirNo);
+ SkASSERT(dirName);
+ path.appendf("%s%d%s%s%s", OUT_DIR_PRE, dirNo, DIR_POST, PATH_SLASH, dirName);
+ make_recursive_dir(path);
+ return path;
+}
+
+static SkString get_sum_path(const char* dirName) {
+ SkString path;
+ SkASSERT(dirName);
+ path.appendf("%s%d%s%s", OUT_DIR_SUM, SUMMARY_RUN, PATH_SLASH, dirName);
+ SkDebugf("%s\n", path.c_str());
+ make_recursive_dir(path);
+ return path;
+}
+
+static SkString make_png_name(const char* filename) {
+ SkString pngName = SkString(filename);
+ pngName.remove(pngName.size() - 3, 3);
+ pngName.append("png");
+ return pngName;
+}
-/* stats
-97 http___www_brandyandvinca_com_.skp pixelError=3
-95 http___www_into_asia_com_.skp pixelError=12
-93 http___www_lunarplanner_com_.skp pixelError=14
-98 http___www_lovelyitalia_com_.skp pixelError=17
-90 http___www_inter_partner_blogspot_com_.skp pixelError=18
-99 http___www_maxarea_com_.skp pixelError=26
-98 http___www_maroonsnet_org_.skp pixelError=33
-92 http___www_belinaart_ru_.skp pixelError=50
-100 http___www_chroot_ro_.skp pixelError=62
-99 http___www_hsbrands_com_.skp pixelError=98
-95 http___www_tournamentindicator_com_.skp pixelError=122
-93 http___www_businesses_com_au_.skp pixelError=162
-90 http___www_regenesys_net_.skp pixelError=182
-88 http___www_1863544208148625103_c18eac63985503fa85b06358959c1ba27fc36f82_blogspot_com_.skp pixelError=186
-97 http___www_pregacoesevangelica_com_br_.skp pixelError=240
-77 http___www_zhenggang_org_.skp pixelError=284
-96 http___slidesharemailer_com_.skp pixelError=522
-94 http___www_gensteel_com_.skp pixelError=555
-68 http___www_jf_eti_br_.skp pixelError=610
-83 http___www_swishiat_com_.skp pixelError=706
-96 http___www_matusikmissive_com_au_.skp pixelError=2580
-95 http___www_momentumnation_com_.skp pixelError=3938
-92 http___www_rssowl_com_.skp pixelError=5113
-96 http___www_sexxygirl_tv_.skp pixelError=7605
-99 http___www_georgevalah_wordpress_com_.skp pixelError=8386
-78 http___www_furbo_org_.skp pixelError=8656
-78 http___www_djxhemary_wordpress_com_.skp pixelError=8976
-100 http___www_mindcontrolblackassassins_com_.skp pixelError=31950
-98 http___bababillgates_free_fr_.skp pixelError=40237
-98 http___hepatite_ro_.skp pixelError=44370
-86 http___www_somethingwagging_com_.skp pixelError=47794
-84 http___www_beverageuniverse_com_.skp pixelError=65450
-50 http___www_aveksa_com_.skp pixelError=68194
-10 http___www_publiker_pl_.skp pixelError=89997
-61 http___www_dominos_co_id_.skp pixelError=476868
-87 http___www_du_edu_om_.skp time=46
-87 http___www_bigload_de_.skp time=46
-100 http___www_home_forum_com_.skp time=48
-97 http___www_hotamateurchat_com_.skp time=48
-97 http___www_myrsky_com_cn_.skp time=48
-98 http___www_techiegeex_com_.skp time=49
-82 http___www_fashionoutletsofchicago_com_.skp time=50
-77 http___www_dynamischbureau_nl_.skp time=50
-82 http___www_mayihelpu_co_in_.skp time=50
-84 http___www_vbox7_com_user_history_viewers_.skp time=50
-85 http___www_ktokogda_com_.skp time=50
-85 http___www_propertyturkeysale_com_.skp time=50
-85 http___www_51play_com_.skp time=50
-86 http___www_bayalarm_com_.skp time=50
-87 http___www_eaglepictures_com_.skp time=50
-88 http___www_atlasakvaryum_com_.skp time=50
-91 http___www_pioneerchryslerjeep_com_.skp time=50
-94 http___www_thepulsemag_com_.skp time=50
-95 http___www_dcshoes_com_ph_.skp time=50
-96 http___www_montrealmassage_ca_.skp time=50
-96 http___www_jkshahclasses_com_.skp time=50
-96 http___www_webcamconsult_com_.skp time=51
-100 http___www_bsoscblog_com_.skp time=52
-95 http___www_flaktwoods_com_.skp time=53
-91 http___www_qivivo_com_.skp time=54
-90 http___www_unitender_com_.skp time=56
-97 http___www_casinogaming_com_.skp time=56
-97 http___www_rootdownload_com_.skp time=56
-94 http___www_aspa_ev_de_.skp time=57
-98 http___www_tenpieknyswiat_pl_.skp time=57
-93 http___www_transocean_de_.skp time=58
-94 http___www_vdo2_blogspot_com_.skp time=58
-94 http___www_asmaissexy_com_br_.skp time=58
-100 http___www_prefeiturasjm_com_br_.skp time=60
-100 http___www_eduinsuranceclick_blogspot_com_.skp time=60
-96 http___www_bobdunsire_com_.skp time=61
-96 http___www_omgkettlecorn_com_.skp time=61
-85 http___www_fbbsessions_com_.skp time=62
-86 http___www_hector_ru_.skp time=62
-87 http___www_wereldsupporter_nl_.skp time=62
-90 http___www_arello_com_.skp time=62
-93 http___www_bayerplastics_com_.skp time=62
-93 http___www_superandolamovida_com_ar_.skp time=62
-96 http___www_med_rbf_ru_.skp time=62
-81 http___www_carnegiescience_edu_.skp time=65
-87 http___www_asanewengland_com_.skp time=65
-92 http___www_turkce_karakter_appspot_com_.skp time=65
-94 http___www_k3a_org_.skp time=65
-96 http___www_powermaccenter_com_.skp time=65
-98 http___www_avto49_ru_.skp time=67
-100 http___www_hetoldeambaecht_nl_.skp time=68
-95 http___www_marine_ie_.skp time=69
-96 http___www_quebecvapeboutique_com_.skp time=69
-95 http___www_brays_ingles_com_.skp time=70
-100 http___www_lacondesa_com_.skp time=72
-95 http___www_timbarrathai_com_au_.skp time=76
-95 http___www_cuissedegrenouille_com_.skp time=76
-95 http___www_iwama51_ru_.skp time=76
-99 http___www_fotoantologia_it_.skp time=76
-92 http___www_indian_architects_com_.skp time=78
-92 http___www_totalwomanspa_com_.skp time=78
-100 http___www_fachverband_spielhallen_de_.skp time=83
-93 http___www_golshanemehr_ir_.skp time=84
-95 http___www_maryesses_com_.skp time=84
-99 http___www_ddcorp_ca_.skp time=89
-90 http___www_brontops_com_.skp time=89
-94 http___www_robgolding_com_.skp time=89
-91 http___www_tecban_com_br_.skp time=91
-98 http___www_costamesakarate_com_.skp time=100
-95 http___www_monsexyblog_com_.skp time=103
-97 http___www_stornowaygazette_co_uk_.skp time=103
-93 http___www_fitforaframe_com_.skp time=104
-98 http___www_intentionoftheday_com_.skp time=113
-100 http___www_tailgateclothing_com_.skp time=117
-95 http___www_senbros_com_.skp time=118
-93 http___www_lettoblog_com_.skp time=121
-94 http___www_maxineschallenge_com_au_.skp time=125
-95 http___www_savvycard_net_.skp time=127
-95 http___www_open_ac_mu_.skp time=129
-96 http___www_avgindia_in_.skp time=135
-97 http___www_stocktonseaview_com_.skp time=135
-96 http___www_distroller_com_.skp time=142
-94 http___www_travoggalop_dk_.skp time=144
-100 http___www_history_im_.skp time=144
-94 http___www_playradio_sk_.skp time=145
-92 http___www_linglongglass_com_.skp time=151
-97 http___www_bizzna_com_.skp time=151
-96 http___www_spiros_ws_.skp time=154
-91 http___www_rosen_meents_co_il_.skp time=156
-81 http___www_hoteldeluxeportland_com_.skp time=158
-92 http___www_freetennis_org_.skp time=161
-93 http___www_aircharternetwork_com_au_.skp time=161
-94 http___www_austinparks_org_.skp time=165
-89 http___www_bevvy_co_.skp time=168
-91 http___www_sosyalhile_net_.skp time=168
-98 http___www_minvih_gob_ve_.skp time=171
-89 http___www_streetfoodmtl_com_.skp time=172
-92 http___www_loveslatinas_tumblr_com_.skp time=178
-93 http___www_madbites_co_in_.skp time=180
-94 http___www_rocktarah_ir_.skp time=185
-97 http___www_penthouselife_com_.skp time=185
-96 http___www_appymonkey_com_.skp time=196
-92 http___www_pasargadhotels_com_.skp time=203
-99 http___www_marina_mil_pe_.skp time=203
-89 http___www_kays_co_uk_.skp time=205
-77 http___www_334588_com_.skp time=211
-83 http___www_trendbad24_de_.skp time=211
-81 http___www_cdnetworks_co_kr_.skp time=216
-94 http___www_schellgames_com_.skp time=223
-95 http___www_juliaweddingnews_cn_.skp time=230
-92 http___www_xcrafters_pl_.skp time=253
-93 http___www_pondoo_com_.skp time=253
-96 http___www_helsinkicapitalpartners_fi_.skp time=255
-88 http___www_nadtexican_com_.skp time=259
-85 http___www_canstockphoto_hu_.skp time=266
-78 http___www_ecovacs_com_cn_.skp time=271
-93 http___www_brookfieldplaceny_com_.skp time=334
-93 http___www_fmastrengthtraining_com_.skp time=337
-94 http___www_turtleonthebeach_com_.skp time=394
-90 http___www_temptationthemovie_com_.skp time=413
-95 http___www_patongsawaddi_com_.skp time=491
-91 http___www_online_radio_appspot_com_.skp time=511
-68 http___www_richardmiller_co_uk_.skp time=528
-63 http___www_eschrade_com_.skp time=543
-55 http___www_interaction_inf_br_.skp time=625
-38 http___www_huskyliners_com_.skp time=632
-86 http___granda_net_.skp time=1067
-24 http___www_cocacolafm_com_br_.skp time=1081
-*/
-
-size_t skipOverSeptCount = sizeof(skipOverSept) / sizeof(skipOverSept[0]);
+////////////////////////////////////////////////////////
enum TestStep {
kCompareBits,
@@ -238,6 +166,13 @@ struct TestResult {
fTestStep = kCompareBits;
fScale = 1;
}
+
+ void init(int dirNo, const SkString& filename) {
+ fDirNo = dirNo;
+ strcpy(fFilename, filename.c_str());
+ fTestStep = kCompareBits;
+ fScale = 1;
+ }
SkString status() {
SkString outStr;
@@ -262,14 +197,6 @@ struct TestResult {
}
- static void Test(int dirNo, const char* filename, TestStep testStep) {
- TestResult test;
- test.init(dirNo);
- test.fTestStep = testStep;
- strcpy(test.fFilename, filename);
- test.testOne();
- }
-
void test(int dirNo, const SkString& filename) {
init(dirNo);
strcpy(fFilename, filename.c_str());
@@ -277,7 +204,7 @@ struct TestResult {
}
void testOne();
-
+
char fFilename[kMaxLength];
TestStep fTestStep;
int fDirNo;
@@ -308,28 +235,24 @@ public:
};
struct TestState {
- void init(int dirNo, skiatest::Reporter* reporter) {
- fReporter = reporter;
+ void init(int dirNo) {
fResult.init(dirNo);
}
SkTDArray<SortByPixel> fPixelWorst;
SkTDArray<SortByTime> fSlowest;
- skiatest::Reporter* fReporter;
TestResult fResult;
};
struct TestRunner {
- TestRunner(skiatest::Reporter* reporter, int threadCount)
- : fNumThreads(threadCount)
- , fReporter(reporter) {
+ TestRunner(int threadCount)
+ : fNumThreads(threadCount) {
}
~TestRunner();
void render();
int fNumThreads;
SkTDArray<class TestRunnable*> fRunnables;
- skiatest::Reporter* fReporter;
};
class TestRunnable : public SkRunnable {
@@ -347,7 +270,7 @@ public:
class TestRunnableDir : public TestRunnable {
public:
TestRunnableDir(void (*testFun)(TestState*), int dirNo, TestRunner* runner) {
- fState.init(dirNo, runner->fReporter);
+ fState.init(dirNo);
fTestFun = testFun;
}
@@ -356,7 +279,7 @@ public:
class TestRunnableFile : public TestRunnable {
public:
TestRunnableFile(void (*testFun)(TestState*), int dirNo, const char* name, TestRunner* runner) {
- fState.init(dirNo, runner->fReporter);
+ fState.init(dirNo);
strcpy(fState.fResult.fFilename, name);
fTestFun = testFun;
}
@@ -385,74 +308,6 @@ void TestRunner::render() {
////////////////////////////////////////////////
-static const char outOpDir[] = OUT_DIR "opClip";
-static const char outOldDir[] = OUT_DIR "oldClip";
-static const char outSkpDir[] = OUT_DIR "skpTest";
-static const char outDiffDir[] = OUT_DIR "outTest";
-static const char outStatusDir[] = OUT_DIR "statusTest";
-
-static SkString make_filepath(int dirNo, const char* dir, const char* name) {
- SkString path(dir);
- if (dirNo) {
- path.appendf("%d", dirNo);
- }
- path.append(PATH_SLASH);
- path.append(name);
- return path;
-}
-
-static SkString make_in_dir_name(int dirNo) {
- SkString dirName(IN_DIR);
- dirName.appendf("%d", dirNo);
- if (!sk_exists(dirName.c_str())) {
- SkDebugf("could not read dir %s\n", dirName.c_str());
- return SkString();
- }
- return dirName;
-}
-
-static SkString make_stat_dir_name(int dirNo) {
- SkString dirName(outStatusDir);
- dirName.appendf("%d", dirNo);
- if (!sk_exists(dirName.c_str())) {
- SkDebugf("could not read dir %s\n", dirName.c_str());
- return SkString();
- }
- return dirName;
-}
-
-static bool make_one_out_dir(const char* outDirStr) {
- SkString outDir = make_filepath(0, outDirStr, "");
- if (!sk_exists(outDir.c_str())) {
- if (!sk_mkdir(outDir.c_str())) {
- SkDebugf("could not create dir %s\n", outDir.c_str());
- return false;
- }
- }
- return true;
-}
-
-static bool make_out_dirs() {
- SkString outDir = make_filepath(0, OUT_DIR, "");
- if (!sk_exists(outDir.c_str())) {
- if (!sk_mkdir(outDir.c_str())) {
- SkDebugf("could not create dir %s\n", outDir.c_str());
- return false;
- }
- }
- return make_one_out_dir(outOldDir)
- && make_one_out_dir(outOpDir)
- && make_one_out_dir(outSkpDir)
- && make_one_out_dir(outDiffDir)
- && make_one_out_dir(outStatusDir);
-}
-
-static SkString make_png_name(const char* filename) {
- SkString pngName = SkString(filename);
- pngName.remove(pngName.size() - 3, 3);
- pngName.append("png");
- return pngName;
-}
static int similarBits(const SkBitmap& gr, const SkBitmap& sk) {
const int kRowCount = 3;
@@ -574,9 +429,9 @@ static void drawPict(SkPicture* pic, SkCanvas* canvas, int scale) {
}
static void writePict(const SkBitmap& bitmap, const char* outDir, const char* pngName) {
- SkString outFile = make_filepath(0, outDir, pngName);
- if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap,
- SkImageEncoder::kPNG_Type, 100)) {
+ SkString outFile = get_sum_path(outDir);
+ outFile.appendf("%s%s", PATH_SLASH, pngName);
+ if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100)) {
SkDebugf("unable to encode gr %s (width=%d height=%d)\n", pngName,
bitmap.width(), bitmap.height());
}
@@ -607,7 +462,7 @@ void TestResult::testOne() {
strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
}
#endif
- SkString path = make_filepath(fDirNo, IN_DIR, fFilename);
+ SkString path = get_in_path(fDirNo, fFilename);
SkFILEStream stream(path.c_str());
if (!stream.isValid()) {
SkDebugf("invalid stream %s\n", path.c_str());
@@ -665,189 +520,255 @@ finish:
}
}
-static SkString makeStatusString(int dirNo) {
- SkString statName;
- statName.printf("stats%d.txt", dirNo);
- SkString statusFile = make_filepath(0, outStatusDir, statName.c_str());
- return statusFile;
+DEFINE_string2(match, m, "PathOpsSkpClipThreaded",
+ "[~][^]substring[$] [...] of test name to run.\n"
+ "Multiple matches may be separated by spaces.\n"
+ "~ causes a matching test to always be skipped\n"
+ "^ requires the start of the test to match\n"
+ "$ requires the end of the test to match\n"
+ "^ and $ requires an exact match\n"
+ "If a test does not match any list entry,\n"
+ "it is skipped unless some list entry starts with ~");
+DEFINE_string2(dir, d, NULL, "range of directories (e.g., 1-100)");
+DEFINE_string2(skp, s, NULL, "skp to test");
+DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
+DEFINE_int32(testIndex, 0, "override local test index (PathOpsSkpClipOneOff only).");
+DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
+ "Run threadsafe tests on a threadpool with this many threads.");
+DEFINE_bool2(verbose, v, false, "enable verbose output.");
+
+static bool verbose() {
+ return FLAGS_verbose;
+}
+
+static int getThreadCount() {
+ return FLAGS_single ? 1 : FLAGS_threads;
}
-class PreParser {
+class Dirs {
public:
- PreParser(int dirNo, bool threaded)
- : fDirNo(dirNo)
- , fIndex(0)
- , fThreaded(threaded) {
- SkString statusPath = makeStatusString(dirNo);
- if (!sk_exists(statusPath.c_str())) {
- return;
+ Dirs() {
+ reset();
+ sk_bzero(fRun, sizeof(fRun));
+ fSet = false;
+ }
+
+ int first() const {
+ int index = 0;
+ while (++index < kMaxDir) {
+ if (fRun[index]) {
+ return index;
+ }
}
- SkFILEStream reader;
- reader.setPath(statusPath.c_str());
- while (fetch(reader, &fResults.push_back()))
+ SkASSERT(0);
+ return -1;
+ }
+
+ int last() const {
+ int index = kMaxDir;
+ while (--index > 0 && !fRun[index])
;
- fResults.pop_back();
+ return index;
}
- bool fetch(SkFILEStream& reader, TestResult* result) {
- char c;
- int i = 0;
- result->init(fDirNo);
- result->fPixelError = 0;
- result->fTime = 0;
- do {
- bool readOne = reader.read(&c, 1) != 0;
- if (!readOne) {
-// SkASSERT(i == 0); // the current text may be incomplete -- if so, ignore it
- return false;
+ int next() {
+ while (++fIndex < kMaxDir) {
+ if (fRun[fIndex]) {
+ return fIndex;
}
- if (c == ' ') {
- result->fFilename[i++] = '\0';
- break;
- }
- result->fFilename[i++] = c;
- SkASSERT(i < kMaxLength);
- } while (true);
- do {
- if (!reader.read(&c, 1)) {
- return false;
- }
- if (c == ' ') {
- break;
- }
- SkASSERT(c >= '0' && c <= '9');
- result->fPixelError = result->fPixelError * 10 + (c - '0');
- } while (true);
- bool minus = false;
- do {
- if (!reader.read(&c, 1)) {
- return false;
- }
- if (c == '\n') {
- break;
- }
- if (c == '-') {
- minus = true;
- continue;
- }
- SkASSERT(c >= '0' && c <= '9');
- result->fTime = result->fTime * 10 + (c - '0');
- } while (true);
- if (minus) {
- result->fTime = -result->fTime;
}
- return true;
+ return -1;
}
- bool match(const SkString& filename, SkFILEWStream* stream, TestResult* result) {
- if (fThreaded) {
- for (int index = 0; index < fResults.count(); ++index) {
- const TestResult& test = fResults[index];
- if (filename.equals(test.fFilename)) {
- *result = test;
- SkString outStr(result->status());
- stream->write(outStr.c_str(), outStr.size());
- return true;
- }
- }
- } else if (fIndex < fResults.count()) {
- *result = fResults[fIndex++];
- SkASSERT(filename.equals(result->fFilename));
- SkString outStr(result->status());
- stream->write(outStr.c_str(), outStr.size());
- return true;
+ void reset() {
+ fIndex = -1;
+ }
+
+ void set(int start, int end) {
+ while (start < end) {
+ fRun[start++] = 1;
+ }
+ fSet = true;
+ }
+
+ void setDefault() {
+ if (!fSet) {
+ set(1, 100);
}
- return false;
}
private:
- int fDirNo;
+ enum {
+ kMaxDir = 101
+ };
+ char fRun[kMaxDir];
int fIndex;
- SkTArray<TestResult, true> fResults;
- bool fThreaded;
-};
+ bool fSet;
+} gDirs;
+
+class Filenames {
+public:
+ Filenames()
+ : fIndex(-1) {
+ }
+
+ const char* next() {
+ while (fNames && ++fIndex < fNames->count()) {
+ return (*fNames)[fIndex];
+ }
+ return NULL;
+ }
+
+ void set(const SkCommandLineFlags::StringArray& names) {
+ fNames = &names;
+ }
+
+private:
+ int fIndex;
+ const SkCommandLineFlags::StringArray* fNames;
+} gNames;
+
+static bool buildTestDir(int dirNo, int firstDirNo,
+ SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
+ SkString dirName = get_out_path(dirNo, outStatusDir);
+ if (!dirName.size()) {
+ return false;
+ }
+ SkOSFile::Iter iter(dirName.c_str(), "skp");
+ SkString filename;
+ while (iter.next(&filename)) {
+ TestResult test;
+ test.init(dirNo);
+ SkString spaceFile(filename);
+ char* spaces = spaceFile.writable_str();
+ int spaceSize = (int) spaceFile.size();
+ for (int index = 0; index < spaceSize; ++index) {
+ if (spaces[index] == '.') {
+ spaces[index] = ' ';
+ }
+ }
+ int success = sscanf(spaces, "%s %d %d skp", test.fFilename,
+ &test.fPixelError, &test.fTime);
+ if (success < 3) {
+ SkDebugf("failed to scan %s matched=%d\n", filename.c_str(), success);
+ return false;
+ }
+ *tests[dirNo - firstDirNo].append() = test;
+ }
+ if (!sorted) {
+ return true;
+ }
+ SkTDArray<TestResult>& testSet = tests[dirNo - firstDirNo];
+ int count = testSet.count();
+ for (int index = 0; index < count; ++index) {
+ *sorted[dirNo - firstDirNo].append() = (SortByName*) &testSet[index];
+ }
+ if (sorted[dirNo - firstDirNo].count()) {
+ SkTQSort<SortByName>(sorted[dirNo - firstDirNo].begin(),
+ sorted[dirNo - firstDirNo].end() - 1);
+ if (verbose()) {
+ SkDebugf("+");
+ }
+ }
+ return true;
+}
+
+static void testSkpClip(TestState* data) {
+ data->fResult.testOne();
+ SkString statName(data->fResult.fFilename);
+ SkASSERT(statName.endsWith(".skp"));
+ statName.remove(statName.size() - 4, 4);
+ statName.appendf(".%d.%d.skp", data->fResult.fPixelError, data->fResult.fTime);
+ SkString statusFile = get_out_path(data->fResult.fDirNo, outStatusDir);
+ if (!statusFile.size()) {
+ SkDebugf("failed to create %s", statusFile.c_str());
+ return;
+ }
+ statusFile.appendf("%s%s", PATH_SLASH, statName.c_str());
+ SkFILE* file = sk_fopen(statusFile.c_str(), kWrite_SkFILE_Flag);
+ if (!file) {
+ SkDebugf("failed to create %s", statusFile.c_str());
+ return;
+ }
+ sk_fclose(file);
+ if (verbose()) {
+ if (data->fResult.fPixelError || data->fResult.fTime) {
+ SkDebugf("%s", data->fResult.progress().c_str());
+ } else {
+ SkDebugf(".");
+ }
+ }
+}
+
+bool Less(const SortByName& a, const SortByName& b);
+bool Less(const SortByName& a, const SortByName& b) {
+ return a < b;
+}
static bool doOneDir(TestState* state, bool threaded) {
int dirNo = state->fResult.fDirNo;
- skiatest::Reporter* reporter = state->fReporter;
- SkString dirName = make_in_dir_name(dirNo);
+ SkString dirName = get_in_path(dirNo, NULL);
if (!dirName.size()) {
return false;
}
+ SkTDArray<TestResult> tests[1];
+ SkTDArray<SortByName*> sorted[1];
+ if (!buildTestDir(dirNo, dirNo, tests, sorted)) {
+ return false;
+ }
SkOSFile::Iter iter(dirName.c_str(), "skp");
SkString filename;
- int testCount = 0;
- PreParser preParser(dirNo, threaded);
- SkFILEWStream statusStream(makeStatusString(dirNo).c_str());
while (iter.next(&filename)) {
- for (size_t index = 0; index < skipOverSeptCount; ++index) {
- if (skipOverSept[index].directory == dirNo
- && strcmp(filename.c_str(), skipOverSept[index].filename) == 0) {
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ if (skipOver[index].directory == dirNo
+ && strcmp(filename.c_str(), skipOver[index].filename) == 0) {
goto checkEarlyExit;
}
}
- if (preParser.match(filename, &statusStream, &state->fResult)) {
- (void) addError(state, state->fResult);
- ++testCount;
- goto checkEarlyExit;
- }
{
- TestResult& result = state->fResult;
- result.test(dirNo, filename);
- SkString outStr(result.status());
- statusStream.write(outStr.c_str(), outStr.size());
- statusStream.flush();
- if (addError(state, result)) {
- SkDebugf("%s", result.progress().c_str());
+ SortByName name;
+ name.init(dirNo);
+ strncpy(name.fFilename, filename.c_str(), filename.size() - 4); // drop .skp
+ int count = sorted[0].count();
+ int idx = SkTSearch<SortByName, Less>(sorted[0].begin(), count, &name, sizeof(&name));
+ if (idx >= 0) {
+ SortByName* found = sorted[0][idx];
+ (void) addError(state, *found);
+ continue;
}
- }
- ++testCount;
- if (reporter->verbose()) {
- SkDebugf(".");
- if (++testCount % 100 == 0) {
- SkDebugf("%d\n", testCount);
+ TestResult test;
+ test.init(dirNo, filename);
+ state->fResult = test;
+ testSkpClip(state);
+#if 0 // artificially limit to a few while debugging code
+ static int debugLimit = 0;
+ if (++debugLimit == 5) {
+ return true;
}
+#endif
}
checkEarlyExit:
- if (0 && testCount >= 1) {
- return true;
- }
+ ;
}
return true;
}
-static bool initTest() {
+static void initTest() {
#if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC
SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
SK_CONF_SET("images.png.suppressDecoderWarnings", true);
#endif
- return make_out_dirs();
}
-static bool initUberTest(int firstDirNo, int lastDirNo) {
- if (!initTest()) {
- return false;
- }
- for (int index = firstDirNo; index <= lastDirNo; ++index) {
- SkString statusDir(outStatusDir);
- statusDir.appendf("%d", index);
- if (!make_one_out_dir(statusDir.c_str())) {
- return false;
- }
- }
- return true;
-}
-
-
static void testSkpClipEncode(TestState* data) {
data->fResult.testOne();
- if (data->fReporter->verbose()) {
- SkDebugf("+");
+ if (verbose()) {
+ SkDebugf("+");
}
}
-static void encodeFound(skiatest::Reporter* reporter, TestState& state) {
- if (reporter->verbose()) {
+static void encodeFound(TestState& state) {
+ if (verbose()) {
if (state.fPixelWorst.count()) {
SkTDArray<SortByPixel*> worst;
for (int index = 0; index < state.fPixelWorst.count(); ++index) {
@@ -873,9 +794,8 @@ static void encodeFound(skiatest::Reporter* reporter, TestState& state) {
}
}
}
-
- int threadCount = reporter->allowThreaded() ? SkThreadPool::kThreadPerCore : 1;
- TestRunner testRunner(reporter, threadCount);
+ int threadCount = getThreadCount();
+ TestRunner testRunner(threadCount);
for (int index = 0; index < state.fPixelWorst.count(); ++index) {
const TestResult& result = state.fPixelWorst[index];
SkString filename(result.fFilename);
@@ -886,28 +806,50 @@ static void encodeFound(skiatest::Reporter* reporter, TestState& state) {
(&testSkpClipEncode, result.fDirNo, filename.c_str(), &testRunner));
}
testRunner.render();
-#if 0
- for (int index = 0; index < state.fPixelWorst.count(); ++index) {
- const TestResult& result = state.fPixelWorst[index];
- SkString filename(result.fFilename);
- if (!filename.endsWith(".skp")) {
- filename.append(".skp");
- }
- TestResult::Test(result.fDirNo, filename.c_str(), kEncodeFiles);
- if (reporter->verbose()) SkDebugf("+");
- }
-#endif
}
-DEF_TEST(PathOpsSkpClip, reporter) {
- if (!initTest()) {
- return;
- }
+class Test {
+public:
+ Test() {}
+ virtual ~Test() {}
+
+ const char* getName() { onGetName(&fName); return fName.c_str(); }
+ void run() { onRun(); }
+
+protected:
+ virtual void onGetName(SkString*) = 0;
+ virtual void onRun() = 0;
+
+private:
+ SkString fName;
+};
+
+typedef SkTRegistry<Test*(*)(void*)> TestRegistry;
+
+#define DEF_TEST(name) \
+ static void test_##name(); \
+ class name##Class : public Test { \
+ public: \
+ static Test* Factory(void*) { return SkNEW(name##Class); } \
+ protected: \
+ virtual void onGetName(SkString* name) SK_OVERRIDE { \
+ name->set(#name); \
+ } \
+ virtual void onRun() SK_OVERRIDE { test_##name(); } \
+ }; \
+ static TestRegistry gReg_##name##Class(name##Class::Factory); \
+ static void test_##name()
+
+DEF_TEST(PathOpsSkpClip) {
+ gDirs.setDefault();
+ initTest();
SkTArray<TestResult, true> errors;
TestState state;
- state.init(0, reporter);
- for (int dirNo = 1; dirNo <= 100; ++dirNo) {
- if (reporter->verbose()) {
+ state.init(0);
+ int dirNo;
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
+ if (verbose()) {
SkDebugf("dirNo=%d\n", dirNo);
}
state.fResult.fDirNo = dirNo;
@@ -915,28 +857,29 @@ DEF_TEST(PathOpsSkpClip, reporter) {
break;
}
}
- encodeFound(reporter, state);
+ encodeFound(state);
}
static void testSkpClipMain(TestState* data) {
(void) doOneDir(data, true);
}
-DEF_TEST(PathOpsSkpClipThreaded, reporter) {
- if (!initTest()) {
- return;
- }
- int threadCount = reporter->allowThreaded() ? SkThreadPool::kThreadPerCore : 1;
- TestRunner testRunner(reporter, threadCount);
- const int firstDirNo = 1;
- for (int dirNo = firstDirNo; dirNo <= 100; ++dirNo) {
+DEF_TEST(PathOpsSkpClipThreaded) {
+ gDirs.setDefault();
+ initTest();
+ int threadCount = getThreadCount();
+ TestRunner testRunner(threadCount);
+ int dirNo;
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
*testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableDir,
(&testSkpClipMain, dirNo, &testRunner));
}
testRunner.render();
TestState state;
- state.init(0, reporter);
- for (int dirNo = firstDirNo; dirNo <= 100; ++dirNo) {
+ state.init(0);
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
TestState& testState = testRunner.fRunnables[dirNo - 1]->fState;
SkASSERT(testState.fResult.fDirNo == dirNo);
for (int inner = 0; inner < testState.fPixelWorst.count(); ++inner) {
@@ -946,124 +889,59 @@ DEF_TEST(PathOpsSkpClipThreaded, reporter) {
addError(&state, testState.fSlowest[inner]);
}
}
- encodeFound(reporter, state);
-}
-
-static void testSkpClipUber(TestState* data) {
- data->fResult.testOne();
- SkString dirName = make_stat_dir_name(data->fResult.fDirNo);
- if (!dirName.size()) {
- return;
- }
- SkString statName(data->fResult.fFilename);
- SkASSERT(statName.endsWith(".skp"));
- statName.remove(statName.size() - 4, 4);
- statName.appendf(".%d.%d.skp", data->fResult.fPixelError, data->fResult.fTime);
- SkString statusFile = make_filepath(data->fResult.fDirNo, outStatusDir, statName.c_str());
- SkFILE* file = sk_fopen(statusFile.c_str(), kWrite_SkFILE_Flag);
- if (!file) {
- SkDebugf("failed to create %s", statusFile.c_str());
- return;
- }
- sk_fclose(file);
- if (data->fReporter->verbose()) {
- if (data->fResult.fPixelError || data->fResult.fTime) {
- SkDebugf("%s", data->fResult.progress().c_str());
- } else {
- SkDebugf(".");
- }
- }
+ encodeFound(state);
}
-
-static bool buildTests(skiatest::Reporter* reporter, int firstDirNo, int lastDirNo, SkTDArray<TestResult>* tests,
- SkTDArray<SortByName*>* sorted) {
- for (int dirNo = firstDirNo; dirNo <= lastDirNo; ++dirNo) {
- SkString dirName = make_stat_dir_name(dirNo);
- if (!dirName.size()) {
+
+static bool buildTests(SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
+ int firstDirNo = gDirs.first();
+ int dirNo;
+ while ((dirNo = gDirs.next()) > 0) {
+ if (!buildTestDir(dirNo, firstDirNo, tests, sorted)) {
return false;
}
- SkOSFile::Iter iter(dirName.c_str(), "skp");
- SkString filename;
- while (iter.next(&filename)) {
- TestResult test;
- test.init(dirNo);
- SkString spaceFile(filename);
- char* spaces = spaceFile.writable_str();
- int spaceSize = (int) spaceFile.size();
- for (int index = 0; index < spaceSize; ++index) {
- if (spaces[index] == '.') {
- spaces[index] = ' ';
- }
- }
- int success = sscanf(spaces, "%s %d %d skp", test.fFilename,
- &test.fPixelError, &test.fTime);
- if (success < 3) {
- SkDebugf("failed to scan %s matched=%d\n", filename.c_str(), success);
- return false;
- }
- *tests[dirNo - firstDirNo].append() = test;
- }
- if (!sorted) {
- continue;
- }
- SkTDArray<TestResult>& testSet = tests[dirNo - firstDirNo];
- int count = testSet.count();
- for (int index = 0; index < count; ++index) {
- *sorted[dirNo - firstDirNo].append() = (SortByName*) &testSet[index];
- }
- if (sorted[dirNo - firstDirNo].count()) {
- SkTQSort<SortByName>(sorted[dirNo - firstDirNo].begin(),
- sorted[dirNo - firstDirNo].end() - 1);
- if (reporter->verbose()) {
- SkDebugf("+");
- }
- }
}
return true;
}
-bool Less(const SortByName& a, const SortByName& b);
-bool Less(const SortByName& a, const SortByName& b) {
- return a < b;
-}
-
-DEF_TEST(PathOpsSkpClipUberThreaded, reporter) {
- const int firstDirNo = 1;
- const int lastDirNo = 100;
- if (!initUberTest(firstDirNo, lastDirNo)) {
+DEF_TEST(PathOpsSkpClipUberThreaded) {
+ gDirs.setDefault();
+ const int firstDirNo = gDirs.next();
+ const int lastDirNo = gDirs.last();
+ initTest();
+ int dirCount = lastDirNo - firstDirNo + 1;
+ SkAutoTDeleteArray<SkTDArray<TestResult> > tests(new SkTDArray<TestResult>[dirCount]);
+ SkAutoTDeleteArray<SkTDArray<SortByName*> > sorted(new SkTDArray<SortByName*>[dirCount]);
+ if (!buildTests(tests.get(), sorted.get())) {
return;
}
- const int dirCount = lastDirNo - firstDirNo + 1;
- SkTDArray<TestResult> tests[dirCount];
- SkTDArray<SortByName*> sorted[dirCount];
- if (!buildTests(reporter, firstDirNo, lastDirNo, tests, sorted)) {
- return;
- }
- int threadCount = reporter->allowThreaded() ? SkThreadPool::kThreadPerCore : 1;
- TestRunner testRunner(reporter, threadCount);
- for (int dirNo = firstDirNo; dirNo <= lastDirNo; ++dirNo) {
- SkString dirName = make_in_dir_name(dirNo);
+ int threadCount = getThreadCount();
+ TestRunner testRunner(threadCount);
+ int dirNo;
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
+ SkString dirName = get_in_path(dirNo, NULL);
if (!dirName.size()) {
continue;
}
SkOSFile::Iter iter(dirName.c_str(), "skp");
SkString filename;
while (iter.next(&filename)) {
- int count;
- SortByName name;
- for (size_t index = 0; index < skipOverSeptCount; ++index) {
- if (skipOverSept[index].directory == dirNo
- && strcmp(filename.c_str(), skipOverSept[index].filename) == 0) {
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ if (skipOver[index].directory == dirNo
+ && strcmp(filename.c_str(), skipOver[index].filename) == 0) {
goto checkEarlyExit;
}
}
- name.init(dirNo);
- strncpy(name.fFilename, filename.c_str(), filename.size() - 4); // drop .skp
- count = sorted[dirNo - firstDirNo].count();
- if (SkTSearch<SortByName, Less>(sorted[dirNo - firstDirNo].begin(),
- count, &name, sizeof(&name)) < 0) {
- *testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableFile,
- (&testSkpClipUber, dirNo, filename.c_str(), &testRunner));
+ {
+ SortByName name;
+ name.init(dirNo);
+ strncpy(name.fFilename, filename.c_str(), filename.size() - 4); // drop .skp
+ int count = sorted.get()[dirNo - firstDirNo].count();
+ if (SkTSearch<SortByName, Less>(sorted.get()[dirNo - firstDirNo].begin(),
+ count, &name, sizeof(&name)) < 0) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableFile,
+ (&testSkpClip, dirNo, filename.c_str(), &testRunner));
+ }
}
checkEarlyExit:
;
@@ -1071,13 +949,13 @@ DEF_TEST(PathOpsSkpClipUberThreaded, reporter) {
}
testRunner.render();
- SkTDArray<TestResult> results[dirCount];
- if (!buildTests(reporter, firstDirNo, lastDirNo, results, NULL)) {
+ SkAutoTDeleteArray<SkTDArray<TestResult> > results(new SkTDArray<TestResult>[dirCount]);
+ if (!buildTests(results.get(), NULL)) {
return;
}
SkTDArray<TestResult> allResults;
for (int dirNo = firstDirNo; dirNo <= lastDirNo; ++dirNo) {
- SkTDArray<TestResult>& array = results[dirNo - firstDirNo];
+ SkTDArray<TestResult>& array = results.get()[dirNo - firstDirNo];
allResults.append(array.count(), array.begin());
}
int allCount = allResults.count();
@@ -1100,22 +978,144 @@ DEF_TEST(PathOpsSkpClipUberThreaded, reporter) {
*state.fSlowest.append() = *times[allCount - inner - 1];
}
}
- encodeFound(reporter, state);
+ encodeFound(state);
}
-DEF_TEST(PathOpsSkpClipOneOff, reporter) {
- if (!initTest()) {
- return;
+DEF_TEST(PathOpsSkpClipOneOff) {
+ const int testIndex = FLAGS_testIndex;
+ int dirNo = gDirs.next();
+ if (dirNo < 0) {
+ dirNo = skipOver[testIndex].directory;
+ }
+ const char* skp = gNames.next();
+ if (!skp) {
+ skp = skipOver[testIndex].filename;
}
- const int testIndex = 43 - 37;
- int dirNo = skipOverSept[testIndex].directory;
- SkAssertResult(make_in_dir_name(dirNo).size());
- SkString filename(skipOverSept[testIndex].filename);
+ initTest();
+ SkAssertResult(get_in_path(dirNo, skp).size());
+ SkString filename(skp);
TestResult state;
state.test(dirNo, filename);
- if (reporter->verbose()) {
+ if (verbose()) {
SkDebugf("%s", state.status().c_str());
}
state.fTestStep = kEncodeFiles;
state.testOne();
}
+
+DEF_TEST(PathOpsTestSkipped) {
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ const SkipOverTest& skip = skipOver[index];
+ if (!skip.blamePathOps) {
+ continue;
+ }
+ int dirNo = skip.directory;
+ const char* skp = skip.filename;
+ initTest();
+ SkAssertResult(get_in_path(dirNo, skp).size());
+ SkString filename(skp);
+ TestResult state;
+ state.test(dirNo, filename);
+ if (verbose()) {
+ SkDebugf("%s", state.status().c_str());
+ }
+ state.fTestStep = kEncodeFiles;
+ state.testOne();
+ }
+}
+
+DEF_TEST(PathOpsCopyFails) {
+ FLAGS_verbose = true;
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ int dirNo = skipOver[index].directory;
+ SkDebugf("mkdir -p " IN_DIR_PRE "%d" DIR_POST "\n", dirNo);
+ }
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ int dirNo = skipOver[index].directory;
+ const char* filename = skipOver[index].filename;
+ SkDebugf("rsync -av cary-linux.cnc:/tera" PATH_SLASH "skps" PATH_SLASH "slave"
+ "%d" DIR_POST "/%s " IN_DIR_PRE "%d" DIR_POST "\n", dirNo, filename, dirNo);
+ }
+}
+
+template TestRegistry* TestRegistry::gHead;
+
+class Iter {
+public:
+ Iter() { this->reset(); }
+ void reset() { fReg = TestRegistry::Head(); }
+
+ Test* next() {
+ if (fReg) {
+ TestRegistry::Factory fact = fReg->factory();
+ fReg = fReg->next();
+ Test* test = fact(NULL);
+ return test;
+ }
+ return NULL;
+ }
+
+private:
+ const TestRegistry* fReg;
+};
+
+int tool_main(int argc, char** argv);
+int tool_main(int argc, char** argv) {
+ SetupCrashHandler();
+ SkCommandLineFlags::SetUsage("");
+ SkCommandLineFlags::Parse(argc, argv);
+ SkGraphics::Init();
+ SkString header("PathOps SkpClip:");
+ if (!FLAGS_match.isEmpty()) {
+ header.appendf(" --match");
+ for (int index = 0; index < FLAGS_match.count(); ++index) {
+ header.appendf(" %s", FLAGS_match[index]);
+ }
+ }
+ if (!FLAGS_dir.isEmpty()) {
+ int count = FLAGS_dir.count();
+ for (int i = 0; i < count; ++i) {
+ const char* range = FLAGS_dir[i];
+ const char* dash = strchr(range, '-');
+ if (!dash) {
+ dash = strchr(range, ',');
+ }
+ int first = atoi(range);
+ int last = dash ? atoi(dash + 1) : first;
+ if (!first || !last) {
+ SkDebugf("couldn't parse --dir %s\n", range);
+ return 1;
+ }
+ gDirs.set(first, last);
+ }
+ }
+ if (!FLAGS_skp.isEmpty()) {
+ gNames.set(FLAGS_skp);
+ }
+#ifdef SK_DEBUG
+ header.append(" SK_DEBUG");
+#else
+ header.append(" SK_RELEASE");
+#endif
+ header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
+ if (FLAGS_verbose) {
+ header.appendf("\n");
+ }
+ SkDebugf(header.c_str());
+ Iter iter;
+ Test* test;
+ while ((test = iter.next()) != NULL) {
+ SkAutoTDelete<Test> owned(test);
+ if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
+ test->run();
+ }
+ }
+ SkGraphics::Term();
+ return 0;
+}
+
+#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
+int main(int argc, char * const argv[]) {
+ return tool_main(argc, (char**) argv);
+}
+#endif
diff --git a/tests/PathOpsSkpTest.cpp b/tests/PathOpsSkpTest.cpp
index d62e326278..2da38f4166 100755
--- a/tests/PathOpsSkpTest.cpp
+++ b/tests/PathOpsSkpTest.cpp
@@ -8,6 +8,8 @@
#define TEST(name) { name, #name }
+#define TEST_NEW_FAILURES 0
+
static void skpcheeseandburger_com225(skiatest::Reporter* reporter, const char* filename) {
SkPath path;
path.setFillType(SkPath::kEvenOdd_FillType);
@@ -3547,9 +3549,233 @@ static void skpwww_mortgagemarketguide_com_109(skiatest::Reporter* reporter, con
testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
}
+static void skpwww_9to5mac_com_64(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(365, 5101);
+ path.lineTo(365, 5082);
+ path.lineTo(366, 5083);
+ path.lineTo(367, 5092.96631f);
+ path.lineTo(367, 5100);
+ path.quadTo(367, 5101.50537f, 367.967712f, 5102.61084f);
+ path.lineTo(368.278717f, 5105.71045f);
+ path.quadTo(367.277618f, 5105.34863f, 366.464478f, 5104.53564f);
+ path.quadTo(365, 5103.07129f, 365, 5101);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(365, 5082);
+ pathB.lineTo(365.848175f, 5081.15186f);
+ pathB.lineTo(368, 5103);
+ pathB.lineTo(365, 5106);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+#if TEST_NEW_FAILURES
+// addTCoincident SkASSERT(test->fT < 1);
+static void skpwww_googleventures_com_32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(725.911682f, 898.767456f);
+ path.lineTo(741.232544f, 885.911682f);
+ path.lineTo(754.088318f, 901.232544f);
+ path.lineTo(738.767456f, 914.088318f);
+ path.lineTo(725.911682f, 898.767456f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(728.37677f, 870.59082f);
+ pathB.lineTo(754.088257f, 901.232605f);
+ pathB.lineTo(738.767395f, 914.088379f);
+ pathB.lineTo(713.055908f, 883.446594f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// checkSmallCoincidence failed assertion "!next->fSmall || checkMultiple"
+static void skpwww_devbridge_com_22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(4915, 1523);
+ path.quadTo(4887.24756f, 1523, 4867.62402f, 1542.6239f);
+ path.quadTo(4848, 1562.24768f, 4848, 1590);
+ path.quadTo(4848, 1617.75232f, 4867.62402f, 1637.3761f);
+ path.quadTo(4887.24756f, 1657, 4915, 1657);
+ path.quadTo(4942.75244f, 1657, 4962.37598f, 1637.3761f);
+ path.quadTo(4982, 1617.75232f, 4982, 1590);
+ path.quadTo(4982, 1562.24768f, 4962.37598f, 1542.6239f);
+ path.quadTo(4942.75244f, 1523, 4915, 1523);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4981.99902f, 1590);
+ pathB.quadTo(4981.99902f, 1617.75232f, 4962.375f, 1637.3761f);
+ pathB.quadTo(4942.75146f, 1657, 4914.99902f, 1657);
+ pathB.quadTo(4887.24658f, 1657, 4867.62305f, 1637.3761f);
+ pathB.quadTo(4847.99902f, 1617.75232f, 4847.99902f, 1590);
+ pathB.quadTo(4847.99902f, 1562.24768f, 4867.62305f, 1542.6239f);
+ pathB.quadTo(4887.24658f, 1523, 4914.99902f, 1523);
+ pathB.quadTo(4942.75146f, 1523, 4962.375f, 1542.6239f);
+ pathB.quadTo(4981.99902f, 1562.24768f, 4981.99902f, 1590);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// cubic/quad intersection
+static void skpwww_alamdi_com_3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(10210.8789f, 5315.87891f);
+ path.quadTo(10211.7578f, 5315, 10213, 5315);
+ path.lineTo(10230, 5315);
+ path.quadTo(10231.2422f, 5315, 10232.1211f, 5315.87891f);
+ path.quadTo(10233, 5316.75732f, 10233, 5318);
+ path.lineTo(10233, 5338);
+ path.quadTo(10233, 5339.24268f, 10232.1211f, 5340.12109f);
+ path.quadTo(10231.2422f, 5341, 10230, 5341);
+ path.lineTo(10213, 5341);
+ path.quadTo(10211.7578f, 5341, 10210.8789f, 5340.12109f);
+ path.quadTo(10210, 5339.24268f, 10210, 5338);
+ path.lineTo(10210, 5318);
+ path.quadTo(10210, 5316.75732f, 10210.8789f, 5315.87891f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(10213, 5315);
+ pathB.lineTo(10230, 5315);
+ pathB.cubicTo(10231.6572f, 5315, 10233, 5316.34326f, 10233, 5318);
+ pathB.lineTo(10233, 5338);
+ pathB.cubicTo(10233, 5339.10449f, 10231.6572f, 5340, 10230, 5340);
+ pathB.lineTo(10213, 5340);
+ pathB.cubicTo(10211.3428f, 5340, 10210, 5339.10449f, 10210, 5338);
+ pathB.lineTo(10210, 5318);
+ pathB.cubicTo(10210, 5316.34326f, 10211.3428f, 5315, 10213, 5315);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// bumpSpan failed assertion "span->fOppValue >= 0"
+static void skpwww_familysurvivalprotocol_wordpress_com_61(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(143, 14557);
+ path.lineTo(165, 14557);
+ path.lineTo(165, 14555.9902f);
+ path.lineTo(143, 14556);
+ path.lineTo(143, 14557);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(143, 14557);
+ pathB.lineTo(143, 14555.9902f);
+ pathB.lineTo(165, 14556);
+ pathB.lineTo(165, 14557);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// addTCancel: failed assertion "oIndex > 0"
+static void skpwww_firstunitedbank_com_19(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(808.585815f, 11673.5859f);
+ path.quadTo(809.17157f, 11673, 810, 11673);
+ path.lineTo(1032, 11673);
+ path.quadTo(1038.21326f, 11673, 1042.60657f, 11677.3936f);
+ path.quadTo(1047, 11681.7871f, 1047, 11688);
+ path.quadTo(1047, 11682.2012f, 1042.60657f, 11678.1006f);
+ path.quadTo(1038.21326f, 11674, 1032, 11674);
+ path.lineTo(810, 11674);
+ path.quadTo(809.585815f, 11674, 809.292908f, 11674.293f);
+ path.quadTo(809, 11674.5859f, 809, 11675);
+ path.lineTo(809, 11701);
+ path.quadTo(809, 11701.4141f, 809.292908f, 11701.707f);
+ path.quadTo(809.585815f, 11702, 810, 11702);
+ path.lineTo(1032, 11702);
+ path.quadTo(1038.21326f, 11702, 1042.60657f, 11697.8994f);
+ path.quadTo(1047, 11693.7988f, 1047, 11688);
+ path.quadTo(1047, 11694.2129f, 1042.60657f, 11698.6064f);
+ path.quadTo(1038.21326f, 11703, 1032, 11703);
+ path.lineTo(810, 11703);
+ path.quadTo(809.17157f, 11703, 808.585815f, 11702.4141f);
+ path.quadTo(808, 11701.8281f, 808, 11701);
+ path.lineTo(808, 11675);
+ path.quadTo(808, 11674.1719f, 808.585815f, 11673.5859f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(808, 11703);
+ pathB.lineTo(809.5f, 11701.5f);
+ pathB.lineTo(1062.91907f, 11687.0811f);
+ pathB.lineTo(1047, 11703);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+#endif
+
+// addSimpleAngle: failed assertion "index == count() - 2"
+static void skpwww_shinydemos_com_5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(205.884888f, 648.203857f);
+ path.lineTo(771.570374f, 82.5183716f);
+ path.lineTo(1110.98169f, 421.929626f);
+ path.lineTo(545.296143f, 987.615112f);
+ path.lineTo(205.884888f, 648.203857f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(771.570374f, 82.5183716f);
+ pathB.lineTo(1110.98169f, 421.929626f);
+ pathB.lineTo(545.296204f, 987.615051f);
+ pathB.lineTo(205.884949f, 648.203796f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// addTCoincident oPeek = &other->fTs[++oPeekIndex];
+static void skpwww_lptemp_com_3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(78.6429825f, 1394.30969f);
+ path.quadTo(79.6192932f, 1393.33337f, 81.0000076f, 1393.33337f);
+ path.lineTo(341, 1393.33337f);
+ path.quadTo(342.380707f, 1393.33337f, 343.357025f, 1394.30969f);
+ path.quadTo(344.333344f, 1395.28601f, 344.333344f, 1396.66675f);
+ path.lineTo(344.333344f, 1465.66663f);
+ path.quadTo(344.333344f, 1467.04736f, 343.357025f, 1468.02368f);
+ path.quadTo(342.380707f, 1469, 341, 1469);
+ path.lineTo(81.0000076f, 1469);
+ path.quadTo(79.6192932f, 1469, 78.6429825f, 1468.02368f);
+ path.quadTo(77.6666718f, 1467.04736f, 77.6666718f, 1465.66663f);
+ path.lineTo(77.6666718f, 1396.66675f);
+ path.quadTo(77.6666718f, 1395.28601f, 78.6429825f, 1394.30969f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(81, 1393.33337f);
+ pathB.lineTo(341, 1393.33337f);
+ pathB.cubicTo(342.840942f, 1393.33337f, 344.333344f, 1394.82568f, 344.333344f, 1396.66675f);
+ pathB.lineTo(344.333344f, 1465.66675f);
+ pathB.cubicTo(344.333344f, 1467.32361f, 342.840942f, 1468.66675f, 341, 1468.66675f);
+ pathB.lineTo(81, 1468.66675f);
+ pathB.cubicTo(79.15905f, 1468.66675f, 77.6666718f, 1467.32361f, 77.6666718f, 1465.66675f);
+ pathB.lineTo(77.6666718f, 1396.66675f);
+ pathB.cubicTo(77.6666718f, 1394.82568f, 79.15905f, 1393.33337f, 81, 1393.33337f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
static struct TestDesc tests[] = {
+ TEST(skpwww_lptemp_com_3),
+ TEST(skpwww_shinydemos_com_5),
+#if TEST_NEW_FAILURES
+ TEST(skpwww_familysurvivalprotocol_wordpress_com_61),
+ TEST(skpwww_alamdi_com_3),
+ TEST(skpwww_devbridge_com_22),
+ TEST(skpwww_googleventures_com_32),
+#endif
+ TEST(skpwww_9to5mac_com_64),
TEST(skpwww_wartepop_blogspot_com_br_6),
TEST(skpwww_wartepop_blogspot_com_br_6a),
TEST(skpwww_cooksnaps_com_32a),
diff --git a/tools/pathops_sorter.htm b/tools/pathops_sorter.htm
index aac151af21..79a2c16955 100644
--- a/tools/pathops_sorter.htm
+++ b/tools/pathops_sorter.htm
@@ -953,11 +953,17 @@ op intersect
{{{1020, 672}, {1020, 640.93395999999996}, {998.03301999999996, 618.96698000000004}}}
</div>
+<div id="skpwww_9to5mac_com_64">
+{{{{365.848175,5081.15186}, {368,5103}}},
+{{{367.967712,5102.61084}, {368.278717,5105.71045}}}},
+</div>
+
</div>
<script type="text/javascript">
var testDivs = [
+ skpwww_9to5mac_com_64,
skpcarrot_is24x,
skpwww_wartepop_blogspot_com_br_6,
skpwww_wartepop_blogspot_com_br_6a,
diff --git a/tools/pathops_visualizer.htm b/tools/pathops_visualizer.htm
index 9872b38682..7c109ee3e1 100644
--- a/tools/pathops_visualizer.htm
+++ b/tools/pathops_visualizer.htm
@@ -2,85 +2,139 @@
<head>
<div height="0" hidden="true">
-<div id="skpwww_argus_presse_fr_41">
- RunTestSet [skpwww_argus_presse_fr_41]
-
-{{1000,343}, {165,343}},
-{{165,343}, {165,364.869873}},
-{{165,364.869873}, {1000,364.869873}},
-{{1000,364.869873}, {1000,343}},
-op intersect
-{{165,343.000031}, {1000,343.000031}},
-{{1000,343.000031}, {1000,364.869904}},
-{{1000,364.869904}, {165,364.869904}},
-{{165,364.869904}, {165,343.000031}},
-debugShowLineIntersection wtTs[0]=0 {{165,343}, {165,364.869873}} {{165,343}} wnTs[0]=1 {{1000,343}, {165,343}}
-debugShowLineIntersection wtTs[0]=1 {{1000,364.869873}, {1000,343}} {{1000,343}} wnTs[0]=0 {{1000,343}, {165,343}}
-debugShowLineIntersection wtTs[0]=0 {{165,364.869873}, {1000,364.869873}} {{165,364.869873}} wnTs[0]=1 {{165,343}, {165,364.869873}}
-debugShowLineIntersection wtTs[0]=0 {{1000,364.869873}, {1000,343}} {{1000,364.869873}} wnTs[0]=1 {{165,364.869873}, {1000,364.869873}}
-debugShowLineIntersection wtTs[0]=0 {{165,343.000031}, {1000,343.000031}} {{165,343}} wtTs[1]=1 {{1000,343}} wnTs[0]=1 {{1000,343}, {165,343}} wnTs[1]=0
-debugShowLineIntersection wtTs[0]=0 {{1000,343.000031}, {1000,364.869904}} {{1000,343.000031}} wnTs[0]=0 {{1000,343}, {165,343}}
-debugShowLineIntersection wtTs[0]=1 {{165,364.869904}, {165,343.000031}} {{165,343.000031}} wnTs[0]=1 {{1000,343}, {165,343}}
-debugShowLineIntersection wtTs[0]=0 {{165,343.000031}, {1000,343.000031}} {{165,343}} wnTs[0]=0 {{165,343}, {165,364.869873}}
-debugShowLineIntersection wtTs[0]=1 {{1000,364.869904}, {165,364.869904}} {{165,364.869873}} wnTs[0]=1 {{165,343}, {165,364.869873}}
-debugShowLineIntersection wtTs[0]=0 {{165,364.869904}, {165,343.000031}} {{165,364.869904}} wtTs[1]=1 {{165,343.000031}} wnTs[0]=1 {{165,343}, {165,364.869873}} wnTs[1]=1.39541634e-006
-debugShowLineIntersection wtTs[0]=1 {{1000,343.000031}, {1000,364.869904}} {{1000,364.869904}} wnTs[0]=1 {{165,364.869873}, {1000,364.869873}}
-debugShowLineIntersection wtTs[0]=0 {{1000,364.869904}, {165,364.869904}} {{1000,364.869873}} wtTs[1]=1 {{165,364.869873}} wnTs[0]=1 {{165,364.869873}, {1000,364.869873}} wnTs[1]=0
-debugShowLineIntersection wtTs[0]=0 {{165,364.869904}, {165,343.000031}} {{165,364.869904}} wnTs[0]=0 {{165,364.869873}, {1000,364.869873}}
-debugShowLineIntersection wtTs[0]=1 {{165,343.000031}, {1000,343.000031}} {{1000,343}} wnTs[0]=1 {{1000,364.869873}, {1000,343}}
-debugShowLineIntersection wtTs[0]=0 {{1000,343.000031}, {1000,364.869904}} {{1000,343.000031}} wtTs[1]=1 {{1000,364.869904}} wnTs[0]=0.999999 {{1000,364.869873}, {1000,343}} wnTs[1]=0
-debugShowLineIntersection wtTs[0]=0 {{1000,364.869904}, {165,364.869904}} {{1000,364.869873}} wnTs[0]=0 {{1000,364.869873}, {1000,343}}
-debugShowLineIntersection wtTs[0]=0 {{1000,343.000031}, {1000,364.869904}} {{1000,343.000031}} wnTs[0]=1 {{165,343.000031}, {1000,343.000031}}
-debugShowLineIntersection wtTs[0]=1 {{165,364.869904}, {165,343.000031}} {{165,343.000031}} wnTs[0]=0 {{165,343.000031}, {1000,343.000031}}
-debugShowLineIntersection wtTs[0]=0 {{1000,364.869904}, {165,364.869904}} {{1000,364.869904}} wnTs[0]=1 {{1000,343.000031}, {1000,364.869904}}
-debugShowLineIntersection wtTs[0]=0 {{165,364.869904}, {165,343.000031}} {{165,364.869904}} wnTs[0]=1 {{1000,364.869904}, {165,364.869904}}
-SkOpSegment::debugShowTs - id=0 [o=3,5 t=0 1000,343.000031 w=1 o=0] [o=7,1 t=1 165,343 w=1 o=0]
-SkOpSegment::debugShowTs o id=4 [o=7,1 t=0 165,343 w=1 o=0] [o=3,5 t=1 1000,343.000031 w=1 o=0] operand
-SkOpSegment::debugShowTs + id=0 [o=3,5 t=0 1000,343.000031 w=1 o=0] [o=7,1 t=1 165,343 w=1 o=0]
-SkOpSegment::debugShowTs o id=4 [o=7,1 t=0 165,343 w=1 o=0] [o=3,5 t=1 1000,343.000031 w=1 o=0] operand
-SkOpSegment::debugShowTs - id=1 [o=4,0 t=0 165,343 w=1 o=0] [o=6,2 t=1 165,364.869873 w=1 o=0]
-SkOpSegment::debugShowTs o id=7 [o=6,2 t=0 165,364.869904 w=1 o=0] [o=4,0 t=1 165,343.000031 w=1 o=0] operand
-SkOpSegment::addTPair addTPair this=1 1.39541634e-006 other=7 1
-SkOpSegment::addTPair addTPair this=7 0 other=1 1
-SkOpSegment::debugShowTs + id=1 [o=4,0 t=0 165,343 w=1 o=0] [o=7 t=1.4e-006 165,343.000031 w=1 o=0] [o=7,6,2 t=1 165,364.869873 w=1 o=0]
-SkOpSegment::debugShowTs o id=7 [o=1,6,2 t=0 165,364.869904 w=1 o=0] [o=1,4,0 t=1 165,343.000031 w=1 o=0] operand
-SkOpSegment::debugShowTs - id=2 [o=1,7 t=0 165,364.869904 w=1 o=0] [o=5,3 t=1 1000,364.869873 w=1 o=0]
-SkOpSegment::debugShowTs o id=6 [o=5,3 t=0 1000,364.869873 w=1 o=0] [o=1,7 t=1 165,364.869904 w=1 o=0] operand
-SkOpSegment::debugShowTs + id=2 [o=1,7 t=0 165,364.869904 w=1 o=0] [o=5,3 t=1 1000,364.869873 w=1 o=0]
-SkOpSegment::debugShowTs o id=6 [o=5,3 t=0 1000,364.869873 w=1 o=0] [o=1,7 t=1 165,364.869904 w=1 o=0] operand
-SkOpSegment::debugShowTs - id=3 [o=6,2 t=0 1000,364.869873 w=1 o=0] [o=4,0 t=1 1000,343 w=1 o=0]
-SkOpSegment::debugShowTs o id=5 [o=4,0 t=0 1000,343.000031 w=1 o=0] [o=6,2 t=1 1000,364.869904 w=1 o=0] operand
-SkOpSegment::addTPair addTPair this=3 0 other=5 1
-SkOpSegment::addTPair addTPair this=5 0 other=3 0.999998605
-SkOpSegment::debugShowTs + id=3 [o=6,2,5 t=0 1000,364.869904 w=1 o=0] [o=5 t=1 1000,343.000031 w=1 o=0] [o=4,0 t=1 1000,343 w=1 o=0]
-SkOpSegment::debugShowTs o id=5 [o=3,4,0 t=0 1000,343.000031 w=1 o=0] [o=3,6,2 t=1 1000,364.869904 w=1 o=0] operand
-SkOpContour::calcCoincidentWinding count=4
-SkOpSegment::debugShowTs p id=0 [o=3,5 t=0 1000,343.000031 w=1 o=-1] [o=7,1 t=1 165,343 w=1 o=0]
-SkOpSegment::debugShowTs o id=4 [o=7,1 t=0 165,343 w=0 o=0] [o=3,5 t=1 1000,343.000031 w=1 o=0] operand done
-SkOpSegment::debugShowTs p id=1 [o=4,0 t=0 165,343 w=1 o=0] [o=7 t=1.4e-006 165,343.000031 w=1 o=-1] [o=7,6,2 t=1 165,364.869873 w=1 o=0]
-SkOpSegment::debugShowTs o id=7 [o=1,6,2 t=0 165,364.869904 w=0 o=0] [o=1,4,0 t=1 165,343.000031 w=1 o=0] operand done
-SkOpSegment::debugShowTs p id=2 [o=1,7 t=0 165,364.869904 w=1 o=-1] [o=5,3 t=1 1000,364.869873 w=1 o=0]
-SkOpSegment::debugShowTs o id=6 [o=5,3 t=0 1000,364.869873 w=0 o=0] [o=1,7 t=1 165,364.869904 w=1 o=0] operand done
-SkOpSegment::debugShowTs p id=3 [o=6,2,5 t=0 1000,364.869904 w=1 o=-1] [o=5 t=1 1000,343.000031 w=1 o=0] [o=4,0 t=1 1000,343 w=1 o=0]
-SkOpSegment::debugShowTs o id=5 [o=3,4,0 t=0 1000,343.000031 w=0 o=0] [o=3,6,2 t=1 1000,364.869904 w=1 o=0] operand done
-SkOpSegment::addTPair addTPair this=0 0 other=4 1
-SkOpSegment::addTPair addTPair this=0 1 other=4 0
-SkOpSegment::addTPair addTPair this=6 1 other=2 0
-SkOpSegment::addTPair addTPair duplicate this=2 0 other=6 1
-SkOpSegment::addTPair addTPair this=2 1 other=6 0
-SkOpContour::joinCoincidence count=4
-SkOpSegment::sortAngles [0] tStart=0 [0]
-SkOpSegment::sortAngles [0] tStart=1 [5]
-SkOpSegment::sortAngles [1] tStart=1.39541634e-006 [2]
-SkOpSegment::sortAngles [1] tStart=1 [5]
-SkOpSegment::sortAngles [2] tStart=1 [5]
-SkOpSegment::sortAngles [3] tStart=0.999998605 [3]
-SkOpSegment::debugShowActiveSpans id=0 (1000,343 165,343) t=0 (1000,343) tEnd=1 other=3 otherT=1 otherIndex=5 windSum=? windValue=1 oppValue=-1
-SkOpSegment::debugShowActiveSpans id=1 (165,343 165,364.869873) t=1.39541634e-006 (165,343.000031) tEnd=1 other=7 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=-1
-SkOpSegment::debugShowActiveSpans id=2 (165,364.869873 1000,364.869873) t=0 (165,364.869873) tEnd=1 other=6 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=-1
-SkOpSegment::debugShowActiveSpans id=3 (1000,364.869873 1000,343) t=0 (1000,364.869873) tEnd=0.999998605 other=6 otherT=0 otherIndex=2 windSum=? windValue=1 oppValue=-1
-Assemble
-
+<div id="issue2753">
+ RunTestSet [issue2753]
+
+{{142.701004,110.568001}, {142.957001,100}},
+{{142.957001,100}, {153.835007,100}},
+{{153.835007,100}, {154.591995,108.188004}},
+{{154.591995,108.188004}, {154.591995,108.188004}, {153.173004,108.483002}, {152.830002,109.412003}},
+{{152.830002,109.412003}, {152.830002,109.412003}, {142.701004,110.568001}, {142.701004,110.568001}},
+op union
+{{39,124.000999}, {39,124.000999}, {50.5999985,117.000999}, {50.5999985,117.000999}},
+{{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}},
+{{188.201004,117.600998}, {188.201004,117.600998}, {174.800995,93}, {39,124.000999}},
+debugShowCubicIntersection no self intersect {{154.591995,108.188004}, {154.591995,108.188004}, {153.173004,108.483002}, {152.830002,109.412003}}
+debugShowLineIntersection wtTs[0]=1 {{142.701004,110.568001}, {142.957001,100}} {{142.957001,100}} wnTs[0]=0 {{142.957001,100}, {153.835007,100}}
+debugShowLineIntersection wtTs[0]=0 {{142.701004,110.568001}, {142.957001,100}} {{142.701004,110.568001}} wnTs[0]=1 {{152.830002,109.412003}, {142.701004,110.568001}}
+debugShowLineIntersection wtTs[0]=0 {{153.835007,100}, {154.591995,108.188004}} {{153.835007,100}} wnTs[0]=1 {{142.957001,100}, {153.835007,100}}
+debugShowCubicLineIntersection wtTs[0]=0 {{154.591995,108.188004}, {154.591995,108.188004}, {153.173004,108.483002}, {152.830002,109.412003}} {{154.591995,108.188004}} wnTs[0]=1 {{153.835007,100}, {154.591995,108.188004}}
+debugShowCubicLineIntersection wtTs[0]=1 {{154.591995,108.188004}, {154.591995,108.188004}, {153.173004,108.483002}, {152.830002,109.412003}} {{152.830002,109.412003}} wnTs[0]=0 {{152.830002,109.412003}, {142.701004,110.568001}}
+debugShowCubicLineIntersection wtTs[0]=0.671281996 {{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}} {{142.883102,103.050758}} wnTs[0]=0.711321 {{142.701004,110.568001}, {142.957001,100}}
+debugShowCubicLineIntersection wtTs[0]=0.642192755 {{188.201004,117.600998}, {188.201004,117.600998}, {174.800995,93}, {39,124.000999}} {{142.753387,108.405373}} wnTs[0]=0.204639 {{142.701004,110.568001}, {142.957001,100}}
+debugShowCubicLineIntersection wtTs[0]=0.734814757 {{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}} {{154.165848,103.578537}} wnTs[0]=0.437047 {{153.835007,100}, {154.591995,108.188004}}
+debugShowCubicIntersection no intersect {{154.591995,108.188004}, {154.591995,108.188004}, {153.173004,108.483002}, {152.830002,109.412003}} {{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}}
+debugShowCubicIntersection no intersect {{154.591995,108.188004}, {154.591995,108.188004}, {153.173004,108.483002}, {152.830002,109.412003}} {{188.201004,117.600998}, {188.201004,117.600998}, {174.800995,93}, {39,124.000999}}
+debugShowCubicLineIntersection no intersect {{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}} {{152.830002,109.412003}, {142.701004,110.568001}}
+debugShowCubicLineIntersection no intersect {{188.201004,117.600998}, {188.201004,117.600998}, {174.800995,93}, {39,124.000999}} {{152.830002,109.412003}, {142.701004,110.568001}}
+debugShowCubicIntersection no self intersect {{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}}
+debugShowCubicIntersection no self intersect {{188.201004,117.600998}, {188.201004,117.600998}, {174.800995,93}, {39,124.000999}}
+debugShowCubicLineIntersection wtTs[0]=0 {{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}} {{50.5999985,117.000999}} wnTs[0]=1 {{39,124.000999}, {50.5999985,117.000999}}
+debugShowCubicLineIntersection wtTs[0]=1 {{188.201004,117.600998}, {188.201004,117.600998}, {174.800995,93}, {39,124.000999}} {{39,124.000999}} wnTs[0]=0 {{39,124.000999}, {50.5999985,117.000999}}
+debugShowCubicIntersection wtTs[0]=1 {{50.5999985,117.000999}, {50.5999985,117.000999}, {164.600998,85.1999969}, {188.201004,117.600998}} {{188.201004,117.600998}} wnTs[0]=0 {{188.201004,117.600998}, {188.201004,117.600998}, {174.800995,93}, {39,124.000999}}
+SkOpSegment::sortAngles [0] tStart=0.204639461 [1]
+SkOpAngle::after [0/1] 21/21 tStart=0.204639461 tEnd=0 < [7/1] 1/29 tStart=0.642192755 tEnd=0 < [0/2] 5/5 tStart=0.204639461 tEnd=0.711321242 T 4
+SkOpAngle::after [0/1] 21/21 tStart=0.204639461 tEnd=0 < [7/2] 17/17 tStart=0.642192755 tEnd=1 < [7/1] 1/29 tStart=0.642192755 tEnd=0 F 4
+SkOpAngle::after [7/1] 1/29 tStart=0.642192755 tEnd=0 < [7/2] 17/17 tStart=0.642192755 tEnd=1 < [0/2] 5/5 tStart=0.204639461 tEnd=0.711321242 F 4
+SkOpAngle::after [0/2] 5/5 tStart=0.204639461 tEnd=0.711321242 < [7/2] 17/17 tStart=0.642192755 tEnd=1 < [0/1] 21/21 tStart=0.204639461 tEnd=0 T 4
+SkOpSegment::sortAngles [0] tStart=0.711321242 [2]
+SkOpAngle::after [0/3] 21/21 tStart=0.711321242 tEnd=0.204639461 < [6/1] 13/17 tStart=0.671281996 tEnd=0 < [0/4] 5/5 tStart=0.711321242 tEnd=1 F 4
+SkOpAngle::after [0/3] 21/21 tStart=0.711321242 tEnd=0.204639461 < [6/2] 29/29 tStart=0.671281996 tEnd=0.734814757 < [0/4] 5/5 tStart=0.711321242 tEnd=1 T 4
+SkOpSegment::sortAngles [2] tStart=0.437046747 [1]
+SkOpAngle::after [2/1] 9/9 tStart=0.437046747 tEnd=0 < [6/3] 13/13 tStart=0.734814757 tEnd=0.671281996 < [2/2] 25/25 tStart=0.437046747 tEnd=1 T 4
+SkOpAngle::after [2/1] 9/9 tStart=0.437046747 tEnd=0 < [6/4] 29/29 tStart=0.734814757 tEnd=1 < [6/3] 13/13 tStart=0.734814757 tEnd=0.671281996 F 4
+SkOpAngle::after [6/3] 13/13 tStart=0.734814757 tEnd=0.671281996 < [6/4] 29/29 tStart=0.734814757 tEnd=1 < [2/2] 25/25 tStart=0.437046747 tEnd=1 F 4
+SkOpAngle::after [2/2] 25/25 tStart=0.437046747 tEnd=1 < [6/4] 29/29 tStart=0.734814757 tEnd=1 < [2/1] 9/9 tStart=0.437046747 tEnd=0 T 4
+SkOpSegment::debugShowActiveSpans id=0 (142.701004,110.568001 142.957001,100) t=0 (142.701004,110.568001) tEnd=0.204639461 other=4 otherT=1 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=0 (142.701004,110.568001 142.957001,100) t=0.204639461 (142.753387,108.405373) tEnd=0.711321242 other=7 otherT=0.642192755 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=0 (142.701004,110.568001 142.957001,100) t=0.711321242 (142.883102,103.050758) tEnd=1 other=6 otherT=0.671281996 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=1 (142.957001,100 153.835007,100) t=0 (142.957001,100) tEnd=1 other=0 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (153.835007,100 154.591995,108.188004) t=0 (153.835007,100) tEnd=0.437046747 other=1 otherT=1 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (153.835007,100 154.591995,108.188004) t=0.437046747 (154.165848,103.578537) tEnd=1 other=6 otherT=0.734814757 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (154.591995,108.188004 154.591995,108.188004 153.173004,108.483002 152.830002,109.412003) t=0 (154.591995,108.188004) tEnd=1 other=2 otherT=1 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (152.830002,109.412003 142.701004,110.568001) t=0 (152.830002,109.412003) tEnd=1 other=3 otherT=1 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (39,124.000999 50.5999985,117.000999) t=0 (39,124.000999) tEnd=1 other=7 otherT=1 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0 (50.5999985,117.000999) tEnd=0.671281996 other=5 otherT=1 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0.671281996 (142.883102,103.050758) tEnd=0.734814757 other=0 otherT=0.711321242 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0.734814757 (154.165848,103.578537) tEnd=1 other=2 otherT=0.437046747 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=7 (188.201004,117.600998 188.201004,117.600998 174.800995,93 39,124.000999) t=0 (188.201004,117.600998) tEnd=0.642192755 other=6 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=7 (188.201004,117.600998 188.201004,117.600998 174.800995,93 39,124.000999) t=0.642192755 (142.753387,108.405373) tEnd=1 other=0 otherT=0.204639461 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::findTop
+SkOpAngle::dumpOne [0/5] next=1/1 sect=21/21 s=1 [3] e=0.711321242 [2] sgn=1 windVal=1 windSum=?
+SkOpAngle::dumpOne [1/1] next=0/5 sect=31/31 s=0 [0] e=1 [1] sgn=-1 windVal=1 windSum=? stop
+SkOpSegment::markWinding id=0 (142.701004,110.568001 142.957001,100) t=0.711321242 [2] (142.883102,103.050758) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::nextChase mismatched signs
+SkOpSegment::markWinding id=1 (142.957001,100 153.835007,100) t=0 [0] (142.957001,100) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=2 (153.835007,100 154.591995,108.188004) t=0 [0] (153.835007,100) tEnd=0.437046747 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=0 (142.701004,110.568001 142.957001,100) t=0.711321242 [2] (142.883102,103.050758) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=0 t=0.711321242 tEnd=1 op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::nextChase mismatched signs
+SkOpSegment::findNextOp simple
+SkOpSegment::markDoneBinary id=0 (142.701004,110.568001 142.957001,100) t=0.711321242 [2] (142.883102,103.050758) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+bridgeOp current id=0 from=(142.883102,103.050758) to=(142.957001,100)
+SkOpSegment::findNextOp simple
+SkOpSegment::markDoneBinary id=1 (142.957001,100 153.835007,100) t=0 [0] (142.957001,100) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+bridgeOp current id=1 from=(142.957001,100) to=(153.835007,100)
+path.moveTo(142.883102,103.050758);
+path.lineTo(142.957001,100);
+SkOpSegment::markWinding id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0.671281996 [1] (142.883102,103.050758) tEnd=0.734814757 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last id=6 windSum=-1 small=0
+SkOpSegment::markWinding id=2 (153.835007,100 154.591995,108.188004) t=0.437046747 [1] (154.165848,103.578537) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=3 (154.591995,108.188004 154.591995,108.188004 153.173004,108.483002 152.830002,109.412003) t=0 [0] (154.591995,108.188004) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=4 (152.830002,109.412003 142.701004,110.568001) t=0 [0] (152.830002,109.412003) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=0 (142.701004,110.568001 142.957001,100) t=0 [0] (142.701004,110.568001) tEnd=0.204639461 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last id=0 windSum=? small=0
+SkOpSegment::markWinding id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0.734814757 [2] (154.165848,103.578537) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=7 (188.201004,117.600998 188.201004,117.600998 174.800995,93 39,124.000999) t=0 [0] (188.201004,117.600998) tEnd=0.642192755 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last id=7 windSum=? small=0
+SkOpSegment::findNextOp
+SkOpAngle::dumpOne [2/1] next=6/3 sect=9/9 s=0.437046747 [1] e=0 [0] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [6/3] next=2/2 sect=13/13 s=0.734814757 [2] e=0.671281996 [1] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand
+SkOpAngle::dumpOne [2/2] next=6/4 sect=25/25 s=0.437046747 [1] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1
+SkOpAngle::dumpOne [6/4] next=2/1 sect=29/29 s=0.734814757 [2] e=1 [3] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
+SkOpSegment::activeOp id=6 t=0.734814757 tEnd=0.671281996 op=union miFrom=1 miTo=1 suFrom=0 suTo=1 result=0
+SkOpSegment::markDoneBinary id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0.671281996 [1] (142.883102,103.050758) tEnd=0.734814757 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp chase.append id=6 windSum=-1 small=0
+SkOpSegment::activeOp id=2 t=0.437046747 tEnd=1 op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::markDoneBinary id=2 (153.835007,100 154.591995,108.188004) t=0.437046747 [1] (154.165848,103.578537) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDoneBinary id=3 (154.591995,108.188004 154.591995,108.188004 153.173004,108.483002 152.830002,109.412003) t=0 [0] (154.591995,108.188004) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDoneBinary id=4 (152.830002,109.412003 142.701004,110.568001) t=0 [0] (152.830002,109.412003) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDoneBinary id=0 (142.701004,110.568001 142.957001,100) t=0 [0] (142.701004,110.568001) tEnd=0.204639461 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp chase.append id=0 windSum=-2147483647 small=0
+SkOpSegment::activeOp id=6 t=0.734814757 tEnd=1 op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
+SkOpSegment::findNextOp chase.append id=7 windSum=-2147483647 small=0
+SkOpSegment::markDoneBinary id=2 (153.835007,100 154.591995,108.188004) t=0 [0] (153.835007,100) tEnd=0.437046747 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[2] to:[6] start=2 end=3
+bridgeOp current id=2 from=(153.835007,100) to=(154.165848,103.578537)
+path.lineTo(153.835007,100);
+SkOpSegment::findNextOp simple
+SkOpSegment::markDoneBinary id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0.734814757 [2] (154.165848,103.578537) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+bridgeOp current id=6 from=(154.165848,103.578537) to=(188.201004,117.600998)
+path.lineTo(154.165848,103.578537);
+path.cubicTo(169.326965,104.931351, 181.942627,109.008728, 188.201004,117.600998);
+SkOpSegment::markWinding id=0 (142.701004,110.568001 142.957001,100) t=0.204639461 [1] (142.753387,108.405373) tEnd=0.711321242 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last id=0 windSum=-1 small=0
+SkOpSegment::markWinding id=7 (188.201004,117.600998 188.201004,117.600998 174.800995,93 39,124.000999) t=0.642192755 [1] (142.753387,108.405373) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=5 (39,124.000999 50.5999985,117.000999) t=0 [0] (39,124.000999) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0 [0] (50.5999985,117.000999) tEnd=0.671281996 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last id=6 windSum=-1 small=0
+SkOpSegment::findNextOp
+SkOpAngle::dumpOne [7/1] next=0/2 sect=1/29 s=0.642192755 [1] e=0 [0] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
+SkOpAngle::dumpOne [0/2] next=7/2 sect=5/5 s=0.204639461 [1] e=0.711321242 [2] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=-1
+SkOpAngle::dumpOne [7/2] next=0/1 sect=17/17 s=0.642192755 [1] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [0/1] next=7/1 sect=21/21 s=0.204639461 [1] e=0 [0] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 done
+SkOpSegment::activeOp id=0 t=0.204639461 tEnd=0.711321242 op=union miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDoneBinary id=0 (142.701004,110.568001 142.957001,100) t=0.204639461 [1] (142.753387,108.405373) tEnd=0.711321242 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp chase.append id=0 windSum=-1 small=0
+SkOpSegment::activeOp id=7 t=0.642192755 tEnd=1 op=union miFrom=1 miTo=1 suFrom=1 suTo=0 result=0
+SkOpSegment::markDoneBinary id=7 (188.201004,117.600998 188.201004,117.600998 174.800995,93 39,124.000999) t=0.642192755 [1] (142.753387,108.405373) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDoneBinary id=5 (39,124.000999 50.5999985,117.000999) t=0 [0] (39,124.000999) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDoneBinary id=6 (50.5999985,117.000999 50.5999985,117.000999 164.600998,85.1999969 188.201004,117.600998) t=0 [0] (50.5999985,117.000999) tEnd=0.671281996 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=0 t=0.204639461 tEnd=0 op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::markDoneBinary id=7 (188.201004,117.600998 188.201004,117.600998 174.800995,93 39,124.000999) t=0 [0] (188.201004,117.600998) tEnd=0.642192755 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[7] to:[0] start=1 end=0
+bridgeOp current id=7 from=(188.201004,117.600998) to=(142.753387,108.405373)
+path.cubicTo(188.201004,117.600998, 182.674683,107.455261, 142.753387,108.405373);
</div>
</div>
@@ -88,7 +142,7 @@ Assemble
<script type="text/javascript">
var testDivs = [
- skpwww_argus_presse_fr_41,
+ issue2753,
];
var decimal_places = 3; // make this 3 to show more precision