gfx/skia/trunk/src/pathops/SkOpAngle.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/pathops/SkOpAngle.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,435 @@
     1.4 +/*
     1.5 + * Copyright 2012 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +#include "SkIntersections.h"
    1.11 +#include "SkOpAngle.h"
    1.12 +#include "SkOpSegment.h"
    1.13 +#include "SkPathOpsCurve.h"
    1.14 +#include "SkTSort.h"
    1.15 +
    1.16 +#if DEBUG_ANGLE
    1.17 +#include "SkString.h"
    1.18 +
    1.19 +static const char funcName[] = "SkOpSegment::operator<";
    1.20 +static const int bugChar = strlen(funcName) + 1;
    1.21 +#endif
    1.22 +
    1.23 +/* Angles are sorted counterclockwise. The smallest angle has a positive x and the smallest
    1.24 +   positive y. The largest angle has a positive x and a zero y. */
    1.25 +
    1.26 +#if DEBUG_ANGLE
    1.27 +    static bool CompareResult(SkString* bugOut, const char* append, bool compare) {
    1.28 +        bugOut->appendf("%s", append);
    1.29 +        bugOut->writable_str()[bugChar] = "><"[compare];
    1.30 +        SkDebugf("%s\n", bugOut->c_str());
    1.31 +        return compare;
    1.32 +    }
    1.33 +
    1.34 +    #define COMPARE_RESULT(append, compare) CompareResult(&bugOut, append, compare)
    1.35 +#else
    1.36 +    #define COMPARE_RESULT(append, compare) compare
    1.37 +#endif
    1.38 +
    1.39 +bool SkOpAngle::calcSlop(double x, double y, double rx, double ry, bool* result) const{
    1.40 +    double absX = fabs(x);
    1.41 +    double absY = fabs(y);
    1.42 +    double length = absX < absY ? absX / 2 + absY : absX + absY / 2;
    1.43 +    int exponent;
    1.44 +    (void) frexp(length, &exponent);
    1.45 +    double epsilon = ldexp(FLT_EPSILON, exponent);
    1.46 +    SkPath::Verb verb = fSegment->verb();
    1.47 +    SkASSERT(verb == SkPath::kQuad_Verb || verb == SkPath::kCubic_Verb);
    1.48 +    // FIXME: the quad and cubic factors are made up ; determine actual values
    1.49 +    double slop = verb == SkPath::kQuad_Verb ? 4 * epsilon : 512 * epsilon;
    1.50 +    double xSlop = slop;
    1.51 +    double ySlop = x * y < 0 ? -xSlop : xSlop; // OPTIMIZATION: use copysign / _copysign ?
    1.52 +    double x1 = x - xSlop;
    1.53 +    double y1 = y + ySlop;
    1.54 +    double x_ry1 = x1 * ry;
    1.55 +    double rx_y1 = rx * y1;
    1.56 +    *result = x_ry1 < rx_y1;
    1.57 +    double x2 = x + xSlop;
    1.58 +    double y2 = y - ySlop;
    1.59 +    double x_ry2 = x2 * ry;
    1.60 +    double rx_y2 = rx * y2;
    1.61 +    bool less2 = x_ry2 < rx_y2;
    1.62 +    return *result == less2;
    1.63 +}
    1.64 +
    1.65 +/*
    1.66 +for quads and cubics, set up a parameterized line (e.g. LineParameters )
    1.67 +for points [0] to [1]. See if point [2] is on that line, or on one side
    1.68 +or the other. If it both quads' end points are on the same side, choose
    1.69 +the shorter tangent. If the tangents are equal, choose the better second
    1.70 +tangent angle
    1.71 +
    1.72 +FIXME: maybe I could set up LineParameters lazily
    1.73 +*/
    1.74 +bool SkOpAngle::operator<(const SkOpAngle& rh) const {  // this/lh: left-hand; rh: right-hand
    1.75 +    double y = dy();
    1.76 +    double ry = rh.dy();
    1.77 +#if DEBUG_ANGLE
    1.78 +    SkString bugOut;
    1.79 +    bugOut.printf("%s _ id=%d segId=%d tStart=%1.9g tEnd=%1.9g"
    1.80 +        " | id=%d segId=%d tStart=%1.9g tEnd=%1.9g ", funcName,
    1.81 +        fID, fSegment->debugID(), fSegment->t(fStart), fSegment->t(fEnd),
    1.82 +        rh.fID, rh.fSegment->debugID(), rh.fSegment->t(rh.fStart), rh.fSegment->t(rh.fEnd));
    1.83 +#endif
    1.84 +    double y_ry = y * ry;
    1.85 +    if (y_ry < 0) {  // if y's are opposite signs, we can do a quick return
    1.86 +        return COMPARE_RESULT("1 y * ry < 0", y < 0);
    1.87 +    }
    1.88 +    // at this point, both y's must be the same sign, or one (or both) is zero
    1.89 +    double x = dx();
    1.90 +    double rx = rh.dx();
    1.91 +    if (x * rx < 0) {  // if x's are opposite signs, use y to determine first or second half
    1.92 +        if (y < 0 && ry < 0) {  // if y's are negative, lh x is smaller if positive
    1.93 +            return COMPARE_RESULT("2 x_rx < 0 && y < 0 ...", x > 0);
    1.94 +        }
    1.95 +        if (y >= 0 && ry >= 0) {  // if y's are zero or positive, lh x is smaller if negative
    1.96 +            return COMPARE_RESULT("3 x_rx < 0 && y >= 0 ...", x < 0);
    1.97 +        }
    1.98 +        SkASSERT((y == 0) ^ (ry == 0));  // if one y is zero and one is negative, neg y is smaller
    1.99 +        return COMPARE_RESULT("4 x_rx < 0 && y == 0 ...", y < 0);
   1.100 +    }
   1.101 +    // at this point, both x's must be the same sign, or one (or both) is zero
   1.102 +    if (y_ry == 0) { // if either y is zero
   1.103 +        if (y + ry < 0) { // if the other y is less than zero, it must be smaller
   1.104 +            return COMPARE_RESULT("5 y_ry == 0 && y + ry < 0", y < 0);
   1.105 +        }
   1.106 +        if (y + ry > 0) { // if a y is greater than zero and an x is positive,  non zero is smaller
   1.107 +            return COMPARE_RESULT("6 y_ry == 0 && y + ry > 0", (x + rx > 0) ^ (y == 0));
   1.108 +        }
   1.109 +        // at this point, both y's are zero, so lines are coincident or one is degenerate
   1.110 +        SkASSERT(x * rx != 0);  // and a degenerate line should haven't gotten this far
   1.111 +    }
   1.112 +    // see if either curve can be lengthened before trying the tangent
   1.113 +    if (fSegment->other(fEnd) != rh.fSegment  // tangents not absolutely identical
   1.114 +            && rh.fSegment->other(rh.fEnd) != fSegment
   1.115 +            && y != -DBL_EPSILON
   1.116 +            && ry != -DBL_EPSILON) {  // and not intersecting
   1.117 +        SkOpAngle longer = *this;
   1.118 +        SkOpAngle rhLonger = rh;
   1.119 +        if ((longer.lengthen(rh) | rhLonger.lengthen(*this))  // lengthen both
   1.120 +                && (fUnorderable || !longer.fUnorderable)
   1.121 +                && (rh.fUnorderable || !rhLonger.fUnorderable)) {
   1.122 +#if DEBUG_ANGLE
   1.123 +            bugOut.prepend("  ");
   1.124 +#endif
   1.125 +            return COMPARE_RESULT("10 longer.lengthen(rh) ...", longer < rhLonger);
   1.126 +        }
   1.127 +    }
   1.128 +    SkPath::Verb verb = fSegment->verb();
   1.129 +    SkPath::Verb rVerb = rh.fSegment->verb();
   1.130 +    if (y_ry != 0) { // if they aren't coincident, look for a stable cross product
   1.131 +        // at this point, y's are the same sign, neither is zero
   1.132 +        //   and x's are the same sign, or one (or both) is zero
   1.133 +        double x_ry = x * ry;
   1.134 +        double rx_y = rx * y;
   1.135 +        if (!fComputed && !rh.fComputed) {
   1.136 +            if (!SkDLine::NearRay(x, y, rx, ry) && x_ry != rx_y) {
   1.137 +                return COMPARE_RESULT("7 !fComputed && !rh.fComputed", x_ry < rx_y);
   1.138 +            }
   1.139 +            if (fSide2 == 0 && rh.fSide2 == 0) {
   1.140 +                return COMPARE_RESULT("7a !fComputed && !rh.fComputed", x_ry < rx_y);
   1.141 +            }
   1.142 +        } else {
   1.143 +            // if the vector was a result of subdividing a curve, see if it is stable
   1.144 +            bool sloppy1 = x_ry < rx_y;
   1.145 +            bool sloppy2 = !sloppy1;
   1.146 +            if ((!fComputed || calcSlop(x, y, rx, ry, &sloppy1))
   1.147 +                    && (!rh.fComputed || rh.calcSlop(rx, ry, x, y, &sloppy2))
   1.148 +                    && sloppy1 != sloppy2) {
   1.149 +                return COMPARE_RESULT("8 CalcSlop(x, y ...", sloppy1);
   1.150 +            }
   1.151 +        }
   1.152 +    }
   1.153 +    if (fSide2 * rh.fSide2 == 0) {  // one is zero
   1.154 +#if DEBUG_ANGLE
   1.155 +        if (fSide2 == rh.fSide2 && y_ry) {  // both is zero; coincidence was undetected
   1.156 +            SkDebugf("%s coincidence!\n", __FUNCTION__);
   1.157 +        }
   1.158 +#endif
   1.159 +        return COMPARE_RESULT("9a fSide2 * rh.fSide2 == 0 ...", fSide2 < rh.fSide2);
   1.160 +    }
   1.161 +    // at this point, the initial tangent line is nearly coincident
   1.162 +    // see if edges curl away from each other
   1.163 +    if (fSide * rh.fSide < 0 && (!approximately_zero(fSide) || !approximately_zero(rh.fSide))) {
   1.164 +        return COMPARE_RESULT("9b fSide * rh.fSide < 0 ...", fSide < rh.fSide);
   1.165 +    }
   1.166 +    if (fUnsortable || rh.fUnsortable) {
   1.167 +        // even with no solution, return a stable sort
   1.168 +        return COMPARE_RESULT("11 fUnsortable || rh.fUnsortable", this < &rh);
   1.169 +    }
   1.170 +    if ((verb == SkPath::kLine_Verb && approximately_zero(y) && approximately_zero(x))
   1.171 +            || (rVerb == SkPath::kLine_Verb
   1.172 +            && approximately_zero(ry) && approximately_zero(rx))) {
   1.173 +        // See general unsortable comment below. This case can happen when
   1.174 +        // one line has a non-zero change in t but no change in x and y.
   1.175 +        fUnsortable = true;
   1.176 +        return COMPARE_RESULT("12 verb == SkPath::kLine_Verb ...", this < &rh);
   1.177 +    }
   1.178 +    if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) {
   1.179 +        fUnsortable = true;
   1.180 +        return COMPARE_RESULT("13 verb == fSegment->isTiny(this) ...", this < &rh);
   1.181 +    }
   1.182 +    SkASSERT(verb >= SkPath::kQuad_Verb);
   1.183 +    SkASSERT(rVerb >= SkPath::kQuad_Verb);
   1.184 +    // FIXME: until I can think of something better, project a ray from the
   1.185 +    // end of the shorter tangent to midway between the end points
   1.186 +    // through both curves and use the resulting angle to sort
   1.187 +    // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
   1.188 +    double len = fTangentPart.normalSquared();
   1.189 +    double rlen = rh.fTangentPart.normalSquared();
   1.190 +    SkDLine ray;
   1.191 +    SkIntersections i, ri;
   1.192 +    int roots, rroots;
   1.193 +    bool flip = false;
   1.194 +    bool useThis;
   1.195 +    bool leftLessThanRight = fSide > 0;
   1.196 +    do {
   1.197 +        useThis = (len < rlen) ^ flip;
   1.198 +        const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart;
   1.199 +        SkPath::Verb partVerb = useThis ? verb : rVerb;
   1.200 +        ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
   1.201 +            part[2] : part[1];
   1.202 +        ray[1] = SkDPoint::Mid(part[0], part[SkPathOpsVerbToPoints(partVerb)]);
   1.203 +        SkASSERT(ray[0] != ray[1]);
   1.204 +        roots = (i.*CurveRay[SkPathOpsVerbToPoints(verb)])(fSegment->pts(), ray);
   1.205 +        rroots = (ri.*CurveRay[SkPathOpsVerbToPoints(rVerb)])(rh.fSegment->pts(), ray);
   1.206 +    } while ((roots == 0 || rroots == 0) && (flip ^= true));
   1.207 +    if (roots == 0 || rroots == 0) {
   1.208 +        // FIXME: we don't have a solution in this case. The interim solution
   1.209 +        // is to mark the edges as unsortable, exclude them from this and
   1.210 +        // future computations, and allow the returned path to be fragmented
   1.211 +        fUnsortable = true;
   1.212 +        return COMPARE_RESULT("roots == 0 || rroots == 0", this < &rh);
   1.213 +    }
   1.214 +    SkASSERT(fSide != 0 && rh.fSide != 0);
   1.215 +    if (fSide * rh.fSide < 0) {
   1.216 +        fUnsortable = true;
   1.217 +        return COMPARE_RESULT("14 fSide * rh.fSide < 0", this < &rh);
   1.218 +    }
   1.219 +    SkDPoint lLoc;
   1.220 +    double best = SK_ScalarInfinity;
   1.221 +#if DEBUG_SORT
   1.222 +    SkDebugf("lh=%d rh=%d use-lh=%d ray={{%1.9g,%1.9g}, {%1.9g,%1.9g}} %c\n",
   1.223 +            fSegment->debugID(), rh.fSegment->debugID(), useThis, ray[0].fX, ray[0].fY,
   1.224 +            ray[1].fX, ray[1].fY, "-+"[fSide > 0]);
   1.225 +#endif
   1.226 +    for (int index = 0; index < roots; ++index) {
   1.227 +        SkDPoint loc = i.pt(index);
   1.228 +        SkDVector dxy = loc - ray[0];
   1.229 +        double dist = dxy.lengthSquared();
   1.230 +#if DEBUG_SORT
   1.231 +        SkDebugf("best=%1.9g dist=%1.9g loc={%1.9g,%1.9g} dxy={%1.9g,%1.9g}\n",
   1.232 +                best, dist, loc.fX, loc.fY, dxy.fX, dxy.fY);
   1.233 +#endif
   1.234 +        if (best > dist) {
   1.235 +            lLoc = loc;
   1.236 +            best = dist;
   1.237 +        }
   1.238 +    }
   1.239 +    flip = false;
   1.240 +    SkDPoint rLoc;
   1.241 +    for (int index = 0; index < rroots; ++index) {
   1.242 +        rLoc = ri.pt(index);
   1.243 +        SkDVector dxy = rLoc - ray[0];
   1.244 +        double dist = dxy.lengthSquared();
   1.245 +#if DEBUG_SORT
   1.246 +        SkDebugf("best=%1.9g dist=%1.9g %c=(fSide < 0) rLoc={%1.9g,%1.9g} dxy={%1.9g,%1.9g}\n",
   1.247 +                best, dist, "><"[fSide < 0], rLoc.fX, rLoc.fY, dxy.fX, dxy.fY);
   1.248 +#endif
   1.249 +        if (best > dist) {
   1.250 +            flip = true;
   1.251 +            break;
   1.252 +        }
   1.253 +    }
   1.254 +    if (flip) {
   1.255 +        leftLessThanRight = !leftLessThanRight;
   1.256 +    }
   1.257 +    return COMPARE_RESULT("15 leftLessThanRight", leftLessThanRight);
   1.258 +}
   1.259 +
   1.260 +bool SkOpAngle::isHorizontal() const {
   1.261 +    return dy() == 0 && fSegment->verb() == SkPath::kLine_Verb;
   1.262 +}
   1.263 +
   1.264 +// lengthen cannot cross opposite angle
   1.265 +bool SkOpAngle::lengthen(const SkOpAngle& opp) {
   1.266 +    if (fSegment->other(fEnd) == opp.fSegment) {
   1.267 +        return false;
   1.268 +    }
   1.269 +    // FIXME: make this a while loop instead and make it as large as possible?
   1.270 +    int newEnd = fEnd;
   1.271 +    if (fStart < fEnd ? ++newEnd < fSegment->count() : --newEnd >= 0) {
   1.272 +        fEnd = newEnd;
   1.273 +        setSpans();
   1.274 +        return true;
   1.275 +    }
   1.276 +    return false;
   1.277 +}
   1.278 +
   1.279 +void SkOpAngle::set(const SkOpSegment* segment, int start, int end) {
   1.280 +    fSegment = segment;
   1.281 +    fStart = start;
   1.282 +    fEnd = end;
   1.283 +    setSpans();
   1.284 +}
   1.285 +
   1.286 +void SkOpAngle::setSpans() {
   1.287 +    fUnorderable = fSegment->isTiny(this);
   1.288 +    fLastMarked = NULL;
   1.289 +    fUnsortable = false;
   1.290 +    const SkPoint* pts = fSegment->pts();
   1.291 +    if (fSegment->verb() != SkPath::kLine_Verb) {
   1.292 +        fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart);
   1.293 +        fSegment->subDivide(fStart, fStart < fEnd ? fSegment->count() - 1 : 0, &fCurveHalf);
   1.294 +    }
   1.295 +    // FIXME: slight errors in subdivision cause sort trouble later on. As an experiment, try
   1.296 +    // rounding the curve part to float precision here
   1.297 +    // fCurvePart.round(fSegment->verb());
   1.298 +    switch (fSegment->verb()) {
   1.299 +    case SkPath::kLine_Verb: {
   1.300 +        SkASSERT(fStart != fEnd);
   1.301 +        fCurvePart[0].set(pts[fStart > fEnd]);
   1.302 +        fCurvePart[1].set(pts[fStart < fEnd]);
   1.303 +        fComputed = false;
   1.304 +        // OPTIMIZATION: for pure line compares, we never need fTangentPart.c
   1.305 +        fTangentPart.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart));
   1.306 +        fSide = 0;
   1.307 +        fSide2 = 0;
   1.308 +        } break;
   1.309 +    case SkPath::kQuad_Verb: {
   1.310 +        fSide2 = -fTangentHalf.quadPart(*SkTCast<SkDQuad*>(&fCurveHalf));
   1.311 +        SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart);
   1.312 +        fTangentPart.quadEndPoints(quad);
   1.313 +        fSide = -fTangentPart.pointDistance(fCurvePart[2]);  // not normalized -- compare sign only
   1.314 +        if (fComputed && dx() > 0 && approximately_zero(dy())) {
   1.315 +            SkDCubic origCurve; // can't use segment's curve in place since it may be flipped
   1.316 +            int last = fSegment->count() - 1;
   1.317 +            fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
   1.318 +            SkLineParameters origTan;
   1.319 +            origTan.quadEndPoints(*SkTCast<SkDQuad*>(&origCurve));
   1.320 +            if (origTan.dx() <= 0
   1.321 +                    || (dy() != origTan.dy() && dy() * origTan.dy() <= 0)) { // signs match?
   1.322 +                fUnorderable = true;
   1.323 +                return;
   1.324 +            }
   1.325 +        }
   1.326 +        } break;
   1.327 +    case SkPath::kCubic_Verb: {
   1.328 +        double startT = fSegment->t(fStart);
   1.329 +        fSide2 = -fTangentHalf.cubicPart(fCurveHalf);
   1.330 +        fTangentPart.cubicEndPoints(fCurvePart);
   1.331 +        double testTs[4];
   1.332 +        // OPTIMIZATION: keep inflections precomputed with cubic segment?
   1.333 +        int testCount = SkDCubic::FindInflections(pts, testTs);
   1.334 +        double endT = fSegment->t(fEnd);
   1.335 +        double limitT = endT;
   1.336 +        int index;
   1.337 +        for (index = 0; index < testCount; ++index) {
   1.338 +            if (!between(startT, testTs[index], limitT)) {
   1.339 +                testTs[index] = -1;
   1.340 +            }
   1.341 +        }
   1.342 +        testTs[testCount++] = startT;
   1.343 +        testTs[testCount++] = endT;
   1.344 +        SkTQSort<double>(testTs, &testTs[testCount - 1]);
   1.345 +        double bestSide = 0;
   1.346 +        int testCases = (testCount << 1) - 1;
   1.347 +        index = 0;
   1.348 +        while (testTs[index] < 0) {
   1.349 +            ++index;
   1.350 +        }
   1.351 +        index <<= 1;
   1.352 +        for (; index < testCases; ++index) {
   1.353 +            int testIndex = index >> 1;
   1.354 +            double testT = testTs[testIndex];
   1.355 +            if (index & 1) {
   1.356 +                testT = (testT + testTs[testIndex + 1]) / 2;
   1.357 +            }
   1.358 +            // OPTIMIZE: could avoid call for t == startT, endT
   1.359 +            SkDPoint pt = dcubic_xy_at_t(pts, testT);
   1.360 +            double testSide = fTangentPart.pointDistance(pt);
   1.361 +            if (fabs(bestSide) < fabs(testSide)) {
   1.362 +                bestSide = testSide;
   1.363 +            }
   1.364 +        }
   1.365 +        fSide = -bestSide;  // compare sign only
   1.366 +        SkASSERT(fSide == 0 || fSide2 != 0);
   1.367 +        if (fComputed && dx() > 0 && approximately_zero(dy())) {
   1.368 +            SkDCubic origCurve; // can't use segment's curve in place since it may be flipped
   1.369 +            int last = fSegment->count() - 1;
   1.370 +            fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
   1.371 +            SkDCubicPair split = origCurve.chopAt(startT);
   1.372 +            SkLineParameters splitTan;
   1.373 +            splitTan.cubicEndPoints(fStart < fEnd ? split.second() : split.first());
   1.374 +            if (splitTan.dx() <= 0) {
   1.375 +                fUnorderable = true;
   1.376 +                fUnsortable = fSegment->isTiny(this);
   1.377 +                return;
   1.378 +            }
   1.379 +            // if one is < 0 and the other is >= 0
   1.380 +            if (dy() * splitTan.dy() < 0) {
   1.381 +                fUnorderable = true;
   1.382 +                fUnsortable = fSegment->isTiny(this);
   1.383 +                return;
   1.384 +            }
   1.385 +        }
   1.386 +        } break;
   1.387 +    default:
   1.388 +        SkASSERT(0);
   1.389 +    }
   1.390 +    if ((fUnsortable = approximately_zero(dx()) && approximately_zero(dy()))) {
   1.391 +        return;
   1.392 +    }
   1.393 +    if (fSegment->verb() == SkPath::kLine_Verb) {
   1.394 +        return;
   1.395 +    }
   1.396 +    SkASSERT(fStart != fEnd);
   1.397 +    int smaller = SkMin32(fStart, fEnd);
   1.398 +    int larger = SkMax32(fStart, fEnd);
   1.399 +    while (smaller < larger && fSegment->span(smaller).fTiny) {
   1.400 +        ++smaller;
   1.401 +    }
   1.402 +    if (precisely_equal(fSegment->span(smaller).fT, fSegment->span(larger).fT)) {
   1.403 +    #if DEBUG_UNSORTABLE
   1.404 +        SkPoint iPt = fSegment->xyAtT(fStart);
   1.405 +        SkPoint ePt = fSegment->xyAtT(fEnd);
   1.406 +        SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
   1.407 +            fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
   1.408 +    #endif
   1.409 +        fUnsortable = true;
   1.410 +        return;
   1.411 +    }
   1.412 +    fUnsortable = fStart < fEnd ? fSegment->span(smaller).fUnsortableStart
   1.413 +            : fSegment->span(larger).fUnsortableEnd;
   1.414 +#if DEBUG_UNSORTABLE
   1.415 +    if (fUnsortable) {
   1.416 +        SkPoint iPt = fSegment->xyAtT(smaller);
   1.417 +        SkPoint ePt = fSegment->xyAtT(larger);
   1.418 +        SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
   1.419 +                smaller, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
   1.420 +    }
   1.421 +#endif
   1.422 +    return;
   1.423 +}
   1.424 +
   1.425 +#ifdef SK_DEBUG
   1.426 +void SkOpAngle::dump() const {
   1.427 +    const SkOpSpan& spanStart = fSegment->span(fStart);
   1.428 +    const SkOpSpan& spanEnd = fSegment->span(fEnd);
   1.429 +    const SkOpSpan& spanMin = fStart < fEnd ? spanStart : spanEnd;
   1.430 +    SkDebugf("id=%d (%1.9g,%1.9g) start=%d (%1.9g) end=%d (%1.9g) sumWind=",
   1.431 +            fSegment->debugID(), fSegment->xAtT(fStart), fSegment->yAtT(fStart),
   1.432 +            fStart, spanStart.fT, fEnd, spanEnd.fT);
   1.433 +    SkPathOpsDebug::WindingPrintf(spanMin.fWindSum);
   1.434 +    SkDebugf(" oppWind=");
   1.435 +    SkPathOpsDebug::WindingPrintf(spanMin.fOppSum),
   1.436 +    SkDebugf(" done=%d\n", spanMin.fDone);
   1.437 +}
   1.438 +#endif

mercurial