aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2015-04-29 08:28:30 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-04-29 08:28:30 -0700
commitaec251012542e971100e218bf463adbfb5d21d20 (patch)
tree16c2e84c2d59d94b75d7d2bc50fec53c0e38a898
parent97fdea6c4393cf0102d7eee5790782509fb4f57b (diff)
minor fixes to cubics code and overall alignment of how bounds and tops are computed for all curve types
All but 17 extended tests work. A helper function is privately added to SkPath.h to permit a test to modify a given point in a path. BUG=skia:3588 Review URL: https://codereview.chromium.org/1107353004
-rw-r--r--gyp/core.gypi2
-rw-r--r--include/core/SkPath.h2
-rw-r--r--src/core/SkPath.cpp12
-rw-r--r--src/pathops/SkDCubicLineIntersection.cpp6
-rw-r--r--src/pathops/SkOpContour.cpp4
-rw-r--r--src/pathops/SkOpContour.h2
-rw-r--r--src/pathops/SkOpSegment.cpp33
-rw-r--r--src/pathops/SkOpSegment.h16
-rw-r--r--src/pathops/SkPathOpsBounds.cpp51
-rw-r--r--src/pathops/SkPathOpsBounds.h23
-rw-r--r--src/pathops/SkPathOpsCommon.cpp6
-rw-r--r--src/pathops/SkPathOpsCommon.h2
-rw-r--r--src/pathops/SkPathOpsConic.cpp22
-rw-r--r--src/pathops/SkPathOpsConic.h6
-rw-r--r--src/pathops/SkPathOpsCubic.cpp89
-rw-r--r--src/pathops/SkPathOpsCubic.h6
-rw-r--r--src/pathops/SkPathOpsCurve.cpp146
-rw-r--r--src/pathops/SkPathOpsCurve.h53
-rw-r--r--src/pathops/SkPathOpsDebug.h10
-rw-r--r--src/pathops/SkPathOpsOp.cpp4
-rw-r--r--src/pathops/SkPathOpsQuad.cpp31
-rw-r--r--src/pathops/SkPathOpsQuad.h4
-rw-r--r--src/pathops/SkPathOpsRect.cpp61
-rw-r--r--src/pathops/SkPathOpsRect.h20
-rw-r--r--src/pathops/SkPathOpsSimplify.cpp4
-rw-r--r--tests/PathOpsBoundsTest.cpp21
-rw-r--r--tests/PathOpsCubicLineIntersectionTest.cpp3
-rw-r--r--tests/PathOpsDCubicTest.cpp2
-rw-r--r--tests/PathOpsExtendedTest.cpp10
-rw-r--r--tests/PathOpsOpTest.cpp861
-rw-r--r--tests/PathOpsTestCommon.cpp12
-rw-r--r--tools/pathops_sorter.htm4
-rw-r--r--tools/pathops_visualizer.htm500
33 files changed, 1375 insertions, 653 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 190236f11b..1f062524ae 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -350,10 +350,10 @@
'<(skia_src_path)/pathops/SkOpEdgeBuilder.cpp',
'<(skia_src_path)/pathops/SkOpSegment.cpp',
'<(skia_src_path)/pathops/SkOpSpan.cpp',
- '<(skia_src_path)/pathops/SkPathOpsBounds.cpp',
'<(skia_src_path)/pathops/SkPathOpsCommon.cpp',
'<(skia_src_path)/pathops/SkPathOpsConic.cpp',
'<(skia_src_path)/pathops/SkPathOpsCubic.cpp',
+ '<(skia_src_path)/pathops/SkPathOpsCurve.cpp',
'<(skia_src_path)/pathops/SkPathOpsDebug.cpp',
'<(skia_src_path)/pathops/SkPathOpsLine.cpp',
'<(skia_src_path)/pathops/SkPathOpsOp.cpp',
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index b5b95e15e7..c413560102 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -1034,6 +1034,8 @@ private:
ed.setBounds(rect);
}
+ void setPt(int index, SkScalar x, SkScalar y);
+
friend class SkAutoPathBoundsUpdate;
friend class SkAutoDisableOvalCheck;
friend class SkAutoDisableDirectionCheck;
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 45429a6e12..aa99ce4f0e 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -631,6 +631,18 @@ bool SkPath::getLastPt(SkPoint* lastPt) const {
return false;
}
+void SkPath::setPt(int index, SkScalar x, SkScalar y) {
+ SkDEBUGCODE(this->validate();)
+
+ int count = fPathRef->countPoints();
+ if (count <= index) {
+ return;
+ } else {
+ SkPathRef::Editor ed(&fPathRef);
+ ed.atPoint(index)->set(x, y);
+ }
+}
+
void SkPath::setLastPt(SkScalar x, SkScalar y) {
SkDEBUGCODE(this->validate();)
diff --git a/src/pathops/SkDCubicLineIntersection.cpp b/src/pathops/SkDCubicLineIntersection.cpp
index f5fe01503b..f658b09f0b 100644
--- a/src/pathops/SkDCubicLineIntersection.cpp
+++ b/src/pathops/SkDCubicLineIntersection.cpp
@@ -135,7 +135,7 @@ public:
+ (fCubic[n].fX - fLine[0].fX) * adj;
}
double extremeTs[6];
- int extrema = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c[3].fX, extremeTs);
+ int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs);
count = c.searchRoots(extremeTs, extrema, 0, SkDCubic::kXAxis, roots);
break;
}
@@ -171,7 +171,7 @@ public:
SkDPoint calcPt = c.ptAtT(roots[index]);
if (!approximately_equal(calcPt.fY, axisIntercept)) {
double extremeTs[6];
- int extrema = SkDCubic::FindExtrema(c[0].fY, c[1].fY, c[2].fY, c[3].fY, extremeTs);
+ int extrema = SkDCubic::FindExtrema(&c[0].fY, extremeTs);
count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kYAxis, roots);
break;
}
@@ -234,7 +234,7 @@ public:
SkDPoint calcPt = c.ptAtT(roots[index]);
if (!approximately_equal(calcPt.fX, axisIntercept)) {
double extremeTs[6];
- int extrema = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c[3].fX, extremeTs);
+ int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs);
count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kXAxis, roots);
break;
}
diff --git a/src/pathops/SkOpContour.cpp b/src/pathops/SkOpContour.cpp
index ce9439ac26..107c83169b 100644
--- a/src/pathops/SkOpContour.cpp
+++ b/src/pathops/SkOpContour.cpp
@@ -69,7 +69,7 @@ void SkOpContour::toPath(SkPathWriter* path) const {
path->close();
}
-void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY,
+void SkOpContour::topSortableSegment(const SkDPoint& topLeft, SkDPoint* bestXY,
SkOpSegment** topStart) {
int segmentCount = fSortedSegments.count();
SkASSERT(segmentCount > 0);
@@ -84,7 +84,7 @@ void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY,
continue;
}
fDone = false;
- SkPoint testXY = testSegment->activeLeftTop(NULL);
+ SkDPoint testXY = testSegment->activeLeftTop(NULL);
if (*topStart) {
if (testXY.fY < topLeft.fY) {
continue;
diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h
index 3d26ae84c8..9abf38238b 100644
--- a/src/pathops/SkOpContour.h
+++ b/src/pathops/SkOpContour.h
@@ -344,7 +344,7 @@ public:
}
void toPath(SkPathWriter* path) const;
- void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
+ void topSortableSegment(const SkDPoint& topLeft, SkDPoint* bestXY, SkOpSegment** topStart);
SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
private:
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index a571609f53..ce35f846b3 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -102,9 +102,9 @@ SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta
return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable);
}
-SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
+SkDPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
SkASSERT(!done());
- SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
+ SkDPoint topPt = {SK_ScalarMax, SK_ScalarMax};
// see if either end is not done since we want smaller Y of the pair
bool lastDone = true;
SkOpSpanBase* span = &fHead;
@@ -118,10 +118,11 @@ SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
*firstSpan = span;
}
}
- if (fVerb != SkPath::kLine_Verb && !lastDone
- && fCubicType != SkDCubic::kSplitAtMaxCurvature_SkDCubicType) {
+ if (fVerb != SkPath::kLine_Verb && !lastDone) {
double curveTopT;
- SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastSpan->t(), span->t(),
+ SkDCurve curve;
+ this->subDivide(lastSpan, span, &curve);
+ SkDPoint curveTop = (curve.*Top[fVerb])(fPts, fWeight, lastSpan->t(), span->t(),
&curveTopT);
if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY && topPt.fX > curveTop.fX)) {
topPt = curveTop;
@@ -1092,10 +1093,7 @@ SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS
const SkOpSegment* next = angle->segment();
SkPathOpsBounds bounds;
next->subDivideBounds(angle->end(), angle->start(), &bounds);
- bool nearSame = AlmostEqualUlps(top, bounds.top());
- bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->sectorStart();
- bool lesserSector = top > bounds.fTop;
- if (lesserSector && (!nearSame || lowerSector)) {
+ if (top > bounds.fTop) {
top = bounds.fTop;
firstAngle = angle;
}
@@ -1452,7 +1450,12 @@ bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en
}
SkASSERT(fVerb == SkPath::kCubic_Verb);
SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t());
- return dst.monotonicInY();
+ if (dst.monotonicInY()) {
+ return true;
+ }
+ SkDCubic whole;
+ whole.set(fPts);
+ return whole.monotonicInY();
}
bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start,
@@ -2023,9 +2026,15 @@ bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end,
SkPathOpsBounds* bounds) const {
- SkOpCurve edge;
+ SkDCurve edge;
+ subDivide(start, end, &edge);
+ (edge.*SetBounds[fVerb])(fPts, fWeight, start->t(), end->t(), bounds);
+}
+
+SkDPoint SkOpSegment::top(const SkOpSpanBase* start, const SkOpSpanBase* end, double* topT) const {
+ SkDCurve edge;
subDivide(start, end, &edge);
- (bounds->*SetCurveBounds[fVerb])(edge.fPts, edge.fWeight);
+ return (edge.*Top[fVerb])(fPts, fWeight, start->t(), end->t(), topT);
}
void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h
index 1e9e1c44be..a762a66a5a 100644
--- a/src/pathops/SkOpSegment.h
+++ b/src/pathops/SkOpSegment.h
@@ -41,20 +41,24 @@ public:
bool activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end, SkPathOp op,
int* sumMiWinding, int* sumSuWinding);
- SkPoint activeLeftTop(SkOpSpanBase** firstT);
+ SkDPoint activeLeftTop(SkOpSpanBase** firstT);
bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end);
bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding);
SkOpSegment* addConic(SkPoint pts[3], SkScalar weight, SkOpContour* parent) {
init(pts, weight, parent, SkPath::kConic_Verb);
- fBounds.setConicBounds(pts, weight);
+ SkDCurve curve;
+ curve.fConic.set(pts, weight);
+ curve.setConicBounds(pts, weight, 0, 1, &fBounds);
return this;
}
SkOpSegment* addCubic(SkPoint pts[4], SkOpContour* parent) {
init(pts, 1, parent, SkPath::kCubic_Verb);
- fBounds.setCubicBounds(pts, 1);
+ SkDCurve curve;
+ curve.fCubic.set(pts);
+ curve.setCubicBounds(pts, 1, 0, 1, &fBounds);
return this;
}
@@ -88,7 +92,9 @@ public:
SkOpSegment* addQuad(SkPoint pts[3], SkOpContour* parent) {
init(pts, 1, parent, SkPath::kQuad_Verb);
- fBounds.setQuadBounds(pts, 1);
+ SkDCurve curve;
+ curve.fQuad.set(pts);
+ curve.setQuadBounds(pts, 1, 0, 1, &fBounds);
return this;
}
@@ -362,6 +368,8 @@ public:
return start->t() * (1 - mid) + end->t() * mid;
}
+ SkDPoint top(const SkOpSpanBase* start, const SkOpSpanBase* end, double* topT) const;
+
void undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end);
int updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const;
int updateOppWinding(const SkOpAngle* angle) const;
diff --git a/src/pathops/SkPathOpsBounds.cpp b/src/pathops/SkPathOpsBounds.cpp
deleted file mode 100644
index ea13e2ed2c..0000000000
--- a/src/pathops/SkPathOpsBounds.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "SkPathOpsBounds.h"
-#include "SkPathOpsConic.h"
-#include "SkPathOpsCubic.h"
-#include "SkPathOpsLine.h"
-#include "SkPathOpsQuad.h"
-
-void SkPathOpsBounds::setConicBounds(const SkPoint a[3], SkScalar weight) {
- SkDConic conic;
- conic.set(a, weight);
- SkDRect dRect;
- dRect.setBounds(conic);
- set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop),
- SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
-}
-
-void SkPathOpsBounds::setCubicBounds(const SkPoint a[4], SkScalar ) {
- SkDCubic cubic;
- cubic.set(a);
- SkDRect dRect;
- dRect.setBounds(cubic);
- set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop),
- SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
-}
-
-void SkPathOpsBounds::setLineBounds(const SkPoint a[2], SkScalar ) {
- setPointBounds(a[0]);
- add(a[1]);
-}
-
-void SkPathOpsBounds::setQuadBounds(const SkPoint a[3], SkScalar ) {
- SkDQuad quad;
- quad.set(a);
- SkDRect dRect;
- dRect.setBounds(quad);
- set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop),
- SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
-}
-
-void (SkPathOpsBounds::* const SetCurveBounds[])(const SkPoint[], SkScalar weight) = {
- NULL,
- &SkPathOpsBounds::setLineBounds,
- &SkPathOpsBounds::setQuadBounds,
- &SkPathOpsBounds::setConicBounds,
- &SkPathOpsBounds::setCubicBounds
-};
diff --git a/src/pathops/SkPathOpsBounds.h b/src/pathops/SkPathOpsBounds.h
index b65d3bea03..7b9daa3671 100644
--- a/src/pathops/SkPathOpsBounds.h
+++ b/src/pathops/SkPathOpsBounds.h
@@ -33,11 +33,11 @@ struct SkPathOpsBounds : public SkRect {
add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom);
}
- void add(const SkPoint& pt) {
- if (pt.fX < fLeft) fLeft = pt.fX;
- if (pt.fY < fTop) fTop = pt.fY;
- if (pt.fX > fRight) fRight = pt.fX;
- if (pt.fY > fBottom) fBottom = pt.fY;
+ void add(const SkDPoint& pt) {
+ if (pt.fX < fLeft) fLeft = SkDoubleToScalar(pt.fX);
+ if (pt.fY < fTop) fTop = SkDoubleToScalar(pt.fY);
+ if (pt.fX > fRight) fRight = SkDoubleToScalar(pt.fX);
+ if (pt.fY > fBottom) fBottom = SkDoubleToScalar(pt.fY);
}
bool almostContains(const SkPoint& pt) {
@@ -55,19 +55,12 @@ struct SkPathOpsBounds : public SkRect {
|| (fLeft == fRight && fTop == fBottom);
}
- void setConicBounds(const SkPoint a[3], SkScalar weight);
- void setCubicBounds(const SkPoint a[4], SkScalar );
- void setLineBounds(const SkPoint a[2], SkScalar );
- void setQuadBounds(const SkPoint a[3], SkScalar );
-
- void setPointBounds(const SkPoint& pt) {
- fLeft = fRight = pt.fX;
- fTop = fBottom = pt.fY;
+ void setPointBounds(const SkDPoint& pt) {
+ fLeft = fRight = SkDoubleToScalar(pt.fX);
+ fTop = fBottom = SkDoubleToScalar(pt.fY);
}
typedef SkRect INHERITED;
};
-extern void (SkPathOpsBounds::* const SetCurveBounds[])(const SkPoint[], SkScalar weight);
-
#endif
diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp
index 3496179e65..05b370a1df 100644
--- a/src/pathops/SkPathOpsCommon.cpp
+++ b/src/pathops/SkPathOpsCommon.cpp
@@ -205,13 +205,13 @@ void DebugShowActiveSpans(SkTDArray<SkOpContour* >& contourList) {
#endif
static SkOpSegment* findTopSegment(const SkTDArray<SkOpContour* >& contourList,
- bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkPoint* topLeft,
+ bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkDPoint* topLeft,
bool* unsortable, bool* done, SkChunkAlloc* allocator) {
SkOpSegment* result;
const SkOpSegment* lastTopStart = NULL;
SkOpSpanBase* lastStart = NULL, * lastEnd = NULL;
do {
- SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
+ SkDPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
int contourCount = contourList.count();
SkOpSegment* topStart = NULL;
*done = true;
@@ -300,7 +300,7 @@ struct SortableTop2 { // error if local in pre-C++11
SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour* >& contourList, bool firstPass,
SkOpAngle::IncludeType angleIncludeType, bool* firstContour, SkOpSpanBase** startPtr,
- SkOpSpanBase** endPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical,
+ SkOpSpanBase** endPtr, SkDPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical,
SkChunkAlloc* allocator) {
SkOpSegment* current = findTopSegment(contourList, firstPass, startPtr, endPtr, topLeft,
unsortable, done, allocator);
diff --git a/src/pathops/SkPathOpsCommon.h b/src/pathops/SkPathOpsCommon.h
index 1bf17919ad..82eb5da215 100644
--- a/src/pathops/SkPathOpsCommon.h
+++ b/src/pathops/SkPathOpsCommon.h
@@ -19,7 +19,7 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
SkOpSpanBase** endPtr);
SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour*>& , bool firstPass,
SkOpAngle::IncludeType , bool* firstContour, SkOpSpanBase** index,
- SkOpSpanBase** endIndex, SkPoint* topLeft, bool* unsortable,
+ SkOpSpanBase** endIndex, SkDPoint* topLeft, bool* unsortable,
bool* done, bool* onlyVertical, SkChunkAlloc* );
SkOpSegment* FindUndone(SkTDArray<SkOpContour*>& contourList, SkOpSpanBase** startPtr,
SkOpSpanBase** endPtr);
diff --git a/src/pathops/SkPathOpsConic.cpp b/src/pathops/SkPathOpsConic.cpp
index 869a406dce..b9b0cda0d4 100644
--- a/src/pathops/SkPathOpsConic.cpp
+++ b/src/pathops/SkPathOpsConic.cpp
@@ -111,25 +111,3 @@ SkDPoint SkDConic::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, do
*weight = chopped.fWeight;
return chopped[1];
}
-
-SkDPoint SkDConic::top(double startT, double endT, double* topT) const {
- SkDConic sub = subDivide(startT, endT);
- SkDPoint topPt = sub[0];
- *topT = startT;
- if (topPt.fY > sub[2].fY || (topPt.fY == sub[2].fY && topPt.fX > sub[2].fX)) {
- *topT = endT;
- topPt = sub[2];
- }
- if (!between(sub[0].fY, sub[1].fY, sub[2].fY)) {
- double extremeT;
- if (FindExtrema(&sub[0].fY, sub.fWeight, &extremeT)) {
- extremeT = startT + (endT - startT) * extremeT;
- SkDPoint test = ptAtT(extremeT);
- if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) {
- *topT = extremeT;
- topPt = test;
- }
- }
- }
- return topPt;
-}
diff --git a/src/pathops/SkPathOpsConic.h b/src/pathops/SkPathOpsConic.h
index 8251901554..bc73049c46 100644
--- a/src/pathops/SkPathOpsConic.h
+++ b/src/pathops/SkPathOpsConic.h
@@ -72,6 +72,10 @@ struct SkDConic {
return fPts.isLinear(startIndex, endIndex);
}
+ bool monotonicInX() const {
+ return fPts.monotonicInX();
+ }
+
bool monotonicInY() const {
return fPts.monotonicInY();
}
@@ -109,8 +113,6 @@ struct SkDConic {
return conic.subDivide(a, c, t1, t2, newWeight);
}
- SkDPoint top(double startT, double endT, double* topT) const;
-
// utilities callable by the user from the debugger when the implementation code is linked in
void dump() const;
void dumpID(int id) const;
diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
index 63f828fb22..777298b297 100644
--- a/src/pathops/SkPathOpsCubic.cpp
+++ b/src/pathops/SkPathOpsCubic.cpp
@@ -75,7 +75,7 @@ double SkDCubic::calcPrecision() const {
return (width > height ? width : height) / gPrecisionUnit;
}
-bool SkDCubic::clockwise(bool* swap) const {
+bool SkDCubic::clockwise(const SkDCubic& whole, bool* swap) const {
SkDPoint lastPt = fPts[kPointLast];
SkDPoint firstPt = fPts[0];
double sum = 0;
@@ -105,34 +105,15 @@ bool SkDCubic::clockwise(bool* swap) const {
lastPt = firstPt;
firstPt = idx == 1 ? fPts[furthest] : fPts[kPointLast];
}
- *swap = sum > 0 && !this->monotonicInY();
+ *swap = sum > 0 && !this->monotonicInY() && !whole.monotonicInY();
return sum <= 0;
}
bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* swap) {
SkDCubic cubic;
cubic.set(pts);
-#if 0
- bool flip = startT > endT;
- double inflectionTs[2];
- int inflections = cubic.findInflections(inflectionTs);
- for (int index = 0; index < inflections; ++index) {
- double inflectionT = inflectionTs[index];
- if (between(startT, inflectionT, endT)) {
- if (flip) {
- if (!roughly_equal(inflectionT, endT)) {
- startT = inflectionT;
- }
- } else {
- if (!roughly_equal(inflectionT, startT)) {
- endT = inflectionT;
- }
- }
- }
- }
-#endif
SkDCubic part = cubic.subDivide(startT, endT);
- return part.clockwise(swap);
+ return part.clockwise(cubic, swap);
}
void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) {
@@ -301,9 +282,14 @@ bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t, CubicType*
return false;
}
+bool SkDCubic::monotonicInX() const {
+ return precisely_between(fPts[0].fX, fPts[1].fX, fPts[3].fX)
+ && precisely_between(fPts[0].fX, fPts[2].fX, fPts[3].fX);
+}
+
bool SkDCubic::monotonicInY() const {
- return between(fPts[0].fY, fPts[1].fY, fPts[3].fY)
- && between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
+ return precisely_between(fPts[0].fY, fPts[1].fY, fPts[3].fY)
+ && precisely_between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
}
void SkDCubic::otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const {
@@ -343,6 +329,28 @@ int SkDCubic::RootsValidT(double A, double B, double C, double D, double t[3]) {
double s[3];
int realRoots = RootsReal(A, B, C, D, s);
int foundRoots = SkDQuad::AddValidTs(s, realRoots, t);
+ for (int index = 0; index < realRoots; ++index) {
+ double tValue = s[index];
+ if (!approximately_one_or_less(tValue) && between(1, tValue, 1.00005)) {
+ for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
+ if (approximately_equal(t[idx2], 1)) {
+ goto nextRoot;
+ }
+ }
+ SkASSERT(foundRoots < 3);
+ t[foundRoots++] = 1;
+ } else if (!approximately_zero_or_more(tValue) && between(-0.00005, tValue, 0)) {
+ for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
+ if (approximately_equal(t[idx2], 0)) {
+ goto nextRoot;
+ }
+ }
+ SkASSERT(foundRoots < 3);
+ t[foundRoots++] = 0;
+ }
+nextRoot:
+ ;
+ }
return foundRoots;
}
@@ -487,10 +495,14 @@ static void formulate_F1DotF2(const double src[], double coeff[4]) {
C = 3(b - a)
Solve for t, keeping only those that fit between 0 < t < 1
*/
-int SkDCubic::FindExtrema(double a, double b, double c, double d, double tValues[2]) {
+int SkDCubic::FindExtrema(const double src[], double tValues[2]) {
// we divide A,B,C by 3 to simplify
- double A = d - a + 3*(b - c);
- double B = 2*(a - b - b + c);
+ double a = src[0];
+ double b = src[2];
+ double c = src[4];
+ double d = src[6];
+ double A = d - a + 3 * (b - c);
+ double B = 2 * (a - b - b + c);
double C = b - a;
return SkDQuad::RootsValidT(A, B, C, tValues);
@@ -519,29 +531,6 @@ int SkDCubic::findMaxCurvature(double tValues[]) const {
return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues);
}
-SkDPoint SkDCubic::top(double startT, double endT, double* topT) const {
- SkDCubic sub = subDivide(startT, endT);
- SkDPoint topPt = sub[0];
- *topT = startT;
- if (topPt.fY > sub[3].fY || (topPt.fY == sub[3].fY && topPt.fX > sub[3].fX)) {
- *topT = endT;
- topPt = sub[3];
- }
- double extremeTs[2];
- if (!sub.monotonicInY()) {
- int roots = FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, sub[3].fY, extremeTs);
- for (int index = 0; index < roots; ++index) {
- double t = startT + (endT - startT) * extremeTs[index];
- SkDPoint mid = ptAtT(t);
- if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) {
- *topT = t;
- topPt = mid;
- }
- }
- }
- return topPt;
-}
-
SkDPoint SkDCubic::ptAtT(double t) const {
if (0 == t) {
return fPts[0];
diff --git a/src/pathops/SkPathOpsCubic.h b/src/pathops/SkPathOpsCubic.h
index 269073ca69..f9d291056e 100644
--- a/src/pathops/SkPathOpsCubic.h
+++ b/src/pathops/SkPathOpsCubic.h
@@ -57,7 +57,7 @@ struct SkDCubic {
double binarySearch(double min, double max, double axisIntercept, SearchAxis xAxis) const;
double calcPrecision() const;
SkDCubicPair chopAt(double t) const;
- bool clockwise(bool* swap) const;
+ bool clockwise(const SkDCubic& whole, bool* swap) const;
static bool Clockwise(const SkPoint* pts, double startT, double endT, bool* swap);
static void Coefficients(const double* cubic, double* A, double* B, double* C, double* D);
static bool ComplexBreak(const SkPoint pts[4], SkScalar* t, CubicType* cubicType);
@@ -72,7 +72,7 @@ struct SkDCubic {
void dumpInner() const;
SkDVector dxdyAtT(double t) const;
bool endsAreExtremaInXOrY() const;
- static int FindExtrema(double a, double b, double c, double d, double tValue[2]);
+ static int FindExtrema(const double src[], double tValue[2]);
int findInflections(double tValues[2]) const;
static int FindInflections(const SkPoint a[kPointCount], double tValues[2]) {
@@ -87,6 +87,7 @@ struct SkDCubic {
bool hullIntersects(const SkDQuad& c2, bool* isLinear) const;
bool hullIntersects(const SkDPoint* pts, int ptCount, bool* isLinear) const;
bool isLinear(int startIndex, int endIndex) const;
+ bool monotonicInX() const;
bool monotonicInY() const;
void otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const;
SkDPoint ptAtT(double t) const;
@@ -121,7 +122,6 @@ struct SkDCubic {
cubic.subDivide(a, d, t1, t2, p);
}
- SkDPoint top(double startT, double endT, double* topT) const;
SkDQuad toQuad() const;
static const int gPrecisionUnit;
diff --git a/src/pathops/SkPathOpsCurve.cpp b/src/pathops/SkPathOpsCurve.cpp
new file mode 100644
index 0000000000..651e64a908
--- /dev/null
+++ b/src/pathops/SkPathOpsCurve.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkPathOpsBounds.h"
+#include "SkPathOpsRect.h"
+#include "SkPathOpsCurve.h"
+
+SkDPoint SkDCurve::conicTop(const SkPoint curve[3], SkScalar curveWeight,
+ double startT, double endT, double* topT) {
+ SkDPoint topPt = fConic[0];
+ *topT = startT;
+ if (topPt.fY > fConic[2].fY || (topPt.fY == fConic[2].fY && topPt.fX > fConic[2].fX)) {
+ *topT = endT;
+ topPt = fConic[2];
+ }
+ if (!fConic.monotonicInY()) {
+ double extremeT;
+ if (SkDConic::FindExtrema(&fConic.fPts.fPts[0].fY, fConic.fWeight, &extremeT)) {
+ SkDConic dCurve;
+ dCurve.set(curve, curveWeight);
+ extremeT = startT + (endT - startT) * extremeT;
+ SkDPoint test = dCurve.ptAtT(extremeT);
+ if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) {
+ *topT = extremeT;
+ topPt = test;
+ }
+ }
+ }
+ return topPt;
+}
+
+SkDPoint SkDCurve::cubicTop(const SkPoint curve[4], SkScalar ,
+ double startT, double endT, double* topT) {
+ SkDPoint topPt = fCubic[0];
+ *topT = startT;
+ if (topPt.fY > fCubic[3].fY || (topPt.fY == fCubic[3].fY && topPt.fX > fCubic[3].fX)) {
+ *topT = endT;
+ topPt = fCubic[3];
+ }
+ double extremeTs[2];
+ if (!fCubic.monotonicInY()) {
+ int roots = SkDCubic::FindExtrema(&fCubic.fPts[0].fY, extremeTs);
+ SkDCubic dCurve;
+ dCurve.set(curve);
+ for (int index = 0; index < roots; ++index) {
+ double t = startT + (endT - startT) * extremeTs[index];
+ SkDPoint mid = dCurve.ptAtT(t);
+ if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) {
+ *topT = t;
+ topPt = mid;
+ }
+ }
+ }
+ return topPt;
+}
+
+SkDPoint SkDCurve::lineTop(const SkPoint[2], SkScalar , double startT, double endT, double* topT) {
+ SkDPoint topPt = fLine[0];
+ *topT = startT;
+ if (topPt.fY > fLine[1].fY || (topPt.fY == fLine[1].fY && topPt.fX > fLine[1].fX)) {
+ *topT = endT;
+ topPt = fLine[1];
+ }
+ return topPt;
+}
+
+SkDPoint SkDCurve::quadTop(const SkPoint curve[3], SkScalar ,
+ double startT, double endT, double* topT) {
+ SkDPoint topPt = fQuad[0];
+ *topT = startT;
+ if (topPt.fY > fQuad[2].fY || (topPt.fY == fQuad[2].fY && topPt.fX > fQuad[2].fX)) {
+ *topT = endT;
+ topPt = fQuad[2];
+ }
+ if (!fQuad.monotonicInY()) {
+ double extremeT;
+ if (SkDQuad::FindExtrema(&fQuad.fPts[0].fY, &extremeT)) {
+ SkDQuad dCurve;
+ dCurve.set(curve);
+ extremeT = startT + (endT - startT) * extremeT;
+ SkDPoint test = dCurve.ptAtT(extremeT);
+ if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) {
+ *topT = extremeT;
+ topPt = test;
+ }
+ }
+ }
+ return topPt;
+}
+
+SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar curveWeight,
+ double tStart, double tEnd, double* topT) = {
+ NULL,
+ &SkDCurve::lineTop,
+ &SkDCurve::quadTop,
+ &SkDCurve::conicTop,
+ &SkDCurve::cubicTop
+};
+
+void SkDCurve::setConicBounds(const SkPoint curve[3], SkScalar curveWeight,
+ double tStart, double tEnd, SkPathOpsBounds* bounds) {
+ SkDConic dCurve;
+ dCurve.set(curve, curveWeight);
+ SkDRect dRect;
+ dRect.setBounds(dCurve, fConic, tStart, tEnd);
+ bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop),
+ SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
+}
+
+void SkDCurve::setCubicBounds(const SkPoint curve[4], SkScalar ,
+ double tStart, double tEnd, SkPathOpsBounds* bounds) {
+ SkDCubic dCurve;
+ dCurve.set(curve);
+ SkDRect dRect;
+ dRect.setBounds(dCurve, fCubic, tStart, tEnd);
+ bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop),
+ SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
+}
+
+void SkDCurve::setLineBounds(const SkPoint[2], SkScalar ,
+ double , double , SkPathOpsBounds* bounds) {
+ bounds->setPointBounds(fLine[0]);
+ bounds->add(fLine[1]);
+}
+
+void SkDCurve::setQuadBounds(const SkPoint curve[3], SkScalar ,
+ double tStart, double tEnd, SkPathOpsBounds* bounds) {
+ SkDQuad dCurve;
+ dCurve.set(curve);
+ SkDRect dRect;
+ dRect.setBounds(dCurve, fQuad, tStart, tEnd);
+ bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop),
+ SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
+}
+
+void (SkDCurve::* const SetBounds[])(const SkPoint curve[], SkScalar curveWeight,
+ double tStart, double tEnd, SkPathOpsBounds* bounds) = {
+ NULL,
+ &SkDCurve::setLineBounds,
+ &SkDCurve::setQuadBounds,
+ &SkDCurve::setConicBounds,
+ &SkDCurve::setCubicBounds
+};
diff --git a/src/pathops/SkPathOpsCurve.h b/src/pathops/SkPathOpsCurve.h
index 69af91cf34..bfbc515719 100644
--- a/src/pathops/SkPathOpsCurve.h
+++ b/src/pathops/SkPathOpsCurve.h
@@ -16,6 +16,8 @@
#include "SkPath.h"
#endif
+struct SkPathOpsBounds;
+
struct SkOpCurve {
SkPoint fPts[4];
SkScalar fWeight;
@@ -43,6 +45,7 @@ struct SkOpCurve {
SkDEBUGCODE(fWeight = 1);
SkDEBUGCODE(fVerb = SkPath::kCubic_Verb);
}
+
};
struct SkDCurve {
@@ -64,9 +67,29 @@ struct SkDCurve {
return fCubic[n];
}
+ SkDPoint conicTop(const SkPoint curve[3], SkScalar curveWeight,
+ double s, double e, double* topT);
+ SkDPoint cubicTop(const SkPoint curve[4], SkScalar , double s, double e, double* topT);
void dumpID(int ) const;
+ SkDPoint lineTop(const SkPoint[2], SkScalar , double , double , double* topT);
+ SkDPoint quadTop(const SkPoint curve[3], SkScalar , double s, double e, double* topT);
+
+ void setConicBounds(const SkPoint curve[3], SkScalar curveWeight,
+ double s, double e, SkPathOpsBounds* );
+ void setCubicBounds(const SkPoint curve[4], SkScalar ,
+ double s, double e, SkPathOpsBounds* );
+ void setLineBounds(const SkPoint[2], SkScalar , double , double , SkPathOpsBounds* );
+ void setQuadBounds(const SkPoint curve[3], SkScalar ,
+ double s, double e, SkPathOpsBounds*);
};
+
+extern void (SkDCurve::* const SetBounds[])(const SkPoint curve[], SkScalar cWeight,
+ double tStart, double tEnd, SkPathOpsBounds* );
+
+extern SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar cWeight,
+ double tStart, double tEnd, double* topT);
+
static SkDPoint dline_xy_at_t(const SkPoint a[2], SkScalar , double t) {
SkDLine line;
line.set(a);
@@ -179,36 +202,6 @@ static SkVector (* const CurveSlopeAtT[])(const SkPoint[], SkScalar , double ) =
fcubic_dxdy_at_t
};
-static SkPoint quad_top(const SkPoint a[3], SkScalar , double startT, double endT, double* topT) {
- SkDQuad quad;
- quad.set(a);
- SkDPoint topPt = quad.top(startT, endT, topT);
- return topPt.asSkPoint();
-}
-
-static SkPoint conic_top(const SkPoint a[3], SkScalar weight, double startT, double endT,
- double* topT) {
- SkDConic conic;
- conic.set(a, weight);
- SkDPoint topPt = conic.top(startT, endT, topT);
- return topPt.asSkPoint();
-}
-
-static SkPoint cubic_top(const SkPoint a[4], SkScalar , double startT, double endT, double* topT) {
- SkDCubic cubic;
- cubic.set(a);
- SkDPoint topPt = cubic.top(startT, endT, topT);
- return topPt.asSkPoint();
-}
-
-static SkPoint (* const CurveTop[])(const SkPoint[], SkScalar , double , double , double* ) = {
- NULL,
- NULL,
- quad_top,
- conic_top,
- cubic_top
-};
-
static bool line_is_vertical(const SkPoint a[2], SkScalar , double startT, double endT) {
SkDLine line;
line.set(a);
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index 8473d66c70..0624ad687a 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -37,8 +37,6 @@
#if FORCE_RELEASE
-#define DEBUG_CUBIC_SWAP_TOP 0
-
#define DEBUG_ACTIVE_OP 0
#define DEBUG_ACTIVE_SPANS 0
#define DEBUG_ADD_INTERSECTING_TS 0
@@ -47,23 +45,21 @@
#define DEBUG_ASSEMBLE 0
#define DEBUG_CUBIC_BINARY_SEARCH 0
#define DEBUG_CUBIC_SPLIT 0
-#define DEBUG_DUMP_SEGMENTS DEBUG_CUBIC_SWAP_TOP
+#define DEBUG_DUMP_SEGMENTS 0 // 1
#define DEBUG_FLOW 0
#define DEBUG_LIMIT_WIND_SUM 0
#define DEBUG_MARK_DONE 0
#define DEBUG_PATH_CONSTRUCTION 0
#define DEBUG_PERP 0
-#define DEBUG_SHOW_TEST_NAME DEBUG_CUBIC_SWAP_TOP
+#define DEBUG_SHOW_TEST_NAME 0 // 1
#define DEBUG_SORT 0
-#define DEBUG_SWAP_TOP DEBUG_CUBIC_SWAP_TOP
+#define DEBUG_SWAP_TOP 0 // 1
#define DEBUG_T_SECT 0
#define DEBUG_T_SECT_DUMP 0
#define DEBUG_VALIDATE 0
#define DEBUG_WINDING 0
#define DEBUG_WINDING_AT_T 0
-#undef DEBUG_CUBIC_SWAP_TOP
-
#else
#define DEBUG_ACTIVE_OP 1
diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp
index 4e3ec4aad3..1105af5d70 100644
--- a/src/pathops/SkPathOpsOp.cpp
+++ b/src/pathops/SkPathOpsOp.cpp
@@ -104,8 +104,8 @@ static bool bridgeOp(SkTDArray<SkOpContour* >& contourList, const SkPathOp op,
bool unsortable = false;
bool topUnsortable = false;
bool firstPass = true;
- SkPoint lastTopLeft;
- SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
+ SkDPoint lastTopLeft;
+ SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
SkOpSpanBase* start = NULL;
SkOpSpanBase* end = NULL;
diff --git a/src/pathops/SkPathOpsQuad.cpp b/src/pathops/SkPathOpsQuad.cpp
index 397a3ce98a..66f191bb0e 100644
--- a/src/pathops/SkPathOpsQuad.cpp
+++ b/src/pathops/SkPathOpsQuad.cpp
@@ -240,6 +240,10 @@ static double interp_quad_coords(const double* src, double t) {
return abc;
}
+bool SkDQuad::monotonicInX() const {
+ return between(fPts[0].fX, fPts[1].fX, fPts[2].fX);
+}
+
bool SkDQuad::monotonicInY() const {
return between(fPts[0].fY, fPts[1].fY, fPts[2].fY);
}
@@ -323,28 +327,6 @@ SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, dou
return b;
}
-SkDPoint SkDQuad::top(double startT, double endT, double* topT) const {
- SkDQuad sub = subDivide(startT, endT);
- SkDPoint topPt = sub[0];
- *topT = startT;
- if (topPt.fY > sub[2].fY || (topPt.fY == sub[2].fY && topPt.fX > sub[2].fX)) {
- *topT = endT;
- topPt = sub[2];
- }
- if (!between(sub[0].fY, sub[1].fY, sub[2].fY)) {
- double extremeT;
- if (FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, &extremeT)) {
- extremeT = startT + (endT - startT) * extremeT;
- SkDPoint test = ptAtT(extremeT);
- if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) {
- *topT = extremeT;
- topPt = test;
- }
- }
- }
- return topPt;
-}
-
/* classic one t subdivision */
static void interp_quad_coords(const double* src, double* dst, double t) {
double ab = SkDInterp(src[0], src[2], t);
@@ -397,10 +379,13 @@ static int valid_unit_divide(double numer, double denom, double* ratio)
B = 2(b - a)
Solve for t, only if it fits between 0 < t < 1
*/
-int SkDQuad::FindExtrema(double a, double b, double c, double tValue[1]) {
+int SkDQuad::FindExtrema(const double src[], double tValue[1]) {
/* At + B == 0
t = -B / A
*/
+ double a = src[0];
+ double b = src[2];
+ double c = src[4];
return valid_unit_divide(a - b, a - b - b + c, tValue);
}
diff --git a/src/pathops/SkPathOpsQuad.h b/src/pathops/SkPathOpsQuad.h
index b201860f98..de4ce4baa3 100644
--- a/src/pathops/SkPathOpsQuad.h
+++ b/src/pathops/SkPathOpsQuad.h
@@ -62,11 +62,12 @@ struct SkDQuad {
SkDQuadPair chopAt(double t) const;
static bool Clockwise(const SkOpCurve& edge, bool* swap);
SkDVector dxdyAtT(double t) const;
- static int FindExtrema(double a, double b, double c, double tValue[1]);
+ static int FindExtrema(const double src[], double tValue[1]);
bool hullIntersects(const SkDQuad& , bool* isLinear) const;
bool hullIntersects(const SkDConic& , bool* isLinear) const;
bool hullIntersects(const SkDCubic& , bool* isLinear) const;
bool isLinear(int startIndex, int endIndex) const;
+ bool monotonicInX() const;
bool monotonicInY() const;
double nearestT(const SkDPoint&) const;
void otherPts(int oddMan, const SkDPoint* endPt[2]) const;
@@ -89,7 +90,6 @@ struct SkDQuad {
}
SkDConic toConic() const;
SkDCubic toCubic() const;
- SkDPoint top(double startT, double endT, double* topT) const;
// utilities callable by the user from the debugger when the implementation code is linked in
void dump() const;
diff --git a/src/pathops/SkPathOpsRect.cpp b/src/pathops/SkPathOpsRect.cpp
index 540db16a0e..8c01153532 100644
--- a/src/pathops/SkPathOpsRect.cpp
+++ b/src/pathops/SkPathOpsRect.cpp
@@ -10,54 +10,53 @@
#include "SkPathOpsQuad.h"
#include "SkPathOpsRect.h"
-void SkDRect::setBounds(const SkDQuad& quad) {
- set(quad[0]);
- add(quad[2]);
+void SkDRect::setBounds(const SkDQuad& curve, const SkDQuad& sub, double startT, double endT) {
+ set(sub[0]);
+ add(sub[2]);
double tValues[2];
int roots = 0;
- if (!between(quad[0].fX, quad[1].fX, quad[2].fX)) {
- roots = SkDQuad::FindExtrema(quad[0].fX, quad[1].fX, quad[2].fX, tValues);
+ if (!sub.monotonicInX()) {
+ roots = SkDQuad::FindExtrema(&sub[0].fX, tValues);
}
- if (!between(quad[0].fY, quad[1].fY, quad[2].fY)) {
- roots += SkDQuad::FindExtrema(quad[0].fY, quad[1].fY, quad[2].fY, &tValues[roots]);
+ if (!sub.monotonicInY()) {
+ roots += SkDQuad::FindExtrema(&sub[0].fY, &tValues[roots]);
}
- for (int x = 0; x < roots; ++x) {
- add(quad.ptAtT(tValues[x]));
+ for (int index = 0; index < roots; ++index) {
+ double t = startT + (endT - startT) * tValues[index];
+ add(curve.ptAtT(t));
}
}
-void SkDRect::setBounds(const SkDConic& conic) {
- set(conic[0]);
- add(conic[2]);
+void SkDRect::setBounds(const SkDConic& curve, const SkDConic& sub, double startT, double endT) {
+ set(sub[0]);
+ add(sub[2]);
double tValues[2];
int roots = 0;
- if (!between(conic[0].fX, conic[1].fX, conic[2].fX)) {
- roots = SkDConic::FindExtrema(&conic[0].fX, conic.fWeight, tValues);
+ if (!sub.monotonicInX()) {
+ roots = SkDConic::FindExtrema(&sub[0].fX, sub.fWeight, tValues);
}
- if (!between(conic[0].fY, conic[1].fY, conic[2].fY)) {
- roots += SkDConic::FindExtrema(&conic[0].fY, conic.fWeight, &tValues[roots]);
+ if (!sub.monotonicInY()) {
+ roots += SkDConic::FindExtrema(&sub[0].fY, sub.fWeight, &tValues[roots]);
}
- for (int x = 0; x < roots; ++x) {
- add(conic.ptAtT(tValues[x]));
+ for (int index = 0; index < roots; ++index) {
+ double t = startT + (endT - startT) * tValues[index];
+ add(curve.ptAtT(t));
}
}
-static bool is_bounded_by_end_points(double a, double b, double c, double d) {
- return between(a, b, d) && between(a, c, d);
-}
-
-void SkDRect::setBounds(const SkDCubic& c) {
- set(c[0]);
- add(c[3]);
+void SkDRect::setBounds(const SkDCubic& curve, const SkDCubic& sub, double startT, double endT) {
+ set(sub[0]);
+ add(sub[3]);
double tValues[4];
int roots = 0;
- if (!is_bounded_by_end_points(c[0].fX, c[1].fX, c[2].fX, c[3].fX)) {
- roots = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c[3].fX, tValues);
+ if (!sub.monotonicInX()) {
+ roots = SkDCubic::FindExtrema(&sub[0].fX, tValues);
}
- if (!is_bounded_by_end_points(c[0].fY, c[1].fY, c[2].fY, c[3].fY)) {
- roots += SkDCubic::FindExtrema(c[0].fY, c[1].fY, c[2].fY, c[3].fY, &tValues[roots]);
+ if (!sub.monotonicInY()) {
+ roots += SkDCubic::FindExtrema(&sub[0].fY, &tValues[roots]);
}
- for (int x = 0; x < roots; ++x) {
- add(c.ptAtT(tValues[x]));
+ for (int index = 0; index < roots; ++index) {
+ double t = startT + (endT - startT) * tValues[index];
+ add(curve.ptAtT(t));
}
}
diff --git a/src/pathops/SkPathOpsRect.h b/src/pathops/SkPathOpsRect.h
index f783d96b99..7fec70a32a 100644
--- a/src/pathops/SkPathOpsRect.h
+++ b/src/pathops/SkPathOpsRect.h
@@ -48,9 +48,23 @@ struct SkDRect {
return fBottom - fTop;
}
- void setBounds(const SkDConic&);
- void setBounds(const SkDCubic&);
- void setBounds(const SkDQuad&);
+ void setBounds(const SkDConic& curve) {
+ setBounds(curve, curve, 0, 1);
+ }
+
+ void setBounds(const SkDConic& curve, const SkDConic& sub, double tStart, double tEnd);
+
+ void setBounds(const SkDCubic& curve) {
+ setBounds(curve, curve, 0, 1);
+ }
+
+ void setBounds(const SkDCubic& curve, const SkDCubic& sub, double tStart, double tEnd);
+
+ void setBounds(const SkDQuad& curve) {
+ setBounds(curve, curve, 0, 1);
+ }
+
+ void setBounds(const SkDQuad& curve, const SkDQuad& sub, double tStart, double tEnd);
};
#endif
diff --git a/src/pathops/SkPathOpsSimplify.cpp b/src/pathops/SkPathOpsSimplify.cpp
index b4f8e22142..14c6837c1b 100644
--- a/src/pathops/SkPathOpsSimplify.cpp
+++ b/src/pathops/SkPathOpsSimplify.cpp
@@ -16,8 +16,8 @@ static bool bridgeWinding(SkTDArray<SkOpContour* >& contourList, SkPathWriter* s
bool unsortable = false;
bool topUnsortable = false;
bool firstPass = true;
- SkPoint lastTopLeft;
- SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
+ SkDPoint lastTopLeft;
+ SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
SkOpSpanBase* start = NULL;
SkOpSpanBase* end = NULL;
diff --git a/tests/PathOpsBoundsTest.cpp b/tests/PathOpsBoundsTest.cpp
index 1160ae66c1..0c74b69b12 100644
--- a/tests/PathOpsBoundsTest.cpp
+++ b/tests/PathOpsBoundsTest.cpp
@@ -6,6 +6,7 @@
*/
#include "PathOpsTestCommon.h"
#include "SkPathOpsBounds.h"
+#include "SkPathOpsCurve.h"
#include "Test.h"
static const SkRect sectTests[][2] = {
@@ -74,9 +75,9 @@ DEF_TEST(PathOpsBounds, reporter) {
ordinal.set(1, 2, 3, 4);
bounds.add(ordinal);
REPORTER_ASSERT(reporter, bounds == expected);
- SkPoint topLeft = {0, 0};
+ SkDPoint topLeft = {0, 0};
bounds.setPointBounds(topLeft);
- SkPoint botRight = {3, 4};
+ SkDPoint botRight = {3, 4};
bounds.add(botRight);
REPORTER_ASSERT(reporter, bounds == expected);
for (size_t index = 0; index < emptyTestsCount; ++index) {
@@ -92,19 +93,23 @@ DEF_TEST(PathOpsBounds, reporter) {
REPORTER_ASSERT(reporter, !empty);
}
const SkPoint curvePts[] = {{0, 0}, {1, 2}, {3, 4}, {5, 6}};
- bounds.setLineBounds(curvePts, 1);
+ SkDCurve curve;
+ curve.fLine.set(curvePts);
+ curve.setLineBounds(curvePts, 1, 0, 1, &bounds);
expected.set(0, 0, 1, 2);
REPORTER_ASSERT(reporter, bounds == expected);
- (bounds.*SetCurveBounds[SkPath::kLine_Verb])(curvePts, 1);
+ (curve.*SetBounds[SkPath::kLine_Verb])(curvePts, 1, 0, 1, &bounds);
REPORTER_ASSERT(reporter, bounds == expected);
- bounds.setQuadBounds(curvePts, 1);
+ curve.fQuad.set(curvePts);
+ curve.setQuadBounds(curvePts, 1, 0, 1, &bounds);
expected.set(0, 0, 3, 4);
REPORTER_ASSERT(reporter, bounds == expected);
- (bounds.*SetCurveBounds[SkPath::kQuad_Verb])(curvePts, 1);
+ (curve.*SetBounds[SkPath::kQuad_Verb])(curvePts, 1, 0, 1, &bounds);
REPORTER_ASSERT(reporter, bounds == expected);
- bounds.setCubicBounds(curvePts, 1);
+ curve.fCubic.set(curvePts);
+ curve.setCubicBounds(curvePts, 1, 0, 1, &bounds);
expected.set(0, 0, 5, 6);
REPORTER_ASSERT(reporter, bounds == expected);
- (bounds.*SetCurveBounds[SkPath::kCubic_Verb])(curvePts, 1);
+ (curve.*SetBounds[SkPath::kCubic_Verb])(curvePts, 1, 0, 1, &bounds);
REPORTER_ASSERT(reporter, bounds == expected);
}
diff --git a/tests/PathOpsCubicLineIntersectionTest.cpp b/tests/PathOpsCubicLineIntersectionTest.cpp
index 6fdce3cb18..a1f1d9f4f2 100644
--- a/tests/PathOpsCubicLineIntersectionTest.cpp
+++ b/tests/PathOpsCubicLineIntersectionTest.cpp
@@ -49,6 +49,9 @@ static void testFail(skiatest::Reporter* reporter, int iIndex) {
}
static lineCubic lineCubicTests[] = {
+ {{{{0, 6}, {1.0851458311080933, 4.3722810745239258}, {1.5815209150314331, 3.038947582244873}, {1.9683018922805786, 1.9999997615814209}}},
+ {{{3,2}, {1,2}}}},
+
{{{{0.468027353,4}, {1.06734705,1.33333337}, {1.36700678,0}, {3,0}}},
{{{2,1}, {0,1}}}},
diff --git a/tests/PathOpsDCubicTest.cpp b/tests/PathOpsDCubicTest.cpp
index c7c9f2ab96..b5fe8f744b 100644
--- a/tests/PathOpsDCubicTest.cpp
+++ b/tests/PathOpsDCubicTest.cpp
@@ -21,7 +21,7 @@ DEF_TEST(PathOpsDCubic, reporter) {
const SkDCubic& cubic = tests[index];
SkASSERT(ValidCubic(cubic));
bool skip;
- bool result = cubic.clockwise(&skip);
+ bool result = cubic.clockwise(cubic, &skip);
if (!result) {
SkDebugf("%s [%d] expected clockwise\n", __FUNCTION__, index);
REPORTER_ASSERT(reporter, 0);
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index 92b0e87465..9c57797987 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -289,7 +289,7 @@ int comparePaths(skiatest::Reporter* reporter, const char* filename, const SkPat
return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
}
-const int gTestFirst = 20;
+const int gTestFirst = 41;
static int gTestNo = gTestFirst;
static SkTDArray<SkPathOp> gTestOp;
@@ -309,7 +309,7 @@ static void showPathOpPath(const char* testName, const SkPath& one, const SkPath
SkPathOpsDebug::ShowOnePath(b, "pathB", false);
SkDebugf(" testPathOp(reporter, path, pathB, %s, filename);\n", opStrs[shapeOp]);
SkDebugf("}\n");
- drawAsciiPaths(scaledOne, scaledTwo, true);
+ drawAsciiPaths(scaledOne, scaledTwo, false);
}
void ShowTestArray(const char* testName) {
@@ -341,9 +341,10 @@ static int comparePaths(skiatest::Reporter* reporter, const char* testName, cons
}
if (errors2x2 > MAX_ERRORS) {
SkAutoMutexAcquire autoM(compareDebugOut3);
- SkDebugf("\n*** this test fails ***\n");
showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
+ SkDebugf("\n/*");
REPORTER_ASSERT(reporter, 0);
+ SkDebugf(" */\n");
} else if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
SkAutoMutexAcquire autoM(compareDebugOut4);
showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
@@ -531,9 +532,6 @@ static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkP
scaledOut.setFillType(out.getFillType());
int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
a, b, shapeOp, scale, expectSuccess);
- if (result) {
- REPORTER_ASSERT(reporter, 0);
- }
reporter->bumpTestCount();
return result == 0;
}
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 993fdd9a23..f25ebc97a1 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -4478,11 +4478,747 @@ static void cubicOp157(skiatest::Reporter* reporter, const char* filename) {
testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
}
+static void cubics20d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 3, 6, 0, 3, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 6);
+ pathB.cubicTo(2, 3, 2, 1, 3, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void loops20i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 2, 0.833333313f, 2, 1, 3.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0.833333313f, 2, 1, 3.66666651f, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops21i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 2, 0.833333313f, 2, 1, 4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0.833333313f, 2, 1, 4, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops22i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(0, 3, 0.833333313f, 3, 1, 4.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 3);
+ pathB.cubicTo(0.833333313f, 3, 1, 4.66666651f, 1, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops23i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 1, 6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f, 1, 5);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void loops24i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 2, 0.833333313f, 2, 1, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0.833333313f, 2, 1, 3, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops25i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 5, 0.833333313f, 5, 1, 7);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(0.833333313f, 5, 1, 7, 1, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops26i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 6);
+ path.cubicTo(0, 2, 6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f, 1, 6);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void loops27i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(0, 3, 0.833333313f, 3, 1, 4.33333349f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 3);
+ pathB.cubicTo(0.833333313f, 3, 1, 4.33333349f, 1, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops28i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(1, 3, 1.83333337f, 3, 2, 4.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(1.83333337f, 3, 2, 4.66666651f, 2, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops29i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(0, 4, 1.66666663f, 4, 2, 7.33333302f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(1.66666663f, 4, 2, 7.33333302f, 2, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops30i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(0, 4, 1.66666663f, 4, 2, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(1.66666663f, 4, 2, 8, 2, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops31i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 5);
+ path.cubicTo(1, 5, 1.83333337f, 5, 2, 6.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(1.83333337f, 5, 2, 6.66666651f, 2, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops32i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 6, 1.83333337f, 6, 2, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 6);
+ pathB.cubicTo(1.83333337f, 6, 2, 8, 2, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops33i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 2, 7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void loops33iMod(skiatest::Reporter* reporter, const char* filename) {
+ SkPoint pts[] = {{2, 6}, {1, 2}, {7.16666698f, 6.66666698f}, {-4.66666651f, 7.66666651f},
+ {1, 2}, {7.16666698f, 6.66666698f}, {-4.66666651f, 7.66666651f}, {2, 6}};
+ bool up = false;
+ float offset = 0.0380172729f;
+ float step = 7.62939453e-006f;
+ bool lastResult = true;
+ // for (int i = 0; i < 30; ++i) {
+ SkString name(filename);
+ // name.appendS32(i);
+ // if (i > 0) {
+ // SkDebugf("\n\n<div id=\"%s\">\n", name.c_str());
+ // }
+ pts[5].fY = 6.66666698f + offset;
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(pts[4]);
+ pathB.cubicTo(pts[5], pts[6], pts[7]);
+ pathB.close();
+ bool result = testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, name.c_str(),
+ FLAGS_runFail);
+ if (lastResult != result) {
+ up = !up;
+ }
+ step /= 2;
+ offset += up ? step : -step;
+ lastResult = result;
+ // }
+}
+
+
+static void loops33iAsQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 2, 7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops34i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(0, 4, 2.5f, 4, 3, 9);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(2.5f, 4, 3, 9, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops35i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(0, 4, 2.5f, 4, 3, 10);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(2.5f, 4, 3, 10, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops36i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(1, 4, 2.66666675f, 4, 3, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(2.66666675f, 4, 3, 8, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops37i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(1, 4, 1.83333337f, 4, 2, 5.33333349f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(1.83333337f, 4, 2, 5.33333349f, 2, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops38i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(2, 4, 2.83333325f, 4, 3, 6);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(2.83333325f, 4, 3, 6, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops39i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 5);
+ path.cubicTo(0, 5, 2.5f, 5, 3, 10);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(2.5f, 5, 3, 10, 3, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops40i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 5);
+ path.cubicTo(0, 5, 2.5f, 5, 3, 11);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(2.5f, 5, 3, 11, 3, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops40iAsQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 5);
+ path.cubicTo(0, 5, 2.5f, 5, 3, 11);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(2.5f, 5, 3, 11, 3, 5);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops41i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 1, 6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f, 1, 5);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops42i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 6);
+ path.cubicTo(0, 2, 6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f, 1, 6);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops43i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 2, 7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops44i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 1, 7.33333302f, 5.33333349f, -7, 7);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(7.33333302f, 5.33333349f, -7, 7, 1, 5);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops45i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 6);
+ path.cubicTo(0, 2, 7.33333302f, 6.33333302f, -7, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(7.33333302f, 6.33333302f, -7, 8, 1, 6);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops46i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 2, 8.33333302f, 6.33333302f, -6, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(8.33333302f, 6.33333302f, -6, 8, 2, 6);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops47i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(0, 1, 6, 5.83333302f, -4, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(6, 5.83333302f, -4, 8, 2, 4);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops48i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(0, 1, 9.33333302f, 6.83333302f, -8.33333302f, 9.16666603f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(9.33333302f, 6.83333302f, -8.33333302f, 9.16666603f, 2, 6);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops49i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(1, 4, -0.166666687f, 2.66666675f, 1.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(-0.166666687f, 2.66666675f, 1.66666675f, 2, 0, 2);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops50i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(1, 5, -0.166666687f, 3.66666675f, 1.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(-0.166666687f, 3.66666675f, 1.66666675f, 3, 0, 3);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops51i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(2, 4, 0.833333313f, 2.66666675f, 2.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(0.833333313f, 2.66666675f, 2.66666675f, 2, 1, 2);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops52i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(2, 5, 0.833333313f, 3.66666675f, 2.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 5);
+ pathB.cubicTo(0.833333313f, 3.66666675f, 2.66666675f, 3, 1, 3);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops53i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(3, 5, 1.83333325f, 3.66666675f, 3.66666651f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 5);
+ pathB.cubicTo(1.83333325f, 3.66666675f, 3.66666651f, 3, 2, 3);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops54i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(1, 4, 0, 3, 1.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(0, 3, 1.66666675f, 2, 0, 2);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops55i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(1, 5, 0, 4, 1.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(0, 4, 1.66666675f, 3, 0, 3);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops56i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(2, 4, 0.99999994f, 3, 2.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(0.99999994f, 3, 2.66666675f, 2, 1, 2);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops57i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(2, 5, 0.99999994f, 4, 2.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 5);
+ pathB.cubicTo(0.99999994f, 4, 2.66666675f, 3, 1, 3);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops58i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(3, 5, 2, 4, 3.66666651f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 5);
+ pathB.cubicTo(2, 4, 3.66666651f, 3, 2, 3);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops59i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 6);
+ path.cubicTo(1, 2, 7.33333302f, 1.66666663f, -7.5f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.33333302f, 1.66666663f, -7.5f, 2, 0, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+class PathTest_Private {
+public:
+ PathTest_Private(SkPath* path)
+ : fPath(path) {}
+
+ void setPt(int index, SkScalar x, SkScalar y) {
+ fPath->setPt(index, x, y);
+ }
+
+ SkPath* fPath;
+};
+
+static void path_edit(const SkPoint& from, const SkPoint& to, SkPath* path) {
+ PathTest_Private testPath(path);
+ for (int index = 0; index < path->countPoints(); ++index) {
+ if (SkDPoint::ApproximatelyEqual(path->getPoint(index), from)) {
+ testPath.setPt(index, to.fX, to.fY);
+ return;
+ }
+ }
+}
+
+static void loops59iasQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 6);
+ path.cubicTo(1, 2, 7.33333302f, 1.66666663f, -7.5f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.33333302f, 1.66666663f, -7.5f, 2, 0, 6);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+ SkPoint from = {2.61714339f,1.90228665f};
+ SkPoint to = {2.617045833359139f,1.9013528935803314f};
+ path_edit(from, to, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubics41d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(1, 4, 3, 0, 3, 1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 3);
+ pathB.cubicTo(1, 3, 1, 0, 4, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = cubicOp90u;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = loops59i;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static struct TestDesc tests[] = {
+ TEST(cubics41d),
+ TEST(loops59iasQuads),
+ TEST(loops59i),
+ TEST(loops41i),
+ TEST(loops42i),
+ TEST(loops43i),
+ TEST(loops44i),
+ TEST(loops45i),
+ TEST(loops46i),
+ TEST(loops47i),
+ TEST(loops48i),
+ TEST(loops49i),
+ TEST(loops50i),
+ TEST(loops51i),
+ TEST(loops52i),
+ TEST(loops53i),
+ TEST(loops54i),
+ TEST(loops55i),
+ TEST(loops56i),
+ TEST(loops57i),
+ TEST(loops58i),
+ TEST(loops33iMod),
+ TEST(loops33iAsQuads),
+ TEST(loops33i),
+ TEST(loops40i),
+ TEST(loops40iAsQuads),
+ TEST(loops39i),
+ TEST(loops38i),
+ TEST(loops37i),
+ TEST(loops36i),
+ TEST(loops35i),
+ TEST(loops34i),
+ TEST(loops32i),
+ TEST(loops31i),
+ TEST(loops30i),
+ TEST(loops29i),
+ TEST(loops28i),
+ TEST(loops27i),
+ TEST(loops26i),
+ TEST(loops25i),
+ TEST(loops24i),
+ TEST(loops23i),
+ TEST(loops22i),
+ TEST(loops21i),
+ TEST(loops20i),
+ TEST(cubics20d),
TEST(cubics6d),
TEST(cubics7d),
TEST(cubics8d),
@@ -4773,84 +5509,51 @@ static struct TestDesc tests[] = {
static const size_t testCount = SK_ARRAY_COUNT(tests);
static struct TestDesc subTests[] = {
- TEST(loop16),
- TEST(loop15),
- TEST(loop12),
- TEST(cubicOp132),
- TEST(loop11),
- TEST(loop10),
- TEST(circlesOp3),
- TEST(loop9),
- TEST(loop8),
- TEST(rects5),
- TEST(loop7),
- TEST(cubicOp130a),
- TEST(rRect1x),
- TEST(circlesOp2),
- TEST(circlesOp1),
- TEST(cubicOp131),
- TEST(cubicOp130),
- TEST(cubicOp129),
- TEST(cubicOp128),
- TEST(cubicOp127),
- TEST(cubicOp126),
- TEST(cubicOp125),
- TEST(cubicOp124),
- TEST(loop6),
- TEST(loop5),
- TEST(cubicOp123),
- TEST(cubicOp122),
- TEST(cubicOp121),
- TEST(cubicOp120),
- TEST(cubicOp119),
- TEST(loop4),
- TEST(loop3),
- TEST(loop2),
- TEST(loop1asQuad),
- TEST(loop1),
- TEST(issue3517),
- TEST(cubicOp118),
- TEST(cubicOp117),
- TEST(cubicOp116),
- TEST(testRect2),
- TEST(testRect1),
- TEST(cubicOp115),
- TEST(issue2753),
- TEST(cubicOp114),
- TEST(issue2808),
- TEST(cubicOp114asQuad),
- TEST(rects4),
- TEST(rects3),
- TEST(rects2),
- TEST(rects1),
- TEST(issue2540),
- TEST(issue2504),
- TEST(kari1),
- TEST(quadOp10i),
- TEST(cubicOp113),
- TEST(skpcarrot_is24),
- TEST(issue1417),
- TEST(cubicOp112),
- TEST(skpadspert_net23),
- TEST(skpadspert_de11),
- TEST(findFirst1),
- TEST(xOp2i),
- TEST(xOp3i),
- TEST(xOp1u),
- TEST(xOp1i),
- TEST(cubicOp111),
- TEST(cubicOp110),
- TEST(cubicOp109),
- TEST(cubicOp108),
- TEST(cubicOp107),
- TEST(cubicOp106),
- TEST(cubicOp105),
- TEST(cubicOp104),
- TEST(cubicOp103),
- TEST(cubicOp102),
- TEST(cubicOp101),
- TEST(cubicOp100),
- TEST(cubicOp99),
+ TEST(loops40i),
+ TEST(loops39i),
+ TEST(loops38i),
+ TEST(loops37i),
+ TEST(loops36i),
+ TEST(loops35i),
+ TEST(loops34i),
+ TEST(loops33i),
+ TEST(loops32i),
+ TEST(loops31i),
+ TEST(loops30i),
+ TEST(loops29i),
+ TEST(loops28i),
+ TEST(loops27i),
+ TEST(loops26i),
+ TEST(loops25i),
+ TEST(loops24i),
+ TEST(loops23i),
+ TEST(loops22i),
+ TEST(loops21i),
+ TEST(loops20i),
+ TEST(cubics20d),
+ TEST(cubics6d),
+ TEST(cubics7d),
+ TEST(cubics8d),
+ TEST(cubics9d),
+ TEST(cubics10u),
+ TEST(cubics11i),
+ TEST(cubics12d),
+ TEST(cubics13d),
+ TEST(cubics14d),
+ TEST(cubics15d),
+ TEST(cubics16i),
+ TEST(cubics17d),
+ TEST(cubics18d),
+ TEST(cubics19d),
+ TEST(cubicOp157),
+ TEST(cubicOp142),
+ TEST(loops4i),
+ TEST(quadRect1),
+ TEST(quadRect2),
+ TEST(quadRect3),
+ TEST(quadRect4),
+ TEST(quadRect5),
+ TEST(quadRect6),
};
static const size_t subTestCount = SK_ARRAY_COUNT(subTests);
diff --git a/tests/PathOpsTestCommon.cpp b/tests/PathOpsTestCommon.cpp
index d933115132..f6852254c0 100644
--- a/tests/PathOpsTestCommon.cpp
+++ b/tests/PathOpsTestCommon.cpp
@@ -141,8 +141,20 @@ void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, tru
double tStart = 0;
for (int i1 = 0; i1 <= ts.count(); ++i1) {
const double tEnd = i1 < ts.count() ? ts[i1] : 1;
+ SkDRect bounds;
+ bounds.setBounds(cubic);
SkDCubic part = cubic.subDivide(tStart, tEnd);
SkDQuad quad = part.toQuad();
+ if (quad[1].fX < bounds.fLeft) {
+ quad[1].fX = bounds.fLeft;
+ } else if (quad[1].fX > bounds.fRight) {
+ quad[1].fX = bounds.fRight;
+ }
+ if (quad[1].fY < bounds.fTop) {
+ quad[1].fY = bounds.fTop;
+ } else if (quad[1].fY > bounds.fBottom) {
+ quad[1].fY = bounds.fBottom;
+ }
quads.push_back(quad);
tStart = tEnd;
}
diff --git a/tools/pathops_sorter.htm b/tools/pathops_sorter.htm
index c6ec3d467e..c515fe9b87 100644
--- a/tools/pathops_sorter.htm
+++ b/tools/pathops_sorter.htm
@@ -7,8 +7,8 @@
<div style="height:0">
<div id="sect1">
-{{{2.0185184099245816, 2.3784720550756902}, {1.9467591438442469, 2.1736109238117933}, {1.8796295076608658, 1.9722220152616501}, {1.8148146867752075, 1.7777775526046753}}},
-{{{2.0185184099245816, 2.3784720550756902}, {1.9467591438442469, 2.1736109238117933}, {1.8796295076608658, 1.9722220152616501}, {1.8148146867752075, 1.7777775526046753}}},
+{{{2.18726921f, 2.37414956f}, {2.17974997f, 1.98023772f}, {0.0679920018f, 1.92180145f}}}
+{{{1.58881736f, 3.34967732f}, {2.89432383f, 1.86175978f}, {2.97965813f, 1.76450205f}, {-7.5f, 2}}}
</div>
</div>
diff --git a/tools/pathops_visualizer.htm b/tools/pathops_visualizer.htm
index 5aa1068a0c..f1288f0fe8 100644
--- a/tools/pathops_visualizer.htm
+++ b/tools/pathops_visualizer.htm
@@ -2,300 +2,226 @@
<head>
<div height="0" hidden="true">
-<div id="cubics6d">
-seg=1 {{{3, 5}, {1.8377223f, 5}, {2.36405635f, 3.98683286f}, {3.00889349f, 2.74555302f}}}
-seg=2 {{{3.00889349f, 2.74555302f}, {3.47366595f, 1.85088933f}, {4, 0.837722301f}, {4, 0}}}
-seg=3 {{{4, 0}, {3, 5}}}
-op diff
-seg=4 {{{2, 4}, {1.18350339f, 4}, {1.53367352f, 3.83333325f}, {2.2340138f, 3.5f}}}
-seg=5 {{{2.2340138f, 3.5f}, {3.2491498f, 3.01683664f}, {5, 2.18350339f}, {5, 1}}}
-seg=6 {{{5, 1}, {2, 4}}}
-debugShowCubicIntersection wtTs[0]=1 {{{3,5}, {1.8377223,5}, {2.36405635,3.98683286}, {3.00889349,2.74555302}}} {{3.00889349,2.74555302}} wnTs[0]=0 {{{3.00889349,2.74555302}, {3.47366595,1.85088933}, {4,0.837722301}, {4,0}}}
-debugShowCubicLineIntersection wtTs[0]=0 {{{3,5}, {1.8377223,5}, {2.36405635,3.98683286}, {3.00889349,2.74555302}}} {{3,5}} wnTs[0]=1 {{{4,0}, {3,5}}}
-debugShowCubicLineIntersection wtTs[0]=0.602095725 {{{3.00889349,2.74555302}, {3.47366595,1.85088933}, {4,0.837722301}, {4,0}}} {{3.78703713,1.06481469}} wtTs[1]=1 {{4,0}} wnTs[0]=0.212963 {{{4,0}, {3,5}}} wnTs[1]=0
-SkOpSegment::addT insert t=0.602095725 segID=2 spanID=13
-SkOpSegment::addT insert t=0.212962933 segID=3 spanID=14
-debugShowCubicIntersection wtTs[0]=0.860380171 {{{3,5}, {1.8377223,5}, {2.36405635,3.98683286}, {3.00889349,2.74555302}}} {{2.75000095,3.24999785}} wnTs[0]=0.155051 {{{2.2340138,3.5}, {3.2491498,3.01683664}, {5,2.18350339}, {5,1}}}
-SkOpSegment::addT insert t=0.860380171 segID=1 spanID=15
-SkOpSegment::addT insert t=0.155051471 segID=5 spanID=16
-debugShowCubicLineIntersection wtTs[0]=0.860379476 {{{3,5}, {1.8377223,5}, {2.36405635,3.98683286}, {3.00889349,2.74555302}}} {{2.74999976,3.25000024}} wnTs[0]=0.75 {{{5,1}, {2,4}}}
-SkOpSegment::addT insert t=0.860379476 segID=1 spanID=17
-SkOpSegment::addT insert t=0.750000104 segID=6 spanID=18
-debugShowCubicIntersection no intersect {{{3.00889349,2.74555302}, {3.47366595,1.85088933}, {4,0.837722301}, {4,0}}} {{{2.2340138,3.5}, {3.2491498,3.01683664}, {5,2.18350339}, {5,1}}}
-debugShowCubicLineIntersection no intersect {{{3.00889349,2.74555302}, {3.47366595,1.85088933}, {4,0.837722301}, {4,0}}} {{{5,1}, {2,4}}}
-debugShowCubicLineIntersection wtTs[0]=0.338765871 {{{2.2340138,3.5}, {3.2491498,3.01683664}, {5,2.18350339}, {5,1}}} {{3.42231941,2.88840342}} wnTs[0]=0.577681 {{{4,0}, {3,5}}}
-SkOpSegment::addT insert t=0.57768066 segID=3 spanID=19
-SkOpSegment::addT insert t=0.338765871 segID=5 spanID=20
-debugShowLineIntersection wtTs[0]=0.5 {{{4,0}, {3,5}}} {{3.5,2.5}} wnTs[0]=0.5 {{{5,1}, {2,4}}}
-SkOpSegment::addT insert t=0.5 segID=3 spanID=21
-SkOpSegment::addT insert t=0.5 segID=6 spanID=22
-debugShowCubicIntersection wtTs[0]=1 {{{2,4}, {1.18350339,4}, {1.53367352,3.83333325}, {2.2340138,3.5}}} {{2.2340138,3.5}} wnTs[0]=0 {{{2.2340138,3.5}, {3.2491498,3.01683664}, {5,2.18350339}, {5,1}}}
-debugShowCubicLineIntersection wtTs[0]=0 {{{2,4}, {1.18350339,4}, {1.53367352,3.83333325}, {2.2340138,3.5}}} {{2,4}} wnTs[0]=1 {{{5,1}, {2,4}}}
-debugShowCubicLineIntersection wtTs[0]=0.155050964 {{{2.2340138,3.5}, {3.2491498,3.01683664}, {5,2.18350339}, {5,1}}} {{2.75,3.25}} wtTs[1]=1 {{5,1}} wnTs[0]=0.75 {{{5,1}, {2,4}}} wnTs[1]=0
-SkOpSegment::addT insert t=0.155050964 segID=5 spanID=23
-SkOpSegment::addT alias t=0.750000024 segID=6 spanID=18
-SkOpSegment::sortAngles [1] tStart=0.860379476 [17]
-SkOpAngle::after [1/1] 21/25 tStart=0.860379476 tEnd=0 < [6/21] 3/3 tStart=0.750000104 tEnd=0.5 < [1/2] 3/3 tStart=0.860379476 tEnd=0.860380171 T 11
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.24999996,4.25000007}, {2.00000012,5}, {3,5}}} id=1
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {3.5,2.5}}} id=6
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000017,3.24999943}, {2.75000055,3.24999866}, {2.75000095,3.24999785}}} id=1
-SkOpAngle::after [1/1] 21/25 tStart=0.860379476 tEnd=0 < [6/22] 19/19 tStart=0.750000104 tEnd=1 < [6/21] 3/3 tStart=0.750000104 tEnd=0.5 F 4
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.24999996,4.25000007}, {2.00000012,5}, {3,5}}} id=1
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2,4}}} id=6
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {3.5,2.5}}} id=6
-SkOpAngle::after [6/21] 3/3 tStart=0.750000104 tEnd=0.5 < [6/22] 19/19 tStart=0.750000104 tEnd=1 < [1/2] 3/3 tStart=0.860379476 tEnd=0.860380171 F 5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {3.5,2.5}}} id=6
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2,4}}} id=6
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000017,3.24999943}, {2.75000055,3.24999866}, {2.75000095,3.24999785}}} id=1
-SkOpAngle::after [1/2] 3/3 tStart=0.860379476 tEnd=0.860380171 < [6/22] 19/19 tStart=0.750000104 tEnd=1 < [1/1] 21/25 tStart=0.860379476 tEnd=0 T 4
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000017,3.24999943}, {2.75000055,3.24999866}, {2.75000095,3.24999785}}} id=1
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2,4}}} id=6
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.24999996,4.25000007}, {2.00000012,5}, {3,5}}} id=1
-SkOpAngle::after [1/1] 21/25 tStart=0.860379476 tEnd=0 < [5/13] 17/17 tStart=0.155050964 tEnd=0 < [6/21] 3/3 tStart=0.750000104 tEnd=0.5 F 4
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.24999996,4.25000007}, {2.00000012,5}, {3,5}}} id=1
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.56649642,3.34175191}, {2.39141161,3.42508506}, {2.2340138,3.5}}} id=5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {3.5,2.5}}} id=6
-SkOpAngle::after [6/21] 3/3 tStart=0.750000104 tEnd=0.5 < [5/13] 17/17 tStart=0.155050964 tEnd=0 < [1/2] 3/3 tStart=0.860379476 tEnd=0.860380171 F 5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {3.5,2.5}}} id=6
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.56649642,3.34175191}, {2.39141161,3.42508506}, {2.2340138,3.5}}} id=5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000017,3.24999943}, {2.75000055,3.24999866}, {2.75000095,3.24999785}}} id=1
-SkOpAngle::after [1/2] 3/3 tStart=0.860379476 tEnd=0.860380171 < [5/13] 17/17 tStart=0.155050964 tEnd=0 < [6/22] 19/19 tStart=0.750000104 tEnd=1 T 4
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000017,3.24999943}, {2.75000055,3.24999866}, {2.75000095,3.24999785}}} id=1
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.56649642,3.34175191}, {2.39141161,3.42508506}, {2.2340138,3.5}}} id=5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2,4}}} id=6
-SkOpAngle::after [1/1] 21/25 tStart=0.860379476 tEnd=0 < [5/14] 17/17 tStart=0.155050964 tEnd=0.155051471 < [6/21] 3/3 tStart=0.750000104 tEnd=0.5 F 4
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.24999996,4.25000007}, {2.00000012,5}, {3,5}}} id=1
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000036,3.25000024}, {2.75000035,3.24999785}, {2.75000095,3.24999785}}} id=5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {3.5,2.5}}} id=6
-SkOpAngle::after [6/21] 3/3 tStart=0.750000104 tEnd=0.5 < [5/14] 17/17 tStart=0.155050964 tEnd=0.155051471 < [1/2] 3/3 tStart=0.860379476 tEnd=0.860380171 F 5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {3.5,2.5}}} id=6
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.56649642,3.34175191}, {2.39141161,3.42508506}, {2.2340138,3.5}}} id=5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000017,3.24999943}, {2.75000055,3.24999866}, {2.75000095,3.24999785}}} id=1
-SkOpAngle::after [1/2] 3/3 tStart=0.860379476 tEnd=0.860380171 < [5/14] 17/17 tStart=0.155050964 tEnd=0.155051471 < [5/13] 17/17 tStart=0.155050964 tEnd=0 T 11
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.75000017,3.24999943}, {2.75000055,3.24999866}, {2.75000095,3.24999785}}} id=1
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.56649642,3.34175191}, {2.39141161,3.42508506}, {2.2340138,3.5}}} id=5
-SkOpAngle::afterPart {{{2.74999976,3.25000024}, {2.56649642,3.34175191}, {2.39141161,3.42508506}, {2.2340138,3.5}}} id=5
-SkOpSegment::sortAngles [1] tStart=0.860380171 [15]
-SkOpAngle::after [1/3] 19/19 tStart=0.860380171 tEnd=0.860379476 < [5/15] 1/2 tStart=0.155051471 tEnd=0.155050964 < [1/4] 5/5 tStart=0.860380171 tEnd=1 T 4
-SkOpAngle::afterPart {{{2.75000095,3.24999785}, {2.75000055,3.24999866}, {2.75000017,3.24999943}, {2.74999976,3.25000024}}} id=1
-SkOpAngle::afterPart {{{2.75000095,3.24999785}, {2.75000035,3.24999785}, {2.75000036,3.25000024}, {2.74999976,3.25000024}}} id=5
-SkOpAngle::afterPart {{{2.75000095,3.24999785}, {2.8311395,3.08772078}, {2.91886144,2.9188603}, {3.00889349,2.74555302}}} id=1
-SkOpAngle::after [1/3] 19/19 tStart=0.860380171 tEnd=0.860379476 < [5/16] 1/1 tStart=0.155051471 tEnd=0.338765871 < [5/15] 1/2 tStart=0.155051471 tEnd=0.155050964 T 11
-SkOpAngle::afterPart {{{2.75000095,3.24999785}, {2.75000055,3.24999866}, {2.75000017,3.24999943}, {2.74999976,3.25000024}}} id=1
-SkOpAngle::afterPart {{{2.75000095,3.24999785}, {2.96742763,3.14128448}, {3.1966737,3.02075395}, {3.42231941,2.88840342}}} id=5
-SkOpAngle::afterPart {{{2.75000095,3.24999785}, {3.75000071,2.74999781}, {5,1.99999945}, {5,1}}} id=5
-SkOpSegment::sortAngles [2] tStart=0.602095725 [13]
-SkOpAngle::after [2/5] 21/21 tStart=0.602095725 tEnd=0 < [3/7] 5/5 tStart=0.212962933 tEnd=0 < [2/6] 5/5 tStart=0.602095725 tEnd=1 F 11
-SkOpAngle::afterPart {{{3.78703713,1.06481469}, {3.59088584,1.62524693}, {3.288731,2.20687983}, {3.00889349,2.74555302}}} id=2
-SkOpAngle::afterPart {{{3.78703713,1.06481469}, {4,0}}} id=3
-SkOpAngle::afterPart {{{3.78703713,1.06481469}, {3.91666675,0.694444369}, {4,0.333333285}, {4,0}}} id=2
-SkOpAngle::after [2/5] 21/21 tStart=0.602095725 tEnd=0 < [3/8] 21/21 tStart=0.212962933 tEnd=0.5 < [2/6] 5/5 tStart=0.602095725 tEnd=1 T 12
-SkOpAngle::afterPart {{{3.78703713,1.06481469}, {3.59088584,1.62524693}, {3.288731,2.20687983}, {3.00889349,2.74555302}}} id=2
-SkOpAngle::afterPart {{{3.78703713,1.06481469}, {3.5,2.5}}} id=3
-SkOpAngle::afterPart {{{3.78703713,1.06481469}, {3.91666675,0.694444369}, {4,0.333333285}, {4,0}}} id=2
-SkOpSegment::sortAngles [3] tStart=0.212962933 [14]
-SkOpSegment::sortAngles [3] tStart=0.5 [21]
-SkOpAngle::after [3/9] 5/5 tStart=0.5 tEnd=0.212962933 < [6/19] 3/3 tStart=0.5 tEnd=0 < [3/10] 21/21 tStart=0.5 tEnd=0.57768066 F 4
-SkOpAngle::afterPart {{{3.5,2.5}, {3.78703713,1.06481469}}} id=3
-SkOpAngle::afterPart {{{3.5,2.5}, {5,1}}} id=6
-SkOpAngle::afterPart {{{3.5,2.5}, {3.42231941,2.88840342}}} id=3
-SkOpAngle::after [3/9] 5/5 tStart=0.5 tEnd=0.212962933 < [6/20] 19/19 tStart=0.5 tEnd=0.750000104 < [3/10] 21/21 tStart=0.5 tEnd=0.57768066 T 4
-SkOpAngle::afterPart {{{3.5,2.5}, {3.78703713,1.06481469}}} id=3
-SkOpAngle::afterPart {{{3.5,2.5}, {2.74999976,3.25000024}}} id=6
-SkOpAngle::afterPart {{{3.5,2.5}, {3.42231941,2.88840342}}} id=3
-SkOpSegment::sortAngles [3] tStart=0.57768066 [19]
-SkOpAngle::after [3/11] 5/5 tStart=0.57768066 tEnd=0.5 < [5/17] 17/17 tStart=0.338765871 tEnd=0.155051471 < [3/12] 21/21 tStart=0.57768066 tEnd=1 T 4
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3.5,2.5}}} id=3
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3.1966737,3.02075395}, {2.96742763,3.14128448}, {2.75000095,3.24999785}}} id=5
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3,5}}} id=3
-SkOpAngle::after [3/11] 5/5 tStart=0.57768066 tEnd=0.5 < [5/18] 1/5 tStart=0.338765871 tEnd=1 < [5/17] 17/17 tStart=0.338765871 tEnd=0.155051471 F 12
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3.5,2.5}}} id=3
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {4.23447483,2.41204069}, {5,1.78257283}, {5,1}}} id=5
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3.1966737,3.02075395}, {2.96742763,3.14128448}, {2.75000095,3.24999785}}} id=5
-SkOpAngle::after [5/17] 17/17 tStart=0.338765871 tEnd=0.155051471 < [5/18] 1/5 tStart=0.338765871 tEnd=1 < [3/12] 21/21 tStart=0.57768066 tEnd=1 F 4
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3.1966737,3.02075395}, {2.96742763,3.14128448}, {2.75000095,3.24999785}}} id=5
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {4.23447483,2.41204069}, {5,1.78257283}, {5,1}}} id=5
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3,5}}} id=3
-SkOpAngle::after [3/12] 21/21 tStart=0.57768066 tEnd=1 < [5/18] 1/5 tStart=0.338765871 tEnd=1 < [3/11] 5/5 tStart=0.57768066 tEnd=0.5 T 11
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3,5}}} id=3
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {4.23447483,2.41204069}, {5,1.78257283}, {5,1}}} id=5
-SkOpAngle::afterPart {{{3.42231941,2.88840342}, {3.5,2.5}}} id=3
-SkOpSegment::sortAngles [5] tStart=0.155050964 [23]
-SkOpSegment::sortAngles [5] tStart=0.155051471 [16]
-SkOpSegment::sortAngles [5] tStart=0.338765871 [20]
-SkOpSegment::sortAngles [6] tStart=0.5 [22]
-SkOpSegment::sortAngles [6] tStart=0.750000104 [18]
-SkOpSegment::debugShowActiveSpans id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0 (3,5) tEnd=0.860379476 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0.860379476 (2.74999976,3.25000024) tEnd=0.860380171 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0.860380171 (2.75000095,3.24999785) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (3.00889349,2.74555302 3.47366595,1.85088933 4,0.837722301 4,0) t=0 (3.00889349,2.74555302) tEnd=0.602095725 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (3.00889349,2.74555302 3.47366595,1.85088933 4,0.837722301 4,0) t=0.602095725 (3.78703713,1.06481469) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0 (4,0) tEnd=0.212962933 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.212962933 (3.78703713,1.06481469) tEnd=0.5 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.5 (3.5,2.5) tEnd=0.57768066 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.57768066 (3.42231941,2.88840342) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=4 (2,4 1.18350339,4 1.53367352,3.83333325 2.2340138,3.5) t=0 (2,4) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0 (2.2340138,3.5) tEnd=0.155050964 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155050964 (2.74999976,3.25000024) tEnd=0.155051471 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 (2.75000095,3.24999785) tEnd=0.338765871 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.338765871 (3.42231941,2.88840342) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0 (5,1) tEnd=0.5 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0.5 (3.5,2.5) tEnd=0.750000104 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0.750000104 (2.74999976,3.25000024) tEnd=1 windSum=? windValue=1 oppValue=0
+<div id="loops59i">
+SkDCubic::ComplexBreak
+{{{1, 2}, {7.3333330154418945, 1.6666666269302368}, {-7.5, 2}, {0, 6}}},
+inflectionsTs[0]=0.22755391 {{{5.6899562470344014, 1.5351137489099846}, {-0.59395324579271769, 2.2875990427916371}}},
+inflectionsTs[1]=0.134608255 {{{-1.7562572007939035, 2.2074401507711405}, {6.7824037520473279, 1.6104549548102116}}},
+maxCurvature[0]=0.184583395 {{{2.612965320628251, 1.8574526830515183}, {2.6213210132912339, 1.9473982945574213}}},
+maxCurvature[1]=0.764880287 {{{-0.3599143419711428, -3.5772335093952985}, {-3.9435828934112642, 11.072562225478482}}},
+maxCurvature[2]=0.500240448 {{{11.93379531543474, -0.87734455447864557}, {-11.814505983496176, 5.6289081865421942}}},
+seg=1 {{{0, 6}, {0.293506175f, 4.82597542f}, {1.04645705f, 3.96781874f}, {1.58881736f, 3.34967732f}}}
+seg=2 {{{1.58881736f, 3.34967732f}, {2.89432383f, 1.86175978f}, {2.97965813f, 1.76450205f}, {-7.5f, 2}}}
+seg=3 {{{-7.5f, 2}, {0, 6}}}
+op sect
+seg=4 {{{1, 2}, {2.16902828f, 1.93847215f}, {2.61688614f, 1.89965844f}, {2.61714315f, 1.90242553f}}}
+seg=5 {{{2.61714315f, 1.90242553f}, {2.61827874f, 1.91464937f}, {-6.11562443f, 2.7383337f}, {0, 6}}}
+seg=6 {{{0, 6}, {1, 2}}}
+debugShowCubicIntersection wtTs[0]=1 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{1.58881736,3.34967732}} wnTs[0]=0 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=1 {{{-7.5,2}, {0,6}}}
+debugShowCubicLineIntersection wtTs[0]=1 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{-7.5,2}} wnTs[0]=0 {{{-7.5,2}, {0,6}}}
+debugShowCubicIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=1 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=0 {{{0,6}, {1,2}}}
+debugShowCubicIntersection wtTs[0]=0.538493706 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{1.17718506,1.99055469}} wnTs[0]=0.0521913 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}}
+SkOpSegment::addT insert t=0.538493706 segID=2 spanID=13
+SkOpSegment::addT insert t=0.0521913275 segID=4 spanID=14
+debugShowCubicIntersection wtTs[0]=0.481912781 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{1.58025348,2.04903817}} wnTs[0]=0.222514 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
+SkOpSegment::addT insert t=0.481912781 segID=2 spanID=15
+SkOpSegment::addT insert t=0.222514468 segID=5 spanID=16
+debugShowCubicLineIntersection no intersect {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{{0,6}, {1,2}}}
+debugShowCubicLineIntersection wtTs[0]=1 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}} {{0,6}} wnTs[0]=1 {{{-7.5,2}, {0,6}}}
+debugShowLineIntersection wtTs[0]=1 {{{-7.5,2}, {0,6}}} {{0,6}} wnTs[0]=0 {{{0,6}, {1,2}}}
+debugShowCubicIntersection wtTs[0]=1 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}} {{2.61714315,1.90242553}} wnTs[0]=0 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}} {{1,2}} wnTs[0]=1 {{{0,6}, {1,2}}}
+debugShowCubicLineIntersection wtTs[0]=0.293280033 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}} {{0.959100008,2.16359997}} wtTs[1]=1 {{0,6}} wnTs[0]=0.9591 {{{0,6}, {1,2}}} wnTs[1]=0
+SkOpSegment::addT insert t=0.293280033 segID=5 spanID=17
+SkOpSegment::addT insert t=0.959100004 segID=6 spanID=18
+SkOpSegment::sortAngles [1] tStart=0 [1]
+SkOpAngle::after [1/1] 5/5 tStart=0 tEnd=1 < [5/13] 13/5 tStart=1 tEnd=0.293280033 < [6/14] 5/5 tStart=0 tEnd=0.959100004 F 7
+SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
+SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
+SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
+SkOpAngle::after [1/1] 5/5 tStart=0 tEnd=1 < [3/6] 13/13 tStart=1 tEnd=0 < [6/14] 5/5 tStart=0 tEnd=0.959100004 F 5
+SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
+SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
+SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
+SkOpAngle::after [6/14] 5/5 tStart=0 tEnd=0.959100004 < [3/6] 13/13 tStart=1 tEnd=0 < [5/13] 13/5 tStart=1 tEnd=0.293280033 F 7
+SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
+SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
+SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
+SkOpAngle::after [5/13] 13/5 tStart=1 tEnd=0.293280033 < [3/6] 13/13 tStart=1 tEnd=0 < [1/1] 5/5 tStart=0 tEnd=1 T 7
+SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
+SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
+SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
+SkOpSegment::sortAngles [2] tStart=0.481912781 [15]
+SkOpAngle::after [2/2] 29/25 tStart=0.481912781 tEnd=0 < [5/9] 1/1 tStart=0.222514468 tEnd=0 < [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 T 4
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
+SkOpAngle::after [2/2] 29/25 tStart=0.481912781 tEnd=0 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [5/9] 1/1 tStart=0.222514468 tEnd=0 F 4
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
+SkOpAngle::after [5/9] 1/1 tStart=0.222514468 tEnd=0 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 F 4
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
+SkOpAngle::after [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [2/2] 29/25 tStart=0.481912781 tEnd=0 T 4
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
+SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
+SkOpSegment::sortAngles [2] tStart=0.538493706 [13]
+SkOpAngle::after [2/4] 29/29 tStart=0.538493706 tEnd=0.481912781 < [4/7] 17/17 tStart=0.0521913275 tEnd=0 < [2/5] 13/17 tStart=0.538493706 tEnd=1 F 11
+SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.33099307,2.007357}, {1.464785,2.02678763}, {1.58025348,2.04903817}}} id=2
+SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.12006187,1.99363948}, {1.06101314,1.99678878}, {1,2}}} id=4
+SkOpAngle::afterPart {{{1.17718506,1.99055469}, {-0.0773608463,1.85350547}, {-2.66357181,1.89131621}, {-7.5,2}}} id=2
+SkOpAngle::after [2/4] 29/29 tStart=0.538493706 tEnd=0.481912781 < [4/8] 1/1 tStart=0.0521913275 tEnd=1 < [2/5] 13/17 tStart=0.538493706 tEnd=1 T 4
+SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.33099307,2.007357}, {1.464785,2.02678763}, {1.58025348,2.04903817}}} id=2
+SkOpAngle::afterPart {{{1.17718506,1.99055469}, {2.21455765,1.93453399}, {2.61689955,1.89980286}, {2.61714315,1.90242553}}} id=4
+SkOpAngle::afterPart {{{1.17718506,1.99055469}, {-0.0773608463,1.85350547}, {-2.66357181,1.89131621}, {-7.5,2}}} id=2
+SkOpSegment::sortAngles [3] tStart=1 [6]
+SkOpSegment::sortAngles [4] tStart=0.0521913275 [14]
+SkOpSegment::sortAngles [5] tStart=0.222514468 [16]
+SkOpSegment::sortAngles [5] tStart=0.293280033 [17]
+SkOpAngle::after [5/11] 1/1 tStart=0.293280033 tEnd=0.222514468 < [6/15] 21/21 tStart=0.959100004 tEnd=0 < [5/12] 17/21 tStart=0.293280033 tEnd=1 F 11
+SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1.178042,2.11915237}, {1.38787913,2.0811573}, {1.58025348,2.04903817}}} id=5
+SkOpAngle::afterPart {{{0.959100008,2.16359997}, {0,6}}} id=6
+SkOpAngle::afterPart {{{0.959100008,2.16359997}, {-1.22742501,2.60748826}, {-4.3220339,3.6949153}, {0,6}}} id=5
+SkOpAngle::after [5/11] 1/1 tStart=0.293280033 tEnd=0.222514468 < [6/16] 5/5 tStart=0.959100004 tEnd=1 < [5/12] 17/21 tStart=0.293280033 tEnd=1 T 4
+SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1.178042,2.11915237}, {1.38787913,2.0811573}, {1.58025348,2.04903817}}} id=5
+SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1,2}}} id=6
+SkOpAngle::afterPart {{{0.959100008,2.16359997}, {-1.22742501,2.60748826}, {-4.3220339,3.6949153}, {0,6}}} id=5
+SkOpSegment::sortAngles [5] tStart=1 [10]
+SkOpSegment::sortAngles [6] tStart=0 [11]
+SkOpSegment::sortAngles [6] tStart=0.959100004 [18]
+SkOpSegment::debugShowActiveSpans id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 (0,6) tEnd=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 (1.58881736,3.34967732) tEnd=0.481912781 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 (1.58025348,2.04903817) tEnd=0.538493706 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 (1.17718506,1.99055469) tEnd=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (-7.5,2 0,6) t=0 (-7.5,2) tEnd=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 (1,2) tEnd=0.0521913275 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 (1.17718506,1.99055469) tEnd=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 (2.61714315,1.90242553) tEnd=0.222514468 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 (1.58025348,2.04903817) tEnd=0.293280033 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0 (0,6) tEnd=0.959100004 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0.959100004 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::findTop- baseAngle
-SkOpAngle::dumpOne [3/23] next=2/24 sect=21/21 s=0 [5] e=0.212962933 [14] sgn=-1 windVal=1 windSum=?
-SkOpAngle::dumpOne [2/24] next=3/23 sect=22/21 s=1 [4] e=0.602095725 [13] sgn=1 windVal=1 windSum=?
+SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=? operand
+SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=? stop
+SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=? operand
+SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=? stop
-SkOpSegment::findTop- firstAngle
-SkOpAngle::dumpOne [3/23] next=2/24 sect=21/21 s=0 [5] e=0.212962933 [14] sgn=-1 windVal=1 windSum=?
-SkOpAngle::dumpOne [2/24] next=3/23 sect=22/21 s=1 [4] e=0.602095725 [13] sgn=1 windVal=1 windSum=?
-SkOpSegment::findTop id=3 s=0.212962933 e=0 (+) cw=-1 swap=-1 inflections=-1 monotonic=1
-SkOpSegment::markWinding id=3 (4,0 3,5) t=0 [5] (4,0) tEnd=0.212962933 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::nextChase mismatched signs
-SkOpSegment::markWinding id=2 (3.00889349,2.74555302 3.47366595,1.85088933 4,0.837722301 4,0) t=0.602095725 [13] (3.78703713,1.06481469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=3 (4,0 3,5) t=0 [5] (4,0) tEnd=0.212962933 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-SkOpSegment::activeOp id=3 t=0.212962933 tEnd=0 op=diff miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
-SkOpSegment::nextChase mismatched signs
+SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=? operand
+SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=? stop
+SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=? operand
+SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=? stop
+SkDCubic::clockwise pt1dist=0.00263265113 pt2dist=-0.00745519926
+SkOpSegment::findTop id=4 s=1 e=0.0521913275 (+) cw=1 swap=0 inflections=1 monotonic=0
+SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 [9] (2.61714315,1.90242553) tEnd=0.222514468 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::activeOp id=4 t=1 tEnd=0.0521913275 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
+SkOpSegment::markDone id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp chase.append id=4 windSum=1
+SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 [13] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=3 (-7.5,2 0,6) t=0 [5] (-7.5,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=3 span=6
+SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 [7] (1,2) tEnd=0.0521913275 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=6 (0,6 1,2) t=0.959100004 [18] (0.959100008,2.16359997) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=6 span=18 windSum=1
+SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 [15] (1.58025348,2.04903817) tEnd=0.538493706 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=2 span=15 windSum=1
+SkOpSegment::debugShowActiveSpans id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 (0,6) tEnd=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 (1.58881736,3.34967732) tEnd=0.481912781 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 (1.58025348,2.04903817) tEnd=0.538493706 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 (1.17718506,1.99055469) tEnd=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (-7.5,2 0,6) t=0 (-7.5,2) tEnd=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 (1,2) tEnd=0.0521913275 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 (2.61714315,1.90242553) tEnd=0.222514468 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 (1.58025348,2.04903817) tEnd=0.293280033 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0 (0,6) tEnd=0.959100004 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0.959100004 (0.959100008,2.16359997) tEnd=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=2 t=0.538493706 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
SkOpSegment::findNextOp simple
-SkOpSegment::markDone id=3 (4,0 3,5) t=0 [5] (4,0) tEnd=0.212962933 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-bridgeOp current id=3 from=(3.78703713,1.06481469) to=(4,0)
-SkOpSegment::markWinding id=2 (3.00889349,2.74555302 3.47366595,1.85088933 4,0.837722301 4,0) t=0 [3] (3.00889349,2.74555302) tEnd=0.602095725 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0.860380171 [15] (2.75000095,3.24999785) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=1 span=15 windSum=-1
-SkOpSegment::markWinding id=3 (4,0 3,5) t=0.212962933 [14] (3.78703713,1.06481469) tEnd=0.5 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=3 span=21 windSum=?
+SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 [13] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=2 from=(1.17718506,1.99055469) to=(-7.5,2)
+path.moveTo(1.17718506,1.99055469);
+path.cubicTo(-0.0773608461,1.85350549, -2.66357183,1.89131618, -7.5,2);
+SkOpSegment::markWinding id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 [1] (0,6) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 [3] (1.58881736,3.34967732) tEnd=0.481912781 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=2 span=15 windSum=1
+SkOpSegment::markWinding id=6 (0,6 1,2) t=0 [11] (0,6) tEnd=0.959100004 newWindSum=2 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=6 span=18 windSum=1
+SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 [17] (0.959100008,2.16359997) tEnd=1 newWindSum=2 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=5 span=17 windSum=2
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [2/6] next=3/7 sect=5/5 s=0.602095725 [13] e=1 [4] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
-SkOpAngle::dumpOne [3/7] next=2/5 sect=5/5 s=0.212962933 [14] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done
-SkOpAngle::dumpOne [2/5] next=3/8 sect=21/21 s=0.602095725 [13] e=0 [3] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0
-SkOpAngle::dumpOne [3/8] next=2/6 sect=21/21 s=0.212962933 [14] e=0.5 [21] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
-SkOpSegment::activeOp id=3 t=0.212962933 tEnd=0 op=diff miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
-SkOpSegment::activeOp id=2 t=0.602095725 tEnd=0 op=diff miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
-SkOpSegment::findNextOp chase.append segment=1 span=15 windSum=-1
-SkOpSegment::activeOp id=3 t=0.212962933 tEnd=0.5 op=diff miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
-SkOpSegment::findNextOp chase.append segment=3 span=21 windSum=-2147483647
-SkOpSegment::markDone id=2 (3.00889349,2.74555302 3.47366595,1.85088933 4,0.837722301 4,0) t=0.602095725 [13] (3.78703713,1.06481469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[2] to:[3] start=4807220 end=4807892
-bridgeOp current id=2 from=(4,0) to=(3.78703713,1.06481469)
-path.moveTo(3.78703713,1.06481469);
-path.lineTo(4,0);
-path.cubicTo(4,0.333333284, 3.91666675,0.694444358, 3.78703713,1.06481469);
-path.close();
-SkOpSegment::debugShowActiveSpans id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0 (3,5) tEnd=0.860379476 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0.860379476 (2.74999976,3.25000024) tEnd=0.860380171 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0.860380171 (2.75000095,3.24999785) tEnd=1 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (3.00889349,2.74555302 3.47366595,1.85088933 4,0.837722301 4,0) t=0 (3.00889349,2.74555302) tEnd=0.602095725 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.212962933 (3.78703713,1.06481469) tEnd=0.5 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.5 (3.5,2.5) tEnd=0.57768066 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.57768066 (3.42231941,2.88840342) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=4 (2,4 1.18350339,4 1.53367352,3.83333325 2.2340138,3.5) t=0 (2,4) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0 (2.2340138,3.5) tEnd=0.155050964 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155050964 (2.74999976,3.25000024) tEnd=0.155051471 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 (2.75000095,3.24999785) tEnd=0.338765871 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.338765871 (3.42231941,2.88840342) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0 (5,1) tEnd=0.5 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0.5 (3.5,2.5) tEnd=0.750000104 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0.750000104 (2.74999976,3.25000024) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::activeOp id=3 t=0.5 tEnd=0.212962933 op=diff miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
-SkOpSegment::findNextOp
-SkOpAngle::dumpOne [3/8] next=2/6 sect=21/21 s=0.212962933 [14] e=0.5 [21] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
-SkOpAngle::dumpOne [2/6] next=3/7 sect=5/5 s=0.602095725 [13] e=1 [4] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done
-SkOpAngle::dumpOne [3/7] next=2/5 sect=5/5 s=0.212962933 [14] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done
-SkOpAngle::dumpOne [2/5] next=3/8 sect=21/21 s=0.602095725 [13] e=0 [3] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0
-SkOpSegment::activeOp id=2 t=0.602095725 tEnd=1 op=diff miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
-SkOpSegment::activeOp id=3 t=0.212962933 tEnd=0 op=diff miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
-SkOpSegment::activeOp id=2 t=0.602095725 tEnd=0 op=diff miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
-SkOpSegment::markDone id=3 (4,0 3,5) t=0.212962933 [14] (3.78703713,1.06481469) tEnd=0.5 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[3] to:[2] start=4807124 end=4805876
-bridgeOp current id=3 from=(3.5,2.5) to=(3.78703713,1.06481469)
+SkOpAngle::dumpOne [3/6] next=1/1 sect=13/13 s=1 [6] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1
+SkOpAngle::dumpOne [1/1] next=6/14 sect=5/5 s=0 [1] e=1 [2] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1
+SkOpAngle::dumpOne [6/14] next=5/13 sect=5/5 s=0 [11] e=0.959100004 [18] sgn=-1 windVal=1 windSum=2 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [5/13] next=3/6 sect=13/5 s=1 [10] e=0.293280033 [17] sgn=1 windVal=1 windSum=2 oppVal=0 oppSum=1 operand
+SkOpSegment::activeOp id=1 t=0 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
+SkOpSegment::findNextOp chase.append segment=2 span=15 windSum=1
+SkOpSegment::activeOp id=6 t=0 tEnd=0.959100004 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=6 (0,6 1,2) t=0 [11] (0,6) tEnd=0.959100004 newWindSum=2 newOppSum=1 oppSum=1 windSum=2 windValue=1 oppValue=0
+SkOpSegment::findNextOp chase.append segment=6 span=18 windSum=1
+SkOpSegment::activeOp id=5 t=1 tEnd=0.293280033 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 [17] (0.959100008,2.16359997) tEnd=1 newWindSum=2 newOppSum=1 oppSum=1 windSum=2 windValue=1 oppValue=0
+SkOpSegment::findNextOp chase.append segment=5 span=17 windSum=2
+SkOpSegment::markDone id=3 (-7.5,2 0,6) t=0 [5] (-7.5,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[3] to:[1] start=43971536 end=43971632
+bridgeOp current id=3 from=(-7.5,2) to=(0,6)
SkOpSegment::findNextOp simple
-SkOpSegment::markDone id=2 (3.00889349,2.74555302 3.47366595,1.85088933 4,0.837722301 4,0) t=0 [3] (3.00889349,2.74555302) tEnd=0.602095725 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
-bridgeOp current id=2 from=(3.78703713,1.06481469) to=(3.00889349,2.74555302)
-path.moveTo(3.5,2.5);
-path.lineTo(3.78703713,1.06481469);
-path.cubicTo(3.59088588,1.62524688, 3.2887311,2.20687985, 3.00889349,2.74555302);
+SkOpSegment::markDone id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 [1] (0,6) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=1 from=(0,6) to=(1.58881736,3.34967732)
+path.lineTo(0,6);
+path.cubicTo(0.293506175,4.82597542, 1.04645705,3.96781874, 1.58881736,3.34967732);
+SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 [16] (1.58025348,2.04903817) tEnd=0.293280033 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=5 span=17 windSum=2
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [1/4] next=1/3 sect=5/5 s=0.860380171 [15] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
-SkOpAngle::dumpOne [1/3] next=5/16 sect=19/19 s=0.860380171 [15] e=0.860379476 [17] sgn=1 windVal=1 windSum=?
-SkOpAngle::dumpOne [5/16] next=5/15 sect=1/1 s=0.155051471 [16] e=0.338765871 [20] sgn=-1 windVal=1 windSum=? unorderable operand
-SkOpAngle::dumpOne [5/15] next=1/4 sect=1/2 s=0.155051471 [16] e=0.155050964 [23] sgn=1 windVal=1 windSum=? unorderable operand
-SkOpSegment::activeOp id=1 t=0.860380171 tEnd=0.860379476 op=diff miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
-SkOpSegment::activeOp id=5 t=0.155051471 tEnd=0.338765871 op=diff miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
-SkOpSegment::activeOp id=5 t=0.155051471 tEnd=0.155050964 op=diff miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
-SkOpSegment::markDone id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0.860380171 [15] (2.75000095,3.24999785) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[1] to:[1] start=4807316 end=4807508
-bridgeOp current id=1 from=(3.00889349,2.74555302) to=(2.75000095,3.24999785)
-path.cubicTo(2.91886139,2.9188602, 2.83113956,3.08772087, 2.75000095,3.24999785);
+SkOpAngle::dumpOne [2/2] next=5/9 sect=29/25 s=0.481912781 [15] e=0 [3] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1
+SkOpAngle::dumpOne [5/9] next=2/3 sect=1/1 s=0.222514468 [16] e=0 [9] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
+SkOpAngle::dumpOne [2/3] next=5/10 sect=13/13 s=0.481912781 [15] e=0.538493706 [13] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [5/10] next=2/2 sect=17/17 s=0.222514468 [16] e=0.293280033 [17] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
+SkOpSegment::activeOp id=5 t=0.222514468 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
+SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 [9] (2.61714315,1.90242553) tEnd=0.222514468 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=2 t=0.481912781 tEnd=0.538493706 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0
+SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 [15] (1.58025348,2.04903817) tEnd=0.538493706 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=5 t=0.222514468 tEnd=0.293280033 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
+SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 [3] (1.58881736,3.34967732) tEnd=0.481912781 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[2] to:[5] start=2579180 end=2579276
+bridgeOp current id=2 from=(1.58881736,3.34967732) to=(1.58025348,2.04903817)
+path.cubicTo(2.2179575,2.63263083, 2.56372523,2.23855114, 1.58025348,2.04903817);
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [1/2] next=5/14 sect=3/3 s=0.860379476 [17] e=0.860380171 [15] sgn=-1 windVal=1 windSum=?
-SkOpAngle::dumpOne [5/14] next=5/13 sect=17/17 s=0.155050964 [23] e=0.155051471 [16] sgn=-1 windVal=1 windSum=? unorderable operand
-SkOpAngle::dumpOne [5/13] next=6/22 sect=17/17 s=0.155050964 [23] e=0 [9] sgn=1 windVal=1 windSum=? unorderable operand
-SkOpAngle::dumpOne [6/22] next=1/1 sect=19/19 s=0.750000104 [18] e=1 [12] sgn=-1 windVal=1 windSum=? operand
-SkOpAngle::dumpOne [1/1] next=6/21 sect=21/25 s=0.860379476 [17] e=0 [1] sgn=1 windVal=1 windSum=?
-SkOpAngle::dumpOne [6/21] next=1/2 sect=3/3 s=0.750000104 [18] e=0.5 [22] sgn=1 windVal=1 windSum=? operand
-SkOpSegment::markDone id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0.860379476 [17] (2.74999976,3.25000024) tEnd=0.860380171 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=6 (5,1 2,4) t=0.5 [22] (3.5,2.5) tEnd=0.750000104 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=6 span=18 windSum=?
-SkOpSegment::markWinding id=3 (4,0 3,5) t=0.5 [21] (3.5,2.5) tEnd=0.57768066 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=3 span=19 windSum=?
-SkOpSegment::markWinding id=6 (5,1 2,4) t=0 [11] (5,1) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.338765871 [20] (3.42231941,2.88840342) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=5 span=20 windSum=1
-SkOpSegment::debugShowActiveSpans id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0 (3,5) tEnd=0.860379476 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.5 (3.5,2.5) tEnd=0.57768066 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.57768066 (3.42231941,2.88840342) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=4 (2,4 1.18350339,4 1.53367352,3.83333325 2.2340138,3.5) t=0 (2,4) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0 (2.2340138,3.5) tEnd=0.155050964 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155050964 (2.74999976,3.25000024) tEnd=0.155051471 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 (2.75000095,3.24999785) tEnd=0.338765871 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.338765871 (3.42231941,2.88840342) tEnd=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0 (5,1) tEnd=0.5 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0.5 (3.5,2.5) tEnd=0.750000104 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0.750000104 (2.74999976,3.25000024) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::activeOp id=6 t=0.5 tEnd=0.750000104 op=diff miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
-SkOpSegment::markWinding id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0 [1] (3,5) tEnd=0.860379476 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=3 (4,0 3,5) t=0.57768066 [19] (3.42231941,2.88840342) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=3 span=19 windSum=-1
+SkOpAngle::dumpOne [5/11] next=6/16 sect=1/1 s=0.293280033 [17] e=0.222514468 [16] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [6/16] next=5/12 sect=5/5 s=0.959100004 [18] e=1 [12] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [5/12] next=6/15 sect=17/21 s=0.293280033 [17] e=1 [10] sgn=-1 windVal=1 windSum=2 oppVal=0 oppSum=1 done operand
+SkOpAngle::dumpOne [6/15] next=5/11 sect=21/21 s=0.959100004 [18] e=0 [11] sgn=1 windVal=1 windSum=2 oppVal=0 oppSum=1 done operand
+SkOpSegment::activeOp id=6 t=0.959100004 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
+SkOpSegment::activeOp id=5 t=0.293280033 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp id=6 t=0.959100004 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 [16] (1.58025348,2.04903817) tEnd=0.293280033 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[5] to:[6] start=2579372 end=2578764
+bridgeOp current id=5 from=(1.58025348,2.04903817) to=(0.959100008,2.16359997)
+path.cubicTo(1.38787913,2.08115721, 1.17804205,2.11915231, 0.959100008,2.16359997);
+SkOpSegment::findNextOp simple
+SkOpSegment::markDone id=6 (0,6 1,2) t=0.959100004 [18] (0.959100008,2.16359997) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=6 from=(0.959100008,2.16359997) to=(1,2)
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [6/21] next=1/2 sect=3/3 s=0.750000104 [18] e=0.5 [22] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=-1 operand
-SkOpAngle::dumpOne [1/2] next=5/14 sect=3/3 s=0.860379476 [17] e=0.860380171 [15] sgn=-1 windVal=1 windSum=? done
-SkOpAngle::dumpOne [5/14] next=5/13 sect=17/17 s=0.155050964 [23] e=0.155051471 [16] sgn=-1 windVal=1 windSum=? unorderable operand
-SkOpAngle::dumpOne [5/13] next=6/22 sect=17/17 s=0.155050964 [23] e=0 [9] sgn=1 windVal=1 windSum=? unorderable operand
-SkOpAngle::dumpOne [6/22] next=1/1 sect=19/19 s=0.750000104 [18] e=1 [12] sgn=-1 windVal=1 windSum=? operand
-SkOpAngle::dumpOne [1/1] next=6/21 sect=21/25 s=0.860379476 [17] e=0 [1] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=1
-SkOpSegment::activeOp id=1 t=0.860379476 tEnd=0.860380171 op=diff miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
-SkOpSegment::activeOp id=5 t=0.155050964 tEnd=0.155051471 op=diff miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
-SkOpSegment::markDone id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155050964 [23] (2.74999976,3.25000024) tEnd=0.155051471 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::activeOp id=5 t=0.155050964 tEnd=0 op=diff miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
-SkOpSegment::markDone id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0 [9] (2.2340138,3.5) tEnd=0.155050964 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markDone id=4 (2,4 1.18350339,4 1.53367352,3.83333325 2.2340138,3.5) t=0 [7] (2,4) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markDone id=6 (5,1 2,4) t=0.750000104 [18] (2.74999976,3.25000024) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::activeOp id=6 t=0.750000104 tEnd=1 op=diff miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
-SkOpSegment::activeOp id=1 t=0.860379476 tEnd=0 op=diff miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
-SkOpSegment::markDone id=1 (3,5 1.8377223,5 2.36405635,3.98683286 3.00889349,2.74555302) t=0 [1] (3,5) tEnd=0.860379476 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::markDone id=3 (4,0 3,5) t=0.57768066 [19] (3.42231941,2.88840342) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::findNextOp chase.append segment=3 span=19 windSum=-1
-SkOpSegment::markDone id=6 (5,1 2,4) t=0.5 [22] (3.5,2.5) tEnd=0.750000104 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[6] to:[1] start=4807508 end=4807316
-bridgeOp current id=6 from=(3.5,2.5) to=(2.74999976,3.25000024)
-path.moveTo(3.5,2.5);
-path.lineTo(2.74999976,3.25000024);
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.5 (3.5,2.5) tEnd=0.57768066 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 (2.75000095,3.24999785) tEnd=0.338765871 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.338765871 (3.42231941,2.88840342) tEnd=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (5,1 2,4) t=0 (5,1) tEnd=0.5 windSum=1 windValue=1 oppValue=0
-SkOpSegment::activeOp id=5 t=0.338765871 tEnd=1 op=diff miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
-SkOpSegment::markDone id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.338765871 [20] (3.42231941,2.88840342) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-SkOpSegment::markDone id=6 (5,1 2,4) t=0 [11] (5,1) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-bridgeOp chase.append id=6 windSum=1
-SkOpSegment::debugShowActiveSpans id=3 (4,0 3,5) t=0.5 (3.5,2.5) tEnd=0.57768066 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 (2.75000095,3.24999785) tEnd=0.338765871 windSum=? windValue=1 oppValue=0
-SkOpSegment::activeOp id=3 t=0.5 tEnd=0.57768066 op=diff miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
-SkOpSegment::markDone id=3 (4,0 3,5) t=0.5 [21] (3.5,2.5) tEnd=0.57768066 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
-SkOpSegment::markWinding id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 [16] (2.75000095,3.24999785) tEnd=0.338765871 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=5 span=16 windSum=1
-SkOpSegment::debugShowActiveSpans id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 (2.75000095,3.24999785) tEnd=0.338765871 windSum=1 windValue=1 oppValue=0
-SkOpSegment::activeOp id=5 t=0.338765871 tEnd=0.155051471 op=diff miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
-SkOpSegment::markDone id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1) t=0.155051471 [16] (2.75000095,3.24999785) tEnd=0.338765871 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done stop
+SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
+SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 done stop
+SkOpSegment::activeOp id=2 t=0.538493706 tEnd=0.481912781 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0
+SkOpSegment::activeOp id=4 t=0.0521913275 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
+SkOpSegment::activeOp id=2 t=0.538493706 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
+SkOpSegment::markDone id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 [7] (1,2) tEnd=0.0521913275 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[4] to:[2] start=2578892 end=2577740
+bridgeOp current id=4 from=(1,2) to=(1.17718506,1.99055469)
+path.lineTo(1,2);
+path.cubicTo(1.0610131,1.99678874, 1.12006187,1.99363947, 1.17718506,1.99055469);
+path.close();
</div>
</div>
@@ -303,7 +229,7 @@ SkOpSegment::markDone id=5 (2.2340138,3.5 3.2491498,3.01683664 5,2.18350339 5,1)
<script type="text/javascript">
var testDivs = [
- cubics6d,
+ loops59i,
];
var decimal_places = 3; // make this 3 to show more precision