minor fixes to cubics code and overall alignment of how bounds and tops are computed...
authorcaryclark <caryclark@google.com>
Wed, 29 Apr 2015 15:28:30 +0000 (08:28 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 29 Apr 2015 15:28:30 +0000 (08:28 -0700)
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

33 files changed:
gyp/core.gypi
include/core/SkPath.h
src/core/SkPath.cpp
src/pathops/SkDCubicLineIntersection.cpp
src/pathops/SkOpContour.cpp
src/pathops/SkOpContour.h
src/pathops/SkOpSegment.cpp
src/pathops/SkOpSegment.h
src/pathops/SkPathOpsBounds.cpp [deleted file]
src/pathops/SkPathOpsBounds.h
src/pathops/SkPathOpsCommon.cpp
src/pathops/SkPathOpsCommon.h
src/pathops/SkPathOpsConic.cpp
src/pathops/SkPathOpsConic.h
src/pathops/SkPathOpsCubic.cpp
src/pathops/SkPathOpsCubic.h
src/pathops/SkPathOpsCurve.cpp [new file with mode: 0644]
src/pathops/SkPathOpsCurve.h
src/pathops/SkPathOpsDebug.h
src/pathops/SkPathOpsOp.cpp
src/pathops/SkPathOpsQuad.cpp
src/pathops/SkPathOpsQuad.h
src/pathops/SkPathOpsRect.cpp
src/pathops/SkPathOpsRect.h
src/pathops/SkPathOpsSimplify.cpp
tests/PathOpsBoundsTest.cpp
tests/PathOpsCubicLineIntersectionTest.cpp
tests/PathOpsDCubicTest.cpp
tests/PathOpsExtendedTest.cpp
tests/PathOpsOpTest.cpp
tests/PathOpsTestCommon.cpp
tools/pathops_sorter.htm
tools/pathops_visualizer.htm

index 190236f..1f06252 100644 (file)
         '<(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',
index b5b95e1..c413560 100644 (file)
@@ -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;
index 45429a6..aa99ce4 100644 (file)
@@ -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();)
 
index f5fe015..f658b09 100644 (file)
@@ -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;
             }
index ce9439a..107c831 100644 (file)
@@ -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;
index 3d26ae8..9abf382 100644 (file)
@@ -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:
index a571609..ce35f84 100644 (file)
@@ -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) {
index 1e9e1c4..a762a66 100644 (file)
@@ -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 (file)
index ea13e2e..0000000
+++ /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
-};
index b65d3be..7b9daa3 100644 (file)
@@ -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
index 3496179..05b370a 100644 (file)
@@ -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);
index 1bf1791..82eb5da 100644 (file)
@@ -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);
index 869a406..b9b0cda 100644 (file)
@@ -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;
-}
index 8251901..bc73049 100644 (file)
@@ -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;
index 63f828f..777298b 100644 (file)
@@ -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];
index 269073c..f9d2910 100644 (file)
@@ -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 (file)
index 0000000..651e64a
--- /dev/null
@@ -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
+};
index 69af91c..bfbc515 100644 (file)
@@ -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);
index 8473d66..0624ad6 100644 (file)
@@ -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
 #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
index 4e3ec4a..1105af5 100644 (file)
@@ -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;
index 397a3ce..66f191b 100644 (file)
@@ -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);
 }
 
index b201860..de4ce4b 100644 (file)
@@ -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;
index 540db16..8c01153 100644 (file)
 #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));
     }
 }
index f783d96..7fec70a 100644 (file)
@@ -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
index b4f8e22..14c6837 100644 (file)
@@ -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;
index 1160ae6..0c74b69 100644 (file)
@@ -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);
 }
index 6fdce3c..a1f1d9f 100644 (file)
@@ -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}}}},
 
index c7c9f2a..b5fe8f7 100644 (file)
@@ -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);
index 92b0e87..9c57797 100644 (file)
@@ -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;
 }
index 993fdd9..f25ebc9 100644 (file)
@@ -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);
index d933115..f685225 100644 (file)
@@ -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;
     }
index c6ec3d4..c515fe9 100644 (file)
@@ -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>
index 5aa1068..f1288f0 100644 (file)
 <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