| Index: src/pathops/SkPathOpsCubic.cpp
|
| diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
|
| index a89604f94cafa98ae9617868cf36bf86014151aa..59e829643b612c2061158255a641dd34e610e850 100644
|
| --- a/src/pathops/SkPathOpsCubic.cpp
|
| +++ b/src/pathops/SkPathOpsCubic.cpp
|
| @@ -12,6 +12,48 @@
|
|
|
| const int SkDCubic::gPrecisionUnit = 256; // FIXME: test different values in test framework
|
|
|
| +int SkDCubic::AddValidTs(double allRoots[3], int realRoots, double validRoots[3]) {
|
| + int valid = SkDQuad::AddValidTs(allRoots, realRoots, validRoots);
|
| + if (valid != 1) {
|
| + return valid;
|
| + }
|
| + if (realRoots == 1) {
|
| + return valid;
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| +double SkDCubic::binarySearch(double step, double t, double axisIntercept, bool yAxis) const {
|
| + do {
|
| + SkDPoint cubicAtT = ptAtT(t);
|
| + double calcDist = yAxis ? cubicAtT.fX : cubicAtT.fY;
|
| + if (approximately_equal(calcDist, axisIntercept)) {
|
| + break;
|
| + }
|
| + if (step == 0) {
|
| + return -1; // binary search with this step failed
|
| + }
|
| + calcDist = fabs(calcDist - axisIntercept);
|
| + double lastStep = step;
|
| + step /= 2;
|
| + SkDPoint lessPt = ptAtT(t - lastStep);
|
| + double lessDist = fabs((yAxis ? lessPt.fX : lessPt.fY) - axisIntercept);
|
| + if (calcDist > lessDist) {
|
| + t -= step;
|
| + t = SkTMax(0., t);
|
| + } else {
|
| + SkDPoint morePt = ptAtT(t + lastStep);
|
| + double moreDist = fabs((yAxis ? morePt.fX : morePt.fY) - axisIntercept);
|
| + if (calcDist <= moreDist) {
|
| + continue;
|
| + }
|
| + t += step;
|
| + t = SkTMin(1., t);
|
| + }
|
| + } while (true);
|
| + return t;
|
| +}
|
| +
|
| // FIXME: cache keep the bounds and/or precision with the caller?
|
| double SkDCubic::calcPrecision() const {
|
| SkDRect dRect;
|
| @@ -93,6 +135,49 @@ bool SkDCubic::monotonicInY() const {
|
| && between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
|
| }
|
|
|
| +void SkDCubic::searchRoots(double allRoots[3], int realRoots, double* tPtr, double axisIntercept,
|
| + bool yAxis) const {
|
| + double largest = SkTMax(fabs(allRoots[0]), fabs(allRoots[1]));
|
| + if (realRoots == 3) {
|
| + largest = SkTMax(largest, fabs(allRoots[2]));
|
| + }
|
| + int largeBits;
|
| + if (largest <= 1) {
|
| + double smallest = SkTMin(allRoots[0], allRoots[1]);
|
| + if (realRoots == 3) {
|
| + smallest = SkTMin(smallest, allRoots[2]);
|
| + }
|
| + SkASSERT(smallest < 0);
|
| + SkASSERT(smallest >= -1);
|
| + largeBits = 0;
|
| + } else {
|
| + (void) frexp(largest, &largeBits);
|
| + SkASSERT(largeBits >= 0);
|
| + SkASSERT(largeBits < 256);
|
| + }
|
| + double step = 1e-6;
|
| + if (largeBits > 21) {
|
| + step = 1e-1;
|
| + } else if (largeBits > 18) {
|
| + step = 1e-2;
|
| + } else if (largeBits > 15) {
|
| + step = 1e-3;
|
| + } else if (largeBits > 12) {
|
| + step = 1e-4;
|
| + } else if (largeBits > 9) {
|
| + step = 1e-5;
|
| + }
|
| + do {
|
| + double newT = binarySearch(step, *tPtr, axisIntercept, yAxis);
|
| + if (newT >= 0) {
|
| + *tPtr = newT;
|
| + return;
|
| + }
|
| + step *= 1.5;
|
| + SkASSERT(step < 1);
|
| + } while (true);
|
| +}
|
| +
|
| bool SkDCubic::serpentine() const {
|
| #if 0 // FIXME: enabling this fixes cubicOp114 but breaks cubicOp58d and cubicOp53d
|
| double tValues[2];
|
| @@ -118,6 +203,13 @@ bool SkDCubic::serpentine() const {
|
| static const double PI = 3.141592653589793;
|
|
|
| // from SkGeometry.cpp (and Numeric Solutions, 5.6)
|
| +int SkDCubic::RootsValidT(double A, double B, double C, double D, double s[3], int* sCount,
|
| + double t[3]) {
|
| + *sCount = RootsReal(A, B, C, D, s);
|
| + int foundRoots = SkDCubic::AddValidTs(s, *sCount, t);
|
| + return foundRoots;
|
| +}
|
| +
|
| 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);
|
| @@ -180,6 +272,20 @@ int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) {
|
| double R2 = R * R;
|
| double Q3 = Q * Q * Q;
|
| double R2MinusQ3 = R2 - Q3;
|
| + double R2Q3Max = SkTMax(R2, fabs(Q3));
|
| + if (R2Q3Max * FLT_EPSILON > fabs(R2MinusQ3)) {
|
| +#if defined(__clang__) || defined(__GNUC__)
|
| + __float128 R2_128 = (__float128) R * (__float128) R;
|
| + __float128 Q3_128 = (__float128) Q * (__float128) Q * (__float128) Q;
|
| + __float128 R2MinusQ3_128 = R2_128 - Q3_128;
|
| + R2MinusQ3 = (double) R2MinusQ3_128;
|
| +#else
|
| + SkFloat128 R2_128 = SkFloat128Mul(R, R);
|
| + SkFloat128 Q3_128 = SkFloat128Mul(Q, Q);
|
| + Q3_128 = SkFloat128Mul(Q3_128, Q);
|
| + R2MinusQ3 = SkFloat128Sub(R2_128, Q3_128);
|
| +#endif
|
| + }
|
| double adiv3 = a / 3;
|
| double r;
|
| double* roots = s;
|
| @@ -210,7 +316,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;
|
|
|