#include "src/pathops/SkOpCoincidence.h"
#include "src/pathops/SkOpSegment.h"
#include "src/pathops/SkPathOpsTSect.h"
#include <utility>
namespace pk {
bool SkCoincidentSpans::collapsed(const SkOpPtT* test) const {
return (fCoinPtTStart == test && fCoinPtTEnd->contains(test))
|| (fCoinPtTEnd == test && fCoinPtTStart->contains(test))
|| (fOppPtTStart == test && fOppPtTEnd->contains(test))
|| (fOppPtTEnd == test && fOppPtTStart->contains(test));
}
const SkOpPtT* SkCoincidentSpans::coinPtTEnd() const {
return fCoinPtTEnd;
}
const SkOpPtT* SkCoincidentSpans::coinPtTStart() const {
return fCoinPtTStart;
}
void SkCoincidentSpans::correctOneEnd(
const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) {
const SkOpPtT* origPtT = (this->*getEnd)();
const SkOpSpanBase* origSpan = origPtT->span();
const SkOpSpan* prev = origSpan->prev();
const SkOpPtT* testPtT = prev ? prev->next()->ptT()
: origSpan->upCast()->next()->prev()->ptT();
if (origPtT != testPtT) {
(this->*setEnd)(testPtT);
}
}
void SkCoincidentSpans::correctEnds() {
this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart);
this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd);
this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart);
this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd);
}
bool SkCoincidentSpans::expand() {
bool expanded = false;
const SkOpSegment* segment = coinPtTStart()->segment();
const SkOpSegment* oppSegment = oppPtTStart()->segment();
do {
const SkOpSpan* start = coinPtTStart()->span()->upCast();
const SkOpSpan* prev = start->prev();
const SkOpPtT* oppPtT;
if (!prev || !(oppPtT = prev->contains(oppSegment))) {
break;
}
double midT = (prev->t() + start->t()) / 2;
if (!segment->isClose(midT, oppSegment)) {
break;
}
setStarts(prev->ptT(), oppPtT);
expanded = true;
} while (true);
do {
const SkOpSpanBase* end = coinPtTEnd()->span();
SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
if (next && next->deleted()) {
break;
}
const SkOpPtT* oppPtT;
if (!next || !(oppPtT = next->contains(oppSegment))) {
break;
}
double midT = (end->t() + next->t()) / 2;
if (!segment->isClose(midT, oppSegment)) {
break;
}
setEnds(next->ptT(), oppPtT);
expanded = true;
} while (true);
return expanded;
}
bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
bool result = false;
if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped()
? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStart->fT)) {
this->setStarts(coinPtTStart, oppPtTStart);
result = true;
}
if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped()
? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) {
this->setEnds(coinPtTEnd, oppPtTEnd);
result = true;
}
return result;
}
void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart,
const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
PkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
fNext = next;
this->setStarts(coinPtTStart, oppPtTStart);
this->setEnds(coinPtTEnd, oppPtTEnd);
}
bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const {
if (s->fT > e->fT) {
using std::swap;
swap(s, e);
}
if (s->segment() == fCoinPtTStart->segment()) {
return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT;
} else {
PkASSERT(s->segment() == fOppPtTStart->segment());
double oppTs = fOppPtTStart->fT;
double oppTe = fOppPtTEnd->fT;
if (oppTs > oppTe) {
using std::swap;
swap(oppTs, oppTe);
}
return oppTs <= s->fT && e->fT <= oppTe;
}
}
const SkOpPtT* SkCoincidentSpans::oppPtTStart() const {
return fOppPtTStart;
}
const SkOpPtT* SkCoincidentSpans::oppPtTEnd() const {
return fOppPtTEnd;
}
bool SkCoincidentSpans::ordered(bool* result) const {
const SkOpSpanBase* start = this->coinPtTStart()->span();
const SkOpSpanBase* end = this->coinPtTEnd()->span();
const SkOpSpanBase* next = start->upCast()->next();
if (next == end) {
*result = true;
return true;
}
bool flipped = this->flipped();
const SkOpSegment* oppSeg = this->oppPtTStart()->segment();
double oppLastT = fOppPtTStart->fT;
do {
const SkOpPtT* opp = next->contains(oppSeg);
if (!opp) {
return false;
}
if ((oppLastT > opp->fT) != flipped) {
*result = false;
return true;
}
oppLastT = opp->fT;
if (next == end) {
break;
}
if (!next->upCastable()) {
*result = false;
return true;
}
next = next->upCast()->next();
} while (true);
*result = true;
return true;
}
bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
SkCoincidentSpans* test = fHead;
if (!test) {
return false;
}
const SkOpSegment* coinSeg = coinPtTStart->segment();
const SkOpSegment* oppSeg = oppPtTStart->segment();
if (!Ordered(coinPtTStart, oppPtTStart)) {
using std::swap;
swap(coinSeg, oppSeg);
swap(coinPtTStart, oppPtTStart);
swap(coinPtTEnd, oppPtTEnd);
if (coinPtTStart->fT > coinPtTEnd->fT) {
swap(coinPtTStart, coinPtTEnd);
swap(oppPtTStart, oppPtTEnd);
}
}
double oppMinT = std::min(oppPtTStart->fT, oppPtTEnd->fT);
PkDEBUGCODE(double oppMaxT = std::max(oppPtTStart->fT, oppPtTEnd->fT));
do {
if (coinSeg != test->coinPtTStart()->segment()) {
continue;
}
if (oppSeg != test->oppPtTStart()->segment()) {
continue;
}
double oTestMinT = std::min(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
double oTestMaxT = std::max(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
PkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
|| coinPtTEnd->fT > test->coinPtTEnd()->fT
|| oTestMinT > oppMinT || oppMaxT > oTestMaxT);
if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
&& coinPtTStart->fT <= test->coinPtTEnd()->fT)
|| (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
return true;
}
} while ((test = test->next()));
return false;
}
static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart,
const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
#if DEBUG_COINCIDENCE
while (check) {
PkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
|| check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
PkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
|| check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
check = check->next();
}
#endif
}
void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
SkOpPtT* oppPtTEnd) {
if (!Ordered(coinPtTStart, oppPtTStart)) {
if (oppPtTStart->fT < oppPtTEnd->fT) {
this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
} else {
this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
}
return;
}
PkASSERT(Ordered(coinPtTStart, oppPtTStart));
coinPtTStart = coinPtTStart->span()->ptT();
coinPtTEnd = coinPtTEnd->span()->ptT();
oppPtTStart = oppPtTStart->span()->ptT();
oppPtTEnd = oppPtTEnd->span()->ptT();
PkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT);
PkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT);
PkOPASSERT(!coinPtTStart->deleted());
PkOPASSERT(!coinPtTEnd->deleted());
PkOPASSERT(!oppPtTStart->deleted());
PkOPASSERT(!oppPtTEnd->deleted());
DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
SkCoincidentSpans* coinRec = this->globalState()->allocator()->make<SkCoincidentSpans>();
coinRec->init(PkDEBUGCODE(fGlobalState));
coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
fHead = coinRec;
}
bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
const SkOpPtT* testPtT = testSpan->ptT();
const SkOpPtT* stopPtT = testPtT;
const SkOpSegment* baseSeg = base->segment();
int escapeHatch = 100000; while ((testPtT = testPtT->next()) != stopPtT) {
if (--escapeHatch <= 0) {
return false; }
const SkOpSegment* testSeg = testPtT->segment();
if (testPtT->deleted()) {
continue;
}
if (testSeg == baseSeg) {
continue;
}
if (testPtT->span()->ptT() != testPtT) {
continue;
}
if (this->contains(baseSeg, testSeg, testPtT->fT)) {
continue;
}
SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
const SkPoint& pt = base->pt();
SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
SkIntersections i PkDEBUGCODE((this->globalState()));
(*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
for (int index = 0; index < i.used(); ++index) {
double t = i[0][index];
if (!between(0, t, 1)) {
continue;
}
SkDPoint oppPt = i.pt(index);
if (!oppPt.approximatelyEqual(pt)) {
continue;
}
SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
SkOpPtT* oppStart = writableSeg->addT(t);
if (oppStart == testPtT) {
continue;
}
SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
oppStart->span()->addOpp(writableBase);
if (oppStart->deleted()) {
continue;
}
SkOpSegment* coinSeg = base->segment();
SkOpSegment* oppSeg = oppStart->segment();
double coinTs, coinTe, oppTs, oppTe;
if (Ordered(coinSeg, oppSeg)) {
coinTs = base->t();
coinTe = testSpan->t();
oppTs = oppStart->fT;
oppTe = testPtT->fT;
} else {
using std::swap;
swap(coinSeg, oppSeg);
coinTs = oppStart->fT;
coinTe = testPtT->fT;
oppTs = base->t();
oppTe = testSpan->t();
}
if (coinTs > coinTe) {
using std::swap;
swap(coinTs, coinTe);
swap(oppTs, oppTe);
}
bool added;
FAIL_IF(!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added));
}
}
return true;
}
bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
FAIL_IF(!ptT->span()->upCastable());
const SkOpSpan* base = ptT->span()->upCast();
const SkOpSpan* prev = base->prev();
FAIL_IF(!prev);
if (!prev->isCanceled()) {
if (!this->addEndMovedSpans(base, base->prev())) {
return false;
}
}
if (!base->isCanceled()) {
if (!this->addEndMovedSpans(base, base->next())) {
return false;
}
}
return true;
}
bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* span = fHead;
if (!span) {
return true;
}
fTop = span;
fHead = nullptr;
do {
if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
FAIL_IF(1 == span->coinPtTStart()->fT);
bool onEnd = span->coinPtTStart()->fT == 0;
bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
if (onEnd) {
if (!oOnEnd) { if (!this->addEndMovedSpans(span->oppPtTStart())) {
return false;
}
}
} else if (oOnEnd) {
if (!this->addEndMovedSpans(span->coinPtTStart())) {
return false;
}
}
}
if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
bool onEnd = span->coinPtTEnd()->fT == 1;
bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
if (onEnd) {
if (!oOnEnd) {
if (!this->addEndMovedSpans(span->oppPtTEnd())) {
return false;
}
}
} else if (oOnEnd) {
if (!this->addEndMovedSpans(span->coinPtTEnd())) {
return false;
}
}
}
} while ((span = span->next()));
this->restoreHead();
return true;
}
bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = this->fHead;
if (!coin) {
return true;
}
do {
const SkOpPtT* startPtT = coin->coinPtTStart();
const SkOpPtT* oStartPtT = coin->oppPtTStart();
double priorT = startPtT->fT;
double oPriorT = oStartPtT->fT;
FAIL_IF(!startPtT->contains(oStartPtT));
PkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
const SkOpSpanBase* start = startPtT->span();
const SkOpSpanBase* oStart = oStartPtT->span();
const SkOpSpanBase* end = coin->coinPtTEnd()->span();
const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
FAIL_IF(oEnd->deleted());
FAIL_IF(!start->upCastable());
const SkOpSpanBase* test = start->upCast()->next();
FAIL_IF(!coin->flipped() && !oStart->upCastable());
const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
FAIL_IF(!oTest);
SkOpSegment* seg = start->segment();
SkOpSegment* oSeg = oStart->segment();
while (test != end || oTest != oEnd) {
const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
if (!containedOpp || !containedThis) {
double nextT, oNextT;
if (containedOpp) {
nextT = test->t();
oNextT = containedOpp->fT;
} else if (containedThis) {
nextT = containedThis->fT;
oNextT = oTest->t();
} else {
const SkOpSpanBase* walk = test;
const SkOpPtT* walkOpp;
do {
FAIL_IF(!walk->upCastable());
walk = walk->upCast()->next();
} while (!(walkOpp = walk->ptT()->contains(oSeg))
&& walk != coin->coinPtTEnd()->span());
FAIL_IF(!walkOpp);
nextT = walk->t();
oNextT = walkOpp->fT;
}
double startRange = nextT - priorT;
FAIL_IF(!startRange);
double startPart = (test->t() - priorT) / startRange;
double oStartRange = oNextT - oPriorT;
FAIL_IF(!oStartRange);
double oStartPart = (oTest->t() - oPriorT) / oStartRange;
FAIL_IF(startPart == oStartPart);
bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
: !!containedThis;
bool startOver = false;
bool success = addToOpp ? oSeg->addExpanded(
oPriorT + oStartRange * startPart, test, &startOver)
: seg->addExpanded(
priorT + startRange * oStartPart, oTest, &startOver);
FAIL_IF(!success);
if (startOver) {
test = start;
oTest = oStart;
}
end = coin->coinPtTEnd()->span();
oEnd = coin->oppPtTEnd()->span();
}
if (test != end) {
FAIL_IF(!test->upCastable());
priorT = test->t();
test = test->upCast()->next();
}
if (oTest != oEnd) {
oPriorT = oTest->t();
if (coin->flipped()) {
oTest = oTest->prev();
} else {
FAIL_IF(!oTest->upCastable());
oTest = oTest->upCast()->next();
}
FAIL_IF(!oTest);
}
}
} while ((coin = coin->next()));
return true;
}
double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
const SkOpSegment* coinSeg PkDEBUGPARAMS(const SkOpPtT* overE)) {
const SkOpSpanBase* work = overS->span();
const SkOpPtT* foundStart = nullptr;
const SkOpPtT* foundEnd = nullptr;
const SkOpPtT* coinStart = nullptr;
const SkOpPtT* coinEnd = nullptr;
do {
const SkOpPtT* contained = work->contains(coinSeg);
if (!contained) {
if (work->final()) {
break;
}
continue;
}
if (work->t() <= t) {
coinStart = contained;
foundStart = work->ptT();
}
if (work->t() >= t) {
coinEnd = contained;
foundEnd = work->ptT();
break;
}
PkASSERT(work->ptT() != overE);
} while ((work = work->upCast()->next()));
if (!coinStart || !coinEnd) {
return 1;
}
double denom = foundEnd->fT - foundStart->fT;
double sRatio = denom ? (t - foundStart->fT) / denom : 1;
return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
}
bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
double coinTs, double coinTe, double oppTs, double oppTe,
SkTDArray<SkCoincidentSpans*>* overlaps) const {
if (!Ordered(coinSeg, oppSeg)) {
if (oppTs < oppTe) {
return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
overlaps);
}
return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
}
bool swapOpp = oppTs > oppTe;
if (swapOpp) {
using std::swap;
swap(oppTs, oppTe);
}
do {
if (check->coinPtTStart()->segment() != coinSeg) {
continue;
}
if (check->oppPtTStart()->segment() != oppSeg) {
continue;
}
double checkTs = check->coinPtTStart()->fT;
double checkTe = check->coinPtTEnd()->fT;
bool coinOutside = coinTe < checkTs || coinTs > checkTe;
double oCheckTs = check->oppPtTStart()->fT;
double oCheckTe = check->oppPtTEnd()->fT;
if (swapOpp) {
if (oCheckTs <= oCheckTe) {
return false;
}
using std::swap;
swap(oCheckTs, oCheckTe);
}
bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
if (coinOutside && oppOutside) {
continue;
}
bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
if (coinInside && oppInside) { return false;
}
*overlaps->append() = check; } while ((check = check->next()));
return true;
}
bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
PkDEBUGPARAMS(const SkOpPtT* over1e) PkDEBUGPARAMS(const SkOpPtT* over2e)) {
PkASSERT(tStart < tEnd);
PkASSERT(over1s->fT < over1e->fT);
PkASSERT(between(over1s->fT, tStart, over1e->fT));
PkASSERT(between(over1s->fT, tEnd, over1e->fT));
PkASSERT(over2s->fT < over2e->fT);
PkASSERT(between(over2s->fT, tStart, over2e->fT));
PkASSERT(between(over2s->fT, tEnd, over2e->fT));
PkASSERT(over1s->segment() == over1e->segment());
PkASSERT(over2s->segment() == over2e->segment());
PkASSERT(over1s->segment() == over2s->segment());
PkASSERT(over1s->segment() != coinSeg);
PkASSERT(over1s->segment() != oppSeg);
PkASSERT(coinSeg != oppSeg);
double coinTs, coinTe, oppTs, oppTe;
coinTs = TRange(over1s, tStart, coinSeg PkDEBUGPARAMS(over1e));
coinTe = TRange(over1s, tEnd, coinSeg PkDEBUGPARAMS(over1e));
SkOpSpanBase::Collapsed result = coinSeg->collapsed(coinTs, coinTe);
if (SkOpSpanBase::Collapsed::kNo != result) {
return SkOpSpanBase::Collapsed::kYes == result;
}
oppTs = TRange(over2s, tStart, oppSeg PkDEBUGPARAMS(over2e));
oppTe = TRange(over2s, tEnd, oppSeg PkDEBUGPARAMS(over2e));
result = oppSeg->collapsed(oppTs, oppTe);
if (SkOpSpanBase::Collapsed::kNo != result) {
return SkOpSpanBase::Collapsed::kYes == result;
}
if (coinTs > coinTe) {
using std::swap;
swap(coinTs, coinTe);
swap(oppTs, oppTe);
}
(void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
return true;
}
bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
SkTDArray<SkCoincidentSpans*> overlaps;
FAIL_IF(!fTop);
if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
return true;
}
if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
coinTe, oppTs, oppTe, &overlaps)) {
return true;
}
SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
for (int index = 1; index < overlaps.count(); ++index) { SkCoincidentSpans* test = overlaps[index];
if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
overlap->setCoinPtTStart(test->coinPtTStart());
}
if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
overlap->setCoinPtTEnd(test->coinPtTEnd());
}
if (overlap->flipped()
? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
: overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
overlap->setOppPtTStart(test->oppPtTStart());
}
if (overlap->flipped()
? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
: overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
overlap->setOppPtTEnd(test->oppPtTEnd());
}
if (!fHead || !this->release(fHead, test)) {
PkAssertResult(this->release(fTop, test));
}
}
const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
if (overlap && cs && ce && overlap->contains(cs, ce)) {
return true;
}
FAIL_IF(cs == ce && cs);
const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
if (overlap && os && oe && overlap->contains(os, oe)) {
return true;
}
FAIL_IF(cs && cs->deleted());
FAIL_IF(os && os->deleted());
FAIL_IF(ce && ce->deleted());
FAIL_IF(oe && oe->deleted());
const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
FAIL_IF(csExisting && csExisting == ceExisting);
FAIL_IF(ceExisting && (ceExisting == cs ||
ceExisting->contains(csExisting ? csExisting : cs)));
const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
FAIL_IF(osExisting && osExisting == oeExisting);
FAIL_IF(osExisting && (osExisting == oe ||
osExisting->contains(oeExisting ? oeExisting : oe)));
FAIL_IF(oeExisting && (oeExisting == os ||
oeExisting->contains(osExisting ? osExisting : os)));
this->debugValidate();
if (!cs || !os) {
SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
: coinSeg->addT(coinTs);
if (csWritable == ce) {
return true;
}
SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
: oppSeg->addT(oppTs);
FAIL_IF(!csWritable || !osWritable);
csWritable->span()->addOpp(osWritable->span());
cs = csWritable;
os = osWritable->active();
FAIL_IF(!os);
FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
}
if (!ce || !oe) {
SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
: coinSeg->addT(coinTe);
SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
: oppSeg->addT(oppTe);
FAIL_IF(!ceWritable->span()->addOpp(oeWritable->span()));
ce = ceWritable;
oe = oeWritable;
}
this->debugValidate();
FAIL_IF(cs->deleted());
FAIL_IF(os->deleted());
FAIL_IF(ce->deleted());
FAIL_IF(oe->deleted());
FAIL_IF(cs->contains(ce) || os->contains(oe));
bool result = true;
if (overlap) {
if (overlap->coinPtTStart()->segment() == coinSeg) {
result = overlap->extend(cs, ce, os, oe);
} else {
if (os->fT > oe->fT) {
using std::swap;
swap(cs, ce);
swap(os, oe);
}
result = overlap->extend(os, oe, cs, ce);
}
#if DEBUG_COINCIDENCE_VERBOSE
if (result) {
overlaps[0]->debugShow();
}
#endif
} else {
this->add(cs, ce, os, oe);
#if DEBUG_COINCIDENCE_VERBOSE
fHead->debugShow();
#endif
}
this->debugValidate();
if (result) {
*added = true;
}
return true;
}
bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
SkCoincidentSpans* outer = fHead;
*added = false;
if (!outer) {
return true;
}
fTop = outer;
fHead = nullptr;
do {
const SkOpPtT* ocs = outer->coinPtTStart();
FAIL_IF(ocs->deleted());
const SkOpSegment* outerCoin = ocs->segment();
FAIL_IF(outerCoin->done());
const SkOpPtT* oos = outer->oppPtTStart();
if (oos->deleted()) {
return true;
}
const SkOpSegment* outerOpp = oos->segment();
PkOPASSERT(!outerOpp->done());
SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
SkCoincidentSpans* inner = outer;
while ((inner = inner->next())) {
this->debugValidate();
double overS, overE;
const SkOpPtT* ics = inner->coinPtTStart();
FAIL_IF(ics->deleted());
const SkOpSegment* innerCoin = ics->segment();
FAIL_IF(innerCoin->done());
const SkOpPtT* ios = inner->oppPtTStart();
FAIL_IF(ios->deleted());
const SkOpSegment* innerOpp = ios->segment();
PkOPASSERT(!innerOpp->done());
SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
if (outerCoin == innerCoin) {
const SkOpPtT* oce = outer->coinPtTEnd();
if (oce->deleted()) {
return true;
}
const SkOpPtT* ice = inner->coinPtTEnd();
FAIL_IF(ice->deleted());
if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
FAIL_IF(!this->addIfMissing(ocs->starter(oce), ics->starter(ice),
overS, overE, outerOppWritable, innerOppWritable, added
PkDEBUGPARAMS(ocs->debugEnder(oce))
PkDEBUGPARAMS(ics->debugEnder(ice))));
}
} else if (outerCoin == innerOpp) {
const SkOpPtT* oce = outer->coinPtTEnd();
FAIL_IF(oce->deleted());
const SkOpPtT* ioe = inner->oppPtTEnd();
FAIL_IF(ioe->deleted());
if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
FAIL_IF(!this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
overS, overE, outerOppWritable, innerCoinWritable, added
PkDEBUGPARAMS(ocs->debugEnder(oce))
PkDEBUGPARAMS(ios->debugEnder(ioe))));
}
} else if (outerOpp == innerCoin) {
const SkOpPtT* ooe = outer->oppPtTEnd();
FAIL_IF(ooe->deleted());
const SkOpPtT* ice = inner->coinPtTEnd();
FAIL_IF(ice->deleted());
PkASSERT(outerCoin != innerOpp);
if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
FAIL_IF(!this->addIfMissing(oos->starter(ooe), ics->starter(ice),
overS, overE, outerCoinWritable, innerOppWritable, added
PkDEBUGPARAMS(oos->debugEnder(ooe))
PkDEBUGPARAMS(ics->debugEnder(ice))));
}
} else if (outerOpp == innerOpp) {
const SkOpPtT* ooe = outer->oppPtTEnd();
FAIL_IF(ooe->deleted());
const SkOpPtT* ioe = inner->oppPtTEnd();
if (ioe->deleted()) {
return true;
}
PkASSERT(outerCoin != innerCoin);
if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
FAIL_IF(!this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
overS, overE, outerCoinWritable, innerCoinWritable, added
PkDEBUGPARAMS(oos->debugEnder(ooe))
PkDEBUGPARAMS(ios->debugEnder(ioe))));
}
}
this->debugValidate();
}
} while ((outer = outer->next()));
this->restoreHead();
return true;
}
bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
const SkOpSegment* seg2, const SkOpSegment* seg2o,
const SkOpPtT* overS, const SkOpPtT* overE) {
const SkOpPtT* s1 = overS->find(seg1);
const SkOpPtT* e1 = overE->find(seg1);
FAIL_IF(!s1);
FAIL_IF(!e1);
if (!s1->starter(e1)->span()->upCast()->windValue()) {
s1 = overS->find(seg1o);
e1 = overE->find(seg1o);
FAIL_IF(!s1);
FAIL_IF(!e1);
if (!s1->starter(e1)->span()->upCast()->windValue()) {
return true;
}
}
const SkOpPtT* s2 = overS->find(seg2);
const SkOpPtT* e2 = overE->find(seg2);
FAIL_IF(!s2);
FAIL_IF(!e2);
if (!s2->starter(e2)->span()->upCast()->windValue()) {
s2 = overS->find(seg2o);
e2 = overE->find(seg2o);
FAIL_IF(!s2);
FAIL_IF(!e2);
if (!s2->starter(e2)->span()->upCast()->windValue()) {
return true;
}
}
if (s1->segment() == s2->segment()) {
return true;
}
if (s1->fT > e1->fT) {
using std::swap;
swap(s1, e1);
swap(s2, e2);
}
this->add(s1, e1, s2, e2);
return true;
}
bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
if (this->contains(fHead, seg, opp, oppT)) {
return true;
}
if (this->contains(fTop, seg, opp, oppT)) {
return true;
}
return false;
}
bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
const SkOpSegment* opp, double oppT) const {
if (!coin) {
return false;
}
do {
if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
&& between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
return true;
}
if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
&& between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
return true;
}
} while ((coin = coin->next()));
return false;
}
bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
const SkCoincidentSpans* test = fHead;
if (!test) {
return false;
}
const SkOpSegment* coinSeg = coinPtTStart->segment();
const SkOpSegment* oppSeg = oppPtTStart->segment();
if (!Ordered(coinPtTStart, oppPtTStart)) {
using std::swap;
swap(coinSeg, oppSeg);
swap(coinPtTStart, oppPtTStart);
swap(coinPtTEnd, oppPtTEnd);
if (coinPtTStart->fT > coinPtTEnd->fT) {
swap(coinPtTStart, coinPtTEnd);
swap(oppPtTStart, oppPtTEnd);
}
}
double oppMinT = std::min(oppPtTStart->fT, oppPtTEnd->fT);
double oppMaxT = std::max(oppPtTStart->fT, oppPtTEnd->fT);
do {
if (coinSeg != test->coinPtTStart()->segment()) {
continue;
}
if (coinPtTStart->fT < test->coinPtTStart()->fT) {
continue;
}
if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
continue;
}
if (oppSeg != test->oppPtTStart()->segment()) {
continue;
}
if (oppMinT < std::min(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
continue;
}
if (oppMaxT > std::max(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
continue;
}
return true;
} while ((test = test->next()));
return false;
}
void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return;
}
do {
coin->correctEnds();
} while ((coin = coin->next()));
}
bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return true;
}
do {
SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
FAIL_IF(!startSpan->upCastable());
SkOpSpan* start = startSpan->upCast();
if (start->deleted()) {
continue;
}
const SkOpSpanBase* end = coin->coinPtTEnd()->span();
FAIL_IF(start != start->starter(end));
bool flipped = coin->flipped();
SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
: coin->oppPtTStartWritable())->span();
FAIL_IF(!oStartBase->upCastable());
SkOpSpan* oStart = oStartBase->upCast();
if (oStart->deleted()) {
continue;
}
const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
PkASSERT(oStart == oStart->starter(oEnd));
SkOpSegment* segment = start->segment();
SkOpSegment* oSegment = oStart->segment();
bool operandSwap = segment->operand() != oSegment->operand();
if (flipped) {
if (oEnd->deleted()) {
continue;
}
do {
SkOpSpanBase* oNext = oStart->next();
if (oNext == oEnd) {
break;
}
FAIL_IF(!oNext->upCastable());
oStart = oNext->upCast();
} while (true);
}
do {
int windValue = start->windValue();
int oppValue = start->oppValue();
int oWindValue = oStart->windValue();
int oOppValue = oStart->oppValue();
int windDiff = operandSwap ? oOppValue : oWindValue;
int oWindDiff = operandSwap ? oppValue : windValue;
if (!flipped) {
windDiff = -windDiff;
oWindDiff = -oWindDiff;
}
bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
&& oWindValue <= oWindDiff));
if (addToStart ? start->done() : oStart->done()) {
addToStart ^= true;
}
if (addToStart) {
if (operandSwap) {
using std::swap;
swap(oWindValue, oOppValue);
}
if (flipped) {
windValue -= oWindValue;
oppValue -= oOppValue;
} else {
windValue += oWindValue;
oppValue += oOppValue;
}
if (segment->isXor()) {
windValue &= 1;
}
if (segment->oppXor()) {
oppValue &= 1;
}
oWindValue = oOppValue = 0;
} else {
if (operandSwap) {
using std::swap;
swap(windValue, oppValue);
}
if (flipped) {
oWindValue -= windValue;
oOppValue -= oppValue;
} else {
oWindValue += windValue;
oOppValue += oppValue;
}
if (oSegment->isXor()) {
oWindValue &= 1;
}
if (oSegment->oppXor()) {
oOppValue &= 1;
}
windValue = oppValue = 0;
}
#if 0#endif
FAIL_IF(windValue <= -1);
start->setWindValue(windValue);
start->setOppValue(oppValue);
FAIL_IF(oWindValue <= -1);
oStart->setWindValue(oWindValue);
oStart->setOppValue(oOppValue);
if (!windValue && !oppValue) {
segment->markDone(start);
}
if (!oWindValue && !oOppValue) {
oSegment->markDone(oStart);
}
SkOpSpanBase* next = start->next();
SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
if (next == end) {
break;
}
FAIL_IF(!next->upCastable());
start = next->upCast();
if (!oNext || !oNext->upCastable()) {
oNext = oStart;
}
oStart = oNext->upCast();
} while (true);
} while ((coin = coin->next()));
return true;
}
bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
SkCoincidentSpans* head = coin;
SkCoincidentSpans* prev = nullptr;
SkCoincidentSpans* next;
do {
next = coin->next();
if (coin == remove) {
if (prev) {
prev->setNext(next);
} else if (head == fHead) {
fHead = next;
} else {
fTop = next;
}
break;
}
prev = coin;
} while ((coin = next));
return coin != nullptr;
}
void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
if (!coin) {
return;
}
SkCoincidentSpans* head = coin;
SkCoincidentSpans* prev = nullptr;
SkCoincidentSpans* next;
do {
next = coin->next();
if (coin->coinPtTStart()->deleted()) {
PkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
coin->oppPtTStart()->deleted());
if (prev) {
prev->setNext(next);
} else if (head == fHead) {
fHead = next;
} else {
fTop = next;
}
} else {
PkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
!coin->oppPtTStart()->deleted());
prev = coin;
}
} while ((coin = next));
}
void SkOpCoincidence::releaseDeleted() {
this->releaseDeleted(fHead);
this->releaseDeleted(fTop);
}
void SkOpCoincidence::restoreHead() {
SkCoincidentSpans** headPtr = &fHead;
while (*headPtr) {
headPtr = (*headPtr)->nextPtr();
}
*headPtr = fTop;
fTop = nullptr;
headPtr = &fHead;
while (*headPtr) {
SkCoincidentSpans* test = *headPtr;
if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
*headPtr = test->next();
continue;
}
headPtr = (*headPtr)->nextPtr();
}
}
bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return false;
}
bool expanded = false;
do {
if (coin->expand()) {
SkCoincidentSpans* test = fHead;
do {
if (coin == test) {
continue;
}
if (coin->coinPtTStart() == test->coinPtTStart()
&& coin->oppPtTStart() == test->oppPtTStart()) {
this->release(fHead, test);
break;
}
} while ((test = test->next()));
expanded = true;
}
} while ((coin = coin->next()));
return expanded;
}
bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
DEBUG_SET_PHASE();
overlaps->fHead = overlaps->fTop = nullptr;
SkCoincidentSpans* outer = fHead;
while (outer) {
const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
SkCoincidentSpans* inner = outer;
while ((inner = inner->next())) {
const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
if (outerCoin == innerCoin) {
continue; }
const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
const SkOpPtT* overlapS;
const SkOpPtT* overlapE;
if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
&overlapE))
|| (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
&overlapS, &overlapE))
|| (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
&overlapS, &overlapE))) {
if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
overlapS, overlapE)) {
return false;
}
}
}
outer = outer->next();
}
return true;
}
void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
PkOPASSERT(deleted != kept);
if (fHead) {
this->fixUp(fHead, deleted, kept);
}
if (fTop) {
this->fixUp(fTop, deleted, kept);
}
}
void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
SkCoincidentSpans* head = coin;
do {
if (coin->coinPtTStart() == deleted) {
if (coin->coinPtTEnd()->span() == kept->span()) {
this->release(head, coin);
continue;
}
coin->setCoinPtTStart(kept);
}
if (coin->coinPtTEnd() == deleted) {
if (coin->coinPtTStart()->span() == kept->span()) {
this->release(head, coin);
continue;
}
coin->setCoinPtTEnd(kept);
}
if (coin->oppPtTStart() == deleted) {
if (coin->oppPtTEnd()->span() == kept->span()) {
this->release(head, coin);
continue;
}
coin->setOppPtTStart(kept);
}
if (coin->oppPtTEnd() == deleted) {
if (coin->oppPtTStart()->span() == kept->span()) {
this->release(head, coin);
continue;
}
coin->setOppPtTEnd(kept);
}
} while ((coin = coin->next()));
}
bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return true;
}
do {
SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
FAIL_IF(!startBase->upCastable());
SkOpSpan* start = startBase->upCast();
FAIL_IF(start->deleted());
SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
PkOPASSERT(!end->deleted());
SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
PkOPASSERT(!oStart->deleted());
SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
FAIL_IF(oEnd->deleted());
bool flipped = coin->flipped();
if (flipped) {
using std::swap;
swap(oStart, oEnd);
}
FAIL_IF(!oStart->upCastable());
start->insertCoincidence(oStart->upCast());
end->insertCoinEnd(oEnd);
const SkOpSegment* segment = start->segment();
const SkOpSegment* oSegment = oStart->segment();
SkOpSpanBase* next = start;
SkOpSpanBase* oNext = oStart;
bool ordered;
FAIL_IF(!coin->ordered(&ordered));
while ((next = next->upCast()->next()) != end) {
FAIL_IF(!next->upCastable());
FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
}
while ((oNext = oNext->upCast()->next()) != oEnd) {
FAIL_IF(!oNext->upCastable());
FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
}
} while ((coin = coin->next()));
return true;
}
void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
SkCoincidentSpans* head = coin;
while (coin) {
if (coin->collapsed(test)) {
if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
coin->coinPtTStartWritable()->segment()->markAllDone();
}
if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
coin->oppPtTStartWritable()->segment()->markAllDone();
}
this->release(head, coin);
}
coin = coin->next();
}
}
void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
markCollapsed(fHead, test);
markCollapsed(fTop, test);
}
bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
if (coinSeg->verb() < oppSeg->verb()) {
return true;
}
if (coinSeg->verb() > oppSeg->verb()) {
return false;
}
int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
const SkScalar* cPt = &coinSeg->pts()[0].fX;
const SkScalar* oPt = &oppSeg->pts()[0].fX;
for (int index = 0; index < count; ++index) {
if (*cPt < *oPt) {
return true;
}
if (*cPt > *oPt) {
return false;
}
++cPt;
++oPt;
}
return true;
}
bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
PkASSERT(coin1s->segment() == coin2s->segment());
*overS = std::max(std::min(coin1s->fT, coin1e->fT), std::min(coin2s->fT, coin2e->fT));
*overE = std::min(std::max(coin1s->fT, coin1e->fT), std::max(coin2s->fT, coin2e->fT));
return *overS < *overE;
}
void SkOpCoincidence::release(const SkOpSegment* deleted) {
SkCoincidentSpans* coin = fHead;
if (!coin) {
return;
}
do {
if (coin->coinPtTStart()->segment() == deleted
|| coin->coinPtTEnd()->segment() == deleted
|| coin->oppPtTStart()->segment() == deleted
|| coin->oppPtTEnd()->segment() == deleted) {
this->release(fHead, coin);
}
} while ((coin = coin->next()));
}
}