| Index: src/pathops/SkPathOpsCubic.cpp
 | 
| diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
 | 
| index a89604f94cafa98ae9617868cf36bf86014151aa..9d70d58ec15d7a5219637e2eff3f7b869b9f2b59 100644
 | 
| --- a/src/pathops/SkPathOpsCubic.cpp
 | 
| +++ b/src/pathops/SkPathOpsCubic.cpp
 | 
| @@ -9,9 +9,58 @@
 | 
|  #include "SkPathOpsLine.h"
 | 
|  #include "SkPathOpsQuad.h"
 | 
|  #include "SkPathOpsRect.h"
 | 
| +#include "SkTSort.h"
 | 
|  
 | 
|  const int SkDCubic::gPrecisionUnit = 256;  // FIXME: test different values in test framework
 | 
|  
 | 
| +// give up when changing t no longer moves point
 | 
| +// also, copy point rather than recompute it when it does change
 | 
| +double SkDCubic::binarySearch(double min, double max, double axisIntercept,
 | 
| +        SearchAxis xAxis) const {
 | 
| +    double t = (min + max) / 2;
 | 
| +    double step = (t - min) / 2;
 | 
| +    SkDPoint cubicAtT = ptAtT(t);
 | 
| +    double calcPos = (&cubicAtT.fX)[xAxis];
 | 
| +    double calcDist = calcPos - axisIntercept;
 | 
| +    do {
 | 
| +        double priorT = t - step;
 | 
| +        SkASSERT(priorT >= min);
 | 
| +        SkDPoint lessPt = ptAtT(priorT);
 | 
| +        if (approximately_equal(lessPt.fX, cubicAtT.fX)
 | 
| +                && approximately_equal(lessPt.fY, cubicAtT.fY)) {
 | 
| +            return -1;  // binary search found no point at this axis intercept
 | 
| +        }
 | 
| +        double lessDist = (&lessPt.fX)[xAxis] - axisIntercept;
 | 
| +#if DEBUG_CUBIC_BINARY_SEARCH
 | 
| +        SkDebugf("t=%1.9g calc=%1.9g dist=%1.9g step=%1.9g less=%1.9g\n", t, calcPos, calcDist,
 | 
| +                step, lessDist);
 | 
| +#endif
 | 
| +        double lastStep = step;
 | 
| +        step /= 2;
 | 
| +        if (calcDist > 0 ? calcDist > lessDist : calcDist < lessDist) {
 | 
| +            t = priorT;
 | 
| +        } else {
 | 
| +            double nextT = t + lastStep;
 | 
| +            SkASSERT(nextT <= max);
 | 
| +            SkDPoint morePt = ptAtT(nextT);
 | 
| +            if (approximately_equal(morePt.fX, cubicAtT.fX)
 | 
| +                    && approximately_equal(morePt.fY, cubicAtT.fY)) {
 | 
| +                return -1;  // binary search found no point at this axis intercept
 | 
| +            }
 | 
| +            double moreDist = (&morePt.fX)[xAxis] - axisIntercept;
 | 
| +            if (calcDist > 0 ? calcDist <= moreDist : calcDist >= moreDist) {
 | 
| +                continue;
 | 
| +            }
 | 
| +            t = nextT;
 | 
| +        }
 | 
| +        SkDPoint testAtT = ptAtT(t);
 | 
| +        cubicAtT = testAtT;
 | 
| +        calcPos = (&cubicAtT.fX)[xAxis];
 | 
| +        calcDist = calcPos - axisIntercept;
 | 
| +    } while (!approximately_equal(calcPos, axisIntercept));
 | 
| +    return t;
 | 
| +}
 | 
| +
 | 
|  // FIXME: cache keep the bounds and/or precision with the caller?
 | 
|  double SkDCubic::calcPrecision() const {
 | 
|      SkDRect dRect;
 | 
| @@ -93,6 +142,27 @@ bool SkDCubic::monotonicInY() const {
 | 
|              && between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
 | 
|  }
 | 
|  
 | 
| +int SkDCubic::searchRoots(double extremeTs[6], int extrema, double axisIntercept,
 | 
| +        SearchAxis xAxis, double* validRoots) const {
 | 
| +    extrema += findInflections(&extremeTs[extrema]);
 | 
| +    extremeTs[extrema++] = 0;
 | 
| +    extremeTs[extrema] = 1;
 | 
| +    SkTQSort(extremeTs, extremeTs + extrema);
 | 
| +    int validCount = 0;
 | 
| +    for (int index = 0; index < extrema; ) {
 | 
| +        double min = extremeTs[index];
 | 
| +        double max = extremeTs[++index];
 | 
| +        if (min == max) {
 | 
| +            continue;
 | 
| +        }
 | 
| +        double newT = binarySearch(min, max, axisIntercept, xAxis);
 | 
| +        if (newT >= 0) {
 | 
| +            validRoots[validCount++] = newT;
 | 
| +        }
 | 
| +    }
 | 
| +    return validCount;
 | 
| +}
 | 
| +
 | 
|  bool SkDCubic::serpentine() const {
 | 
|  #if 0  // FIXME: enabling this fixes cubicOp114 but breaks cubicOp58d and cubicOp53d
 | 
|      double tValues[2];
 | 
| @@ -210,7 +280,7 @@ int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) {
 | 
|          }
 | 
|          r = A - adiv3;
 | 
|          *roots++ = r;
 | 
| -        if (AlmostDequalUlps(R2, Q3)) {
 | 
| +        if (AlmostDequalUlps((double) R2, (double) Q3)) {
 | 
|              r = -A / 2 - adiv3;
 | 
|              if (!AlmostDequalUlps(s[0], r)) {
 | 
|                  *roots++ = r;
 | 
| 
 |