/* * 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 "SkAddIntersections.h" #include "SkOpCoincidence.h" #include "SkPathOpsBounds.h" #include #if DEBUG_ADD_INTERSECTING_TS static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n", __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); if (pts == 2) { SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i[0][1], PT_DEBUG_DATA(i, 1)); } SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts())); if (pts == 2) { SkDebugf(" " T_DEBUG_STR(wnTs, 1), i[1][1]); } SkDebugf("\n"); } static void debugShowQuadLineIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n", __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowQuadIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n", __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowConicLineIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " CONIC_DEBUG_STR " " LINE_DEBUG_STR "\n", __FUNCTION__, CONIC_DEBUG_DATA(wt.pts(), wt.weight()), LINE_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CONIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], CONIC_DEBUG_DATA(wt.pts(), wt.weight()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowConicQuadIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " CONIC_DEBUG_STR " " QUAD_DEBUG_STR "\n", __FUNCTION__, CONIC_DEBUG_DATA(wt.pts(), wt.weight()), QUAD_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CONIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], CONIC_DEBUG_DATA(wt.pts(), wt.weight()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowConicIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " CONIC_DEBUG_STR " " CONIC_DEBUG_STR "\n", __FUNCTION__, CONIC_DEBUG_DATA(wt.pts(), wt.weight()), CONIC_DEBUG_DATA(wn.pts(), wn.weight())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CONIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], CONIC_DEBUG_DATA(wt.pts(), wt.weight()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " CONIC_DEBUG_STR, i[1][0], CONIC_DEBUG_DATA(wn.pts(), wn.weight())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowCubicLineIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n", __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowCubicQuadIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n", __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowCubicConicIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CONIC_DEBUG_STR "\n", __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CONIC_DEBUG_DATA(wn.pts(), wn.weight())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " CONIC_DEBUG_STR, i[1][0], CONIC_DEBUG_DATA(wn.pts(), wn.weight())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersectionHelper& wn, const SkIntersections& i) { SkASSERT(i.used() == pts); if (!pts) { SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n", __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts())); return; } SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); } SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts())); for (int n = 1; n < pts; ++n) { SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); } SkDebugf("\n"); } #else static void debugShowLineIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowQuadIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowConicLineIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowConicQuadIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowConicIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowCubicConicIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } static void debugShowCubicIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) { } #endif bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coincidence) { if (test != next) { if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) { return false; } // OPTIMIZATION: outset contour bounds a smidgen instead? if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) { return true; } } SkIntersectionHelper wt; wt.init(test); do { SkIntersectionHelper wn; wn.init(next); test->debugValidate(); next->debugValidate(); if (test == next && !wn.startAfter(wt)) { continue; } do { if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) { continue; } int pts = 0; SkIntersections ts { SkDEBUGCODE(test->globalState()) }; bool swap = false; SkDQuad quad1, quad2; SkDConic conic1, conic2; SkDCubic cubic1, cubic2; switch (wt.segmentType()) { case SkIntersectionHelper::kHorizontalLine_Segment: swap = true; switch (wn.segmentType()) { case SkIntersectionHelper::kHorizontalLine_Segment: case SkIntersectionHelper::kVerticalLine_Segment: case SkIntersectionHelper::kLine_Segment: pts = ts.lineHorizontal(wn.pts(), wt.left(), wt.right(), wt.y(), wt.xFlipped()); debugShowLineIntersection(pts, wn, wt, ts); break; case SkIntersectionHelper::kQuad_Segment: pts = ts.quadHorizontal(wn.pts(), wt.left(), wt.right(), wt.y(), wt.xFlipped()); debugShowQuadLineIntersection(pts, wn, wt, ts); break; case SkIntersectionHelper::kConic_Segment: pts = ts.conicHorizontal(wn.pts(), wn.weight(), wt.left(), wt.right(), wt.y(), wt.xFlipped()); debugShowConicLineIntersection(pts, wn, wt, ts); break; case SkIntersectionHelper::kCubic_Segment: pts = ts.cubicHorizontal(wn.pts(), wt.left(), wt.right(), wt.y(), wt.xFlipped()); debugShowCubicLineIntersection(pts, wn, wt, ts); break; default: SkASSERT(0); } break; case SkIntersectionHelper::kVerticalLine_Segment: swap = true; switch (wn.segmentType()) { case SkIntersectionHelper::kHorizontalLine_Segment: case SkIntersectionHelper::kVerticalLine_Segment: case SkIntersectionHelper::kLine_Segment: { pts = ts.lineVertical(wn.pts(), wt.top(), wt.bottom(), wt.x(), wt.yFlipped()); debugShowLineIntersection(pts, wn, wt, ts); break; } case SkIntersectionHelper::kQuad_Segment: { pts = ts.quadVertical(wn.pts(), wt.top(), wt.bottom(), wt.x(), wt.yFlipped()); debugShowQuadLineIntersection(pts, wn, wt, ts); break; } case SkIntersectionHelper::kConic_Segment: { pts = ts.conicVertical(wn.pts(), wn.weight(), wt.top(), wt.bottom(), wt.x(), wt.yFlipped()); debugShowConicLineIntersection(pts, wn, wt, ts); break; } case SkIntersectionHelper::kCubic_Segment: { pts = ts.cubicVertical(wn.pts(), wt.top(), wt.bottom(), wt.x(), wt.yFlipped()); debugShowCubicLineIntersection(pts, wn, wt, ts); break; } default: SkASSERT(0); } break; case SkIntersectionHelper::kLine_Segment: switch (wn.segmentType()) { case SkIntersectionHelper::kHorizontalLine_Segment: pts = ts.lineHorizontal(wt.pts(), wn.left(), wn.right(), wn.y(), wn.xFlipped()); debugShowLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kVerticalLine_Segment: pts = ts.lineVertical(wt.pts(), wn.top(), wn.bottom(), wn.x(), wn.yFlipped()); debugShowLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kLine_Segment: pts = ts.lineLine(wt.pts(), wn.pts()); debugShowLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kQuad_Segment: swap = true; pts = ts.quadLine(wn.pts(), wt.pts()); debugShowQuadLineIntersection(pts, wn, wt, ts); break; case SkIntersectionHelper::kConic_Segment: swap = true; pts = ts.conicLine(wn.pts(), wn.weight(), wt.pts()); debugShowConicLineIntersection(pts, wn, wt, ts); break; case SkIntersectionHelper::kCubic_Segment: swap = true; pts = ts.cubicLine(wn.pts(), wt.pts()); debugShowCubicLineIntersection(pts, wn, wt, ts); break; default: SkASSERT(0); } break; case SkIntersectionHelper::kQuad_Segment: switch (wn.segmentType()) { case SkIntersectionHelper::kHorizontalLine_Segment: pts = ts.quadHorizontal(wt.pts(), wn.left(), wn.right(), wn.y(), wn.xFlipped()); debugShowQuadLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kVerticalLine_Segment: pts = ts.quadVertical(wt.pts(), wn.top(), wn.bottom(), wn.x(), wn.yFlipped()); debugShowQuadLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kLine_Segment: pts = ts.quadLine(wt.pts(), wn.pts()); debugShowQuadLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kQuad_Segment: { pts = ts.intersect(quad1.set(wt.pts()), quad2.set(wn.pts())); debugShowQuadIntersection(pts, wt, wn, ts); break; } case SkIntersectionHelper::kConic_Segment: { swap = true; pts = ts.intersect(conic2.set(wn.pts(), wn.weight()), quad1.set(wt.pts())); debugShowConicQuadIntersection(pts, wn, wt, ts); break; } case SkIntersectionHelper::kCubic_Segment: { swap = true; pts = ts.intersect(cubic2.set(wn.pts()), quad1.set(wt.pts())); debugShowCubicQuadIntersection(pts, wn, wt, ts); break; } default: SkASSERT(0); } break; case SkIntersectionHelper::kConic_Segment: switch (wn.segmentType()) { case SkIntersectionHelper::kHorizontalLine_Segment: pts = ts.conicHorizontal(wt.pts(), wt.weight(), wn.left(), wn.right(), wn.y(), wn.xFlipped()); debugShowConicLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kVerticalLine_Segment: pts = ts.conicVertical(wt.pts(), wt.weight(), wn.top(), wn.bottom(), wn.x(), wn.yFlipped()); debugShowConicLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kLine_Segment: pts = ts.conicLine(wt.pts(), wt.weight(), wn.pts()); debugShowConicLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kQuad_Segment: { pts = ts.intersect(conic1.set(wt.pts(), wt.weight()), quad2.set(wn.pts())); debugShowConicQuadIntersection(pts, wt, wn, ts); break; } case SkIntersectionHelper::kConic_Segment: { pts = ts.intersect(conic1.set(wt.pts(), wt.weight()), conic2.set(wn.pts(), wn.weight())); debugShowConicIntersection(pts, wt, wn, ts); break; } case SkIntersectionHelper::kCubic_Segment: { swap = true; pts = ts.intersect(cubic2.set(wn.pts() SkDEBUGPARAMS(ts.globalState())), conic1.set(wt.pts(), wt.weight() SkDEBUGPARAMS(ts.globalState()))); debugShowCubicConicIntersection(pts, wn, wt, ts); break; } } break; case SkIntersectionHelper::kCubic_Segment: switch (wn.segmentType()) { case SkIntersectionHelper::kHorizontalLine_Segment: pts = ts.cubicHorizontal(wt.pts(), wn.left(), wn.right(), wn.y(), wn.xFlipped()); debugShowCubicLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kVerticalLine_Segment: pts = ts.cubicVertical(wt.pts(), wn.top(), wn.bottom(), wn.x(), wn.yFlipped()); debugShowCubicLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kLine_Segment: pts = ts.cubicLine(wt.pts(), wn.pts()); debugShowCubicLineIntersection(pts, wt, wn, ts); break; case SkIntersectionHelper::kQuad_Segment: { pts = ts.intersect(cubic1.set(wt.pts()), quad2.set(wn.pts())); debugShowCubicQuadIntersection(pts, wt, wn, ts); break; } case SkIntersectionHelper::kConic_Segment: { pts = ts.intersect(cubic1.set(wt.pts() SkDEBUGPARAMS(ts.globalState())), conic2.set(wn.pts(), wn.weight() SkDEBUGPARAMS(ts.globalState()))); debugShowCubicConicIntersection(pts, wt, wn, ts); break; } case SkIntersectionHelper::kCubic_Segment: { pts = ts.intersect(cubic1.set(wt.pts()), cubic2.set(wn.pts())); debugShowCubicIntersection(pts, wt, wn, ts); break; } default: SkASSERT(0); } break; default: SkASSERT(0); } #if DEBUG_T_SECT_LOOP_COUNT test->globalState()->debugAddLoopCount(&ts, wt, wn); #endif int coinIndex = -1; SkOpPtT* coinPtT[2]; for (int pt = 0; pt < pts; ++pt) { SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1); SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1); wt.segment()->debugValidate(); // if t value is used to compute pt in addT, error may creep in and // rect intersections may result in non-rects. if pt value from intersection // is passed in, current tests break. As a workaround, pass in pt // value from intersection only if pt.x and pt.y is integral SkPoint iPt = ts.pt(pt).asSkPoint(); bool iPtIsIntegral = iPt.fX == floor(iPt.fX) && iPt.fY == floor(iPt.fY); SkOpPtT* testTAt = iPtIsIntegral ? wt.segment()->addT(ts[swap][pt], iPt) : wt.segment()->addT(ts[swap][pt]); wn.segment()->debugValidate(); SkOpPtT* nextTAt = iPtIsIntegral ? wn.segment()->addT(ts[!swap][pt], iPt) : wn.segment()->addT(ts[!swap][pt]); if (!testTAt->contains(nextTAt)) { SkOpPtT* oppPrev = testTAt->oppPrev(nextTAt); // Returns nullptr if pair if (oppPrev) { // already share a pt-t loop. testTAt->span()->mergeMatches(nextTAt->span()); testTAt->addOpp(nextTAt, oppPrev); } if (testTAt->fPt != nextTAt->fPt) { testTAt->span()->unaligned(); nextTAt->span()->unaligned(); } wt.segment()->debugValidate(); wn.segment()->debugValidate(); } if (!ts.isCoincident(pt)) { continue; } if (coinIndex < 0) { coinPtT[0] = testTAt; coinPtT[1] = nextTAt; coinIndex = pt; continue; } if (coinPtT[0]->span() == testTAt->span()) { coinIndex = -1; continue; } if (coinPtT[1]->span() == nextTAt->span()) { coinIndex = -1; // coincidence span collapsed continue; } if (swap) { using std::swap; swap(coinPtT[0], coinPtT[1]); swap(testTAt, nextTAt); } SkASSERT(coincidence->globalState()->debugSkipAssert() || coinPtT[0]->span()->t() < testTAt->span()->t()); if (coinPtT[0]->span()->deleted()) { coinIndex = -1; continue; } if (testTAt->span()->deleted()) { coinIndex = -1; continue; } coincidence->add(coinPtT[0], testTAt, coinPtT[1], nextTAt); wt.segment()->debugValidate(); wn.segment()->debugValidate(); coinIndex = -1; } SkOPOBJASSERT(coincidence, coinIndex < 0); // expect coincidence to be paired } while (wn.advance()); } while (wt.advance()); return true; }