1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci#include "src/pathops/SkOpCoincidence.h" 8cb93a386Sopenharmony_ci#include "src/pathops/SkOpSegment.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsTSect.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include <utility> 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci// returns true if coincident span's start and end are the same 14cb93a386Sopenharmony_cibool SkCoincidentSpans::collapsed(const SkOpPtT* test) const { 15cb93a386Sopenharmony_ci return (fCoinPtTStart == test && fCoinPtTEnd->contains(test)) 16cb93a386Sopenharmony_ci || (fCoinPtTEnd == test && fCoinPtTStart->contains(test)) 17cb93a386Sopenharmony_ci || (fOppPtTStart == test && fOppPtTEnd->contains(test)) 18cb93a386Sopenharmony_ci || (fOppPtTEnd == test && fOppPtTStart->contains(test)); 19cb93a386Sopenharmony_ci} 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci// out of line since this function is referenced by address 22cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::coinPtTEnd() const { 23cb93a386Sopenharmony_ci return fCoinPtTEnd; 24cb93a386Sopenharmony_ci} 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci// out of line since this function is referenced by address 27cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::coinPtTStart() const { 28cb93a386Sopenharmony_ci return fCoinPtTStart; 29cb93a386Sopenharmony_ci} 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci// sets the span's end to the ptT referenced by the previous-next 32cb93a386Sopenharmony_civoid SkCoincidentSpans::correctOneEnd( 33cb93a386Sopenharmony_ci const SkOpPtT* (SkCoincidentSpans::* getEnd)() const, 34cb93a386Sopenharmony_ci void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) { 35cb93a386Sopenharmony_ci const SkOpPtT* origPtT = (this->*getEnd)(); 36cb93a386Sopenharmony_ci const SkOpSpanBase* origSpan = origPtT->span(); 37cb93a386Sopenharmony_ci const SkOpSpan* prev = origSpan->prev(); 38cb93a386Sopenharmony_ci const SkOpPtT* testPtT = prev ? prev->next()->ptT() 39cb93a386Sopenharmony_ci : origSpan->upCast()->next()->prev()->ptT(); 40cb93a386Sopenharmony_ci if (origPtT != testPtT) { 41cb93a386Sopenharmony_ci (this->*setEnd)(testPtT); 42cb93a386Sopenharmony_ci } 43cb93a386Sopenharmony_ci} 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci/* Please keep this in sync with debugCorrectEnds */ 46cb93a386Sopenharmony_ci// FIXME: member pointers have fallen out of favor and can be replaced with 47cb93a386Sopenharmony_ci// an alternative approach. 48cb93a386Sopenharmony_ci// makes all span ends agree with the segment's spans that define them 49cb93a386Sopenharmony_civoid SkCoincidentSpans::correctEnds() { 50cb93a386Sopenharmony_ci this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart); 51cb93a386Sopenharmony_ci this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd); 52cb93a386Sopenharmony_ci this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart); 53cb93a386Sopenharmony_ci this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd); 54cb93a386Sopenharmony_ci} 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci/* Please keep this in sync with debugExpand */ 57cb93a386Sopenharmony_ci// expand the range by checking adjacent spans for coincidence 58cb93a386Sopenharmony_cibool SkCoincidentSpans::expand() { 59cb93a386Sopenharmony_ci bool expanded = false; 60cb93a386Sopenharmony_ci const SkOpSegment* segment = coinPtTStart()->segment(); 61cb93a386Sopenharmony_ci const SkOpSegment* oppSegment = oppPtTStart()->segment(); 62cb93a386Sopenharmony_ci do { 63cb93a386Sopenharmony_ci const SkOpSpan* start = coinPtTStart()->span()->upCast(); 64cb93a386Sopenharmony_ci const SkOpSpan* prev = start->prev(); 65cb93a386Sopenharmony_ci const SkOpPtT* oppPtT; 66cb93a386Sopenharmony_ci if (!prev || !(oppPtT = prev->contains(oppSegment))) { 67cb93a386Sopenharmony_ci break; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci double midT = (prev->t() + start->t()) / 2; 70cb93a386Sopenharmony_ci if (!segment->isClose(midT, oppSegment)) { 71cb93a386Sopenharmony_ci break; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci setStarts(prev->ptT(), oppPtT); 74cb93a386Sopenharmony_ci expanded = true; 75cb93a386Sopenharmony_ci } while (true); 76cb93a386Sopenharmony_ci do { 77cb93a386Sopenharmony_ci const SkOpSpanBase* end = coinPtTEnd()->span(); 78cb93a386Sopenharmony_ci SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); 79cb93a386Sopenharmony_ci if (next && next->deleted()) { 80cb93a386Sopenharmony_ci break; 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci const SkOpPtT* oppPtT; 83cb93a386Sopenharmony_ci if (!next || !(oppPtT = next->contains(oppSegment))) { 84cb93a386Sopenharmony_ci break; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci double midT = (end->t() + next->t()) / 2; 87cb93a386Sopenharmony_ci if (!segment->isClose(midT, oppSegment)) { 88cb93a386Sopenharmony_ci break; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci setEnds(next->ptT(), oppPtT); 91cb93a386Sopenharmony_ci expanded = true; 92cb93a386Sopenharmony_ci } while (true); 93cb93a386Sopenharmony_ci return expanded; 94cb93a386Sopenharmony_ci} 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci// increase the range of this span 97cb93a386Sopenharmony_cibool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 98cb93a386Sopenharmony_ci const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { 99cb93a386Sopenharmony_ci bool result = false; 100cb93a386Sopenharmony_ci if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped() 101cb93a386Sopenharmony_ci ? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStart->fT)) { 102cb93a386Sopenharmony_ci this->setStarts(coinPtTStart, oppPtTStart); 103cb93a386Sopenharmony_ci result = true; 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped() 106cb93a386Sopenharmony_ci ? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) { 107cb93a386Sopenharmony_ci this->setEnds(coinPtTEnd, oppPtTEnd); 108cb93a386Sopenharmony_ci result = true; 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci return result; 111cb93a386Sopenharmony_ci} 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci// set the range of this span 114cb93a386Sopenharmony_civoid SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart, 115cb93a386Sopenharmony_ci const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { 116cb93a386Sopenharmony_ci SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart)); 117cb93a386Sopenharmony_ci fNext = next; 118cb93a386Sopenharmony_ci this->setStarts(coinPtTStart, oppPtTStart); 119cb93a386Sopenharmony_ci this->setEnds(coinPtTEnd, oppPtTEnd); 120cb93a386Sopenharmony_ci} 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci// returns true if both points are inside this 123cb93a386Sopenharmony_cibool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const { 124cb93a386Sopenharmony_ci if (s->fT > e->fT) { 125cb93a386Sopenharmony_ci using std::swap; 126cb93a386Sopenharmony_ci swap(s, e); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci if (s->segment() == fCoinPtTStart->segment()) { 129cb93a386Sopenharmony_ci return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT; 130cb93a386Sopenharmony_ci } else { 131cb93a386Sopenharmony_ci SkASSERT(s->segment() == fOppPtTStart->segment()); 132cb93a386Sopenharmony_ci double oppTs = fOppPtTStart->fT; 133cb93a386Sopenharmony_ci double oppTe = fOppPtTEnd->fT; 134cb93a386Sopenharmony_ci if (oppTs > oppTe) { 135cb93a386Sopenharmony_ci using std::swap; 136cb93a386Sopenharmony_ci swap(oppTs, oppTe); 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci return oppTs <= s->fT && e->fT <= oppTe; 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci} 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci// out of line since this function is referenced by address 143cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::oppPtTStart() const { 144cb93a386Sopenharmony_ci return fOppPtTStart; 145cb93a386Sopenharmony_ci} 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci// out of line since this function is referenced by address 148cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::oppPtTEnd() const { 149cb93a386Sopenharmony_ci return fOppPtTEnd; 150cb93a386Sopenharmony_ci} 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci// A coincident span is unordered if the pairs of points in the main and opposite curves' 153cb93a386Sopenharmony_ci// t values do not ascend or descend. For instance, if a tightly arced quadratic is 154cb93a386Sopenharmony_ci// coincident with another curve, it may intersect it out of order. 155cb93a386Sopenharmony_cibool SkCoincidentSpans::ordered(bool* result) const { 156cb93a386Sopenharmony_ci const SkOpSpanBase* start = this->coinPtTStart()->span(); 157cb93a386Sopenharmony_ci const SkOpSpanBase* end = this->coinPtTEnd()->span(); 158cb93a386Sopenharmony_ci const SkOpSpanBase* next = start->upCast()->next(); 159cb93a386Sopenharmony_ci if (next == end) { 160cb93a386Sopenharmony_ci *result = true; 161cb93a386Sopenharmony_ci return true; 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci bool flipped = this->flipped(); 164cb93a386Sopenharmony_ci const SkOpSegment* oppSeg = this->oppPtTStart()->segment(); 165cb93a386Sopenharmony_ci double oppLastT = fOppPtTStart->fT; 166cb93a386Sopenharmony_ci do { 167cb93a386Sopenharmony_ci const SkOpPtT* opp = next->contains(oppSeg); 168cb93a386Sopenharmony_ci if (!opp) { 169cb93a386Sopenharmony_ci// SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed 170cb93a386Sopenharmony_ci return false; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci if ((oppLastT > opp->fT) != flipped) { 173cb93a386Sopenharmony_ci *result = false; 174cb93a386Sopenharmony_ci return true; 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci oppLastT = opp->fT; 177cb93a386Sopenharmony_ci if (next == end) { 178cb93a386Sopenharmony_ci break; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci if (!next->upCastable()) { 181cb93a386Sopenharmony_ci *result = false; 182cb93a386Sopenharmony_ci return true; 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci next = next->upCast()->next(); 185cb93a386Sopenharmony_ci } while (true); 186cb93a386Sopenharmony_ci *result = true; 187cb93a386Sopenharmony_ci return true; 188cb93a386Sopenharmony_ci} 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci// if there is an existing pair that overlaps the addition, extend it 191cb93a386Sopenharmony_cibool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 192cb93a386Sopenharmony_ci const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { 193cb93a386Sopenharmony_ci SkCoincidentSpans* test = fHead; 194cb93a386Sopenharmony_ci if (!test) { 195cb93a386Sopenharmony_ci return false; 196cb93a386Sopenharmony_ci } 197cb93a386Sopenharmony_ci const SkOpSegment* coinSeg = coinPtTStart->segment(); 198cb93a386Sopenharmony_ci const SkOpSegment* oppSeg = oppPtTStart->segment(); 199cb93a386Sopenharmony_ci if (!Ordered(coinPtTStart, oppPtTStart)) { 200cb93a386Sopenharmony_ci using std::swap; 201cb93a386Sopenharmony_ci swap(coinSeg, oppSeg); 202cb93a386Sopenharmony_ci swap(coinPtTStart, oppPtTStart); 203cb93a386Sopenharmony_ci swap(coinPtTEnd, oppPtTEnd); 204cb93a386Sopenharmony_ci if (coinPtTStart->fT > coinPtTEnd->fT) { 205cb93a386Sopenharmony_ci swap(coinPtTStart, coinPtTEnd); 206cb93a386Sopenharmony_ci swap(oppPtTStart, oppPtTEnd); 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci double oppMinT = std::min(oppPtTStart->fT, oppPtTEnd->fT); 210cb93a386Sopenharmony_ci SkDEBUGCODE(double oppMaxT = std::max(oppPtTStart->fT, oppPtTEnd->fT)); 211cb93a386Sopenharmony_ci do { 212cb93a386Sopenharmony_ci if (coinSeg != test->coinPtTStart()->segment()) { 213cb93a386Sopenharmony_ci continue; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci if (oppSeg != test->oppPtTStart()->segment()) { 216cb93a386Sopenharmony_ci continue; 217cb93a386Sopenharmony_ci } 218cb93a386Sopenharmony_ci double oTestMinT = std::min(test->oppPtTStart()->fT, test->oppPtTEnd()->fT); 219cb93a386Sopenharmony_ci double oTestMaxT = std::max(test->oppPtTStart()->fT, test->oppPtTEnd()->fT); 220cb93a386Sopenharmony_ci // if debug check triggers, caller failed to check if extended already exists 221cb93a386Sopenharmony_ci SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT 222cb93a386Sopenharmony_ci || coinPtTEnd->fT > test->coinPtTEnd()->fT 223cb93a386Sopenharmony_ci || oTestMinT > oppMinT || oppMaxT > oTestMaxT); 224cb93a386Sopenharmony_ci if ((test->coinPtTStart()->fT <= coinPtTEnd->fT 225cb93a386Sopenharmony_ci && coinPtTStart->fT <= test->coinPtTEnd()->fT) 226cb93a386Sopenharmony_ci || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) { 227cb93a386Sopenharmony_ci test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 228cb93a386Sopenharmony_ci return true; 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci } while ((test = test->next())); 231cb93a386Sopenharmony_ci return false; 232cb93a386Sopenharmony_ci} 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci// verifies that the coincidence hasn't already been added 235cb93a386Sopenharmony_cistatic void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart, 236cb93a386Sopenharmony_ci const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { 237cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 238cb93a386Sopenharmony_ci while (check) { 239cb93a386Sopenharmony_ci SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd 240cb93a386Sopenharmony_ci || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd); 241cb93a386Sopenharmony_ci SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd 242cb93a386Sopenharmony_ci || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd); 243cb93a386Sopenharmony_ci check = check->next(); 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci#endif 246cb93a386Sopenharmony_ci} 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci// adds a new coincident pair 249cb93a386Sopenharmony_civoid SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, 250cb93a386Sopenharmony_ci SkOpPtT* oppPtTEnd) { 251cb93a386Sopenharmony_ci // OPTIMIZE: caller should have already sorted 252cb93a386Sopenharmony_ci if (!Ordered(coinPtTStart, oppPtTStart)) { 253cb93a386Sopenharmony_ci if (oppPtTStart->fT < oppPtTEnd->fT) { 254cb93a386Sopenharmony_ci this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd); 255cb93a386Sopenharmony_ci } else { 256cb93a386Sopenharmony_ci this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart); 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci return; 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci SkASSERT(Ordered(coinPtTStart, oppPtTStart)); 261cb93a386Sopenharmony_ci // choose the ptT at the front of the list to track 262cb93a386Sopenharmony_ci coinPtTStart = coinPtTStart->span()->ptT(); 263cb93a386Sopenharmony_ci coinPtTEnd = coinPtTEnd->span()->ptT(); 264cb93a386Sopenharmony_ci oppPtTStart = oppPtTStart->span()->ptT(); 265cb93a386Sopenharmony_ci oppPtTEnd = oppPtTEnd->span()->ptT(); 266cb93a386Sopenharmony_ci SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT); 267cb93a386Sopenharmony_ci SkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT); 268cb93a386Sopenharmony_ci SkOPASSERT(!coinPtTStart->deleted()); 269cb93a386Sopenharmony_ci SkOPASSERT(!coinPtTEnd->deleted()); 270cb93a386Sopenharmony_ci SkOPASSERT(!oppPtTStart->deleted()); 271cb93a386Sopenharmony_ci SkOPASSERT(!oppPtTEnd->deleted()); 272cb93a386Sopenharmony_ci DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 273cb93a386Sopenharmony_ci DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 274cb93a386Sopenharmony_ci SkCoincidentSpans* coinRec = this->globalState()->allocator()->make<SkCoincidentSpans>(); 275cb93a386Sopenharmony_ci coinRec->init(SkDEBUGCODE(fGlobalState)); 276cb93a386Sopenharmony_ci coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd); 277cb93a386Sopenharmony_ci fHead = coinRec; 278cb93a386Sopenharmony_ci} 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci// description below 281cb93a386Sopenharmony_cibool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) { 282cb93a386Sopenharmony_ci const SkOpPtT* testPtT = testSpan->ptT(); 283cb93a386Sopenharmony_ci const SkOpPtT* stopPtT = testPtT; 284cb93a386Sopenharmony_ci const SkOpSegment* baseSeg = base->segment(); 285cb93a386Sopenharmony_ci int escapeHatch = 100000; // this is 100 times larger than the debugLoopLimit test 286cb93a386Sopenharmony_ci while ((testPtT = testPtT->next()) != stopPtT) { 287cb93a386Sopenharmony_ci if (--escapeHatch <= 0) { 288cb93a386Sopenharmony_ci return false; // if triggered (likely by a fuzz-generated test) too complex to succeed 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci const SkOpSegment* testSeg = testPtT->segment(); 291cb93a386Sopenharmony_ci if (testPtT->deleted()) { 292cb93a386Sopenharmony_ci continue; 293cb93a386Sopenharmony_ci } 294cb93a386Sopenharmony_ci if (testSeg == baseSeg) { 295cb93a386Sopenharmony_ci continue; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci if (testPtT->span()->ptT() != testPtT) { 298cb93a386Sopenharmony_ci continue; 299cb93a386Sopenharmony_ci } 300cb93a386Sopenharmony_ci if (this->contains(baseSeg, testSeg, testPtT->fT)) { 301cb93a386Sopenharmony_ci continue; 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci // intersect perp with base->ptT() with testPtT->segment() 304cb93a386Sopenharmony_ci SkDVector dxdy = baseSeg->dSlopeAtT(base->t()); 305cb93a386Sopenharmony_ci const SkPoint& pt = base->pt(); 306cb93a386Sopenharmony_ci SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}}; 307cb93a386Sopenharmony_ci SkIntersections i SkDEBUGCODE((this->globalState())); 308cb93a386Sopenharmony_ci (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i); 309cb93a386Sopenharmony_ci for (int index = 0; index < i.used(); ++index) { 310cb93a386Sopenharmony_ci double t = i[0][index]; 311cb93a386Sopenharmony_ci if (!between(0, t, 1)) { 312cb93a386Sopenharmony_ci continue; 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci SkDPoint oppPt = i.pt(index); 315cb93a386Sopenharmony_ci if (!oppPt.approximatelyEqual(pt)) { 316cb93a386Sopenharmony_ci continue; 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg); 319cb93a386Sopenharmony_ci SkOpPtT* oppStart = writableSeg->addT(t); 320cb93a386Sopenharmony_ci if (oppStart == testPtT) { 321cb93a386Sopenharmony_ci continue; 322cb93a386Sopenharmony_ci } 323cb93a386Sopenharmony_ci SkOpSpan* writableBase = const_cast<SkOpSpan*>(base); 324cb93a386Sopenharmony_ci oppStart->span()->addOpp(writableBase); 325cb93a386Sopenharmony_ci if (oppStart->deleted()) { 326cb93a386Sopenharmony_ci continue; 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci SkOpSegment* coinSeg = base->segment(); 329cb93a386Sopenharmony_ci SkOpSegment* oppSeg = oppStart->segment(); 330cb93a386Sopenharmony_ci double coinTs, coinTe, oppTs, oppTe; 331cb93a386Sopenharmony_ci if (Ordered(coinSeg, oppSeg)) { 332cb93a386Sopenharmony_ci coinTs = base->t(); 333cb93a386Sopenharmony_ci coinTe = testSpan->t(); 334cb93a386Sopenharmony_ci oppTs = oppStart->fT; 335cb93a386Sopenharmony_ci oppTe = testPtT->fT; 336cb93a386Sopenharmony_ci } else { 337cb93a386Sopenharmony_ci using std::swap; 338cb93a386Sopenharmony_ci swap(coinSeg, oppSeg); 339cb93a386Sopenharmony_ci coinTs = oppStart->fT; 340cb93a386Sopenharmony_ci coinTe = testPtT->fT; 341cb93a386Sopenharmony_ci oppTs = base->t(); 342cb93a386Sopenharmony_ci oppTe = testSpan->t(); 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci if (coinTs > coinTe) { 345cb93a386Sopenharmony_ci using std::swap; 346cb93a386Sopenharmony_ci swap(coinTs, coinTe); 347cb93a386Sopenharmony_ci swap(oppTs, oppTe); 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci bool added; 350cb93a386Sopenharmony_ci FAIL_IF(!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)); 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci } 353cb93a386Sopenharmony_ci return true; 354cb93a386Sopenharmony_ci} 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci// description below 357cb93a386Sopenharmony_cibool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) { 358cb93a386Sopenharmony_ci FAIL_IF(!ptT->span()->upCastable()); 359cb93a386Sopenharmony_ci const SkOpSpan* base = ptT->span()->upCast(); 360cb93a386Sopenharmony_ci const SkOpSpan* prev = base->prev(); 361cb93a386Sopenharmony_ci FAIL_IF(!prev); 362cb93a386Sopenharmony_ci if (!prev->isCanceled()) { 363cb93a386Sopenharmony_ci if (!this->addEndMovedSpans(base, base->prev())) { 364cb93a386Sopenharmony_ci return false; 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci if (!base->isCanceled()) { 368cb93a386Sopenharmony_ci if (!this->addEndMovedSpans(base, base->next())) { 369cb93a386Sopenharmony_ci return false; 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci return true; 373cb93a386Sopenharmony_ci} 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci/* If A is coincident with B and B includes an endpoint, and A's matching point 376cb93a386Sopenharmony_ci is not the endpoint (i.e., there's an implied line connecting B-end and A) 377cb93a386Sopenharmony_ci then assume that the same implied line may intersect another curve close to B. 378cb93a386Sopenharmony_ci Since we only care about coincidence that was undetected, look at the 379cb93a386Sopenharmony_ci ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but 380cb93a386Sopenharmony_ci next door) and see if the A matching point is close enough to form another 381cb93a386Sopenharmony_ci coincident pair. If so, check for a new coincident span between B-end/A ptT loop 382cb93a386Sopenharmony_ci and the adjacent ptT loop. 383cb93a386Sopenharmony_ci*/ 384cb93a386Sopenharmony_cibool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 385cb93a386Sopenharmony_ci DEBUG_SET_PHASE(); 386cb93a386Sopenharmony_ci SkCoincidentSpans* span = fHead; 387cb93a386Sopenharmony_ci if (!span) { 388cb93a386Sopenharmony_ci return true; 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci fTop = span; 391cb93a386Sopenharmony_ci fHead = nullptr; 392cb93a386Sopenharmony_ci do { 393cb93a386Sopenharmony_ci if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) { 394cb93a386Sopenharmony_ci FAIL_IF(1 == span->coinPtTStart()->fT); 395cb93a386Sopenharmony_ci bool onEnd = span->coinPtTStart()->fT == 0; 396cb93a386Sopenharmony_ci bool oOnEnd = zero_or_one(span->oppPtTStart()->fT); 397cb93a386Sopenharmony_ci if (onEnd) { 398cb93a386Sopenharmony_ci if (!oOnEnd) { // if both are on end, any nearby intersect was already found 399cb93a386Sopenharmony_ci if (!this->addEndMovedSpans(span->oppPtTStart())) { 400cb93a386Sopenharmony_ci return false; 401cb93a386Sopenharmony_ci } 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci } else if (oOnEnd) { 404cb93a386Sopenharmony_ci if (!this->addEndMovedSpans(span->coinPtTStart())) { 405cb93a386Sopenharmony_ci return false; 406cb93a386Sopenharmony_ci } 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci } 409cb93a386Sopenharmony_ci if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) { 410cb93a386Sopenharmony_ci bool onEnd = span->coinPtTEnd()->fT == 1; 411cb93a386Sopenharmony_ci bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT); 412cb93a386Sopenharmony_ci if (onEnd) { 413cb93a386Sopenharmony_ci if (!oOnEnd) { 414cb93a386Sopenharmony_ci if (!this->addEndMovedSpans(span->oppPtTEnd())) { 415cb93a386Sopenharmony_ci return false; 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci } 418cb93a386Sopenharmony_ci } else if (oOnEnd) { 419cb93a386Sopenharmony_ci if (!this->addEndMovedSpans(span->coinPtTEnd())) { 420cb93a386Sopenharmony_ci return false; 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci } 423cb93a386Sopenharmony_ci } 424cb93a386Sopenharmony_ci } while ((span = span->next())); 425cb93a386Sopenharmony_ci this->restoreHead(); 426cb93a386Sopenharmony_ci return true; 427cb93a386Sopenharmony_ci} 428cb93a386Sopenharmony_ci 429cb93a386Sopenharmony_ci/* Please keep this in sync with debugAddExpanded */ 430cb93a386Sopenharmony_ci// for each coincident pair, match the spans 431cb93a386Sopenharmony_ci// if the spans don't match, add the missing pt to the segment and loop it in the opposite span 432cb93a386Sopenharmony_cibool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 433cb93a386Sopenharmony_ci DEBUG_SET_PHASE(); 434cb93a386Sopenharmony_ci SkCoincidentSpans* coin = this->fHead; 435cb93a386Sopenharmony_ci if (!coin) { 436cb93a386Sopenharmony_ci return true; 437cb93a386Sopenharmony_ci } 438cb93a386Sopenharmony_ci do { 439cb93a386Sopenharmony_ci const SkOpPtT* startPtT = coin->coinPtTStart(); 440cb93a386Sopenharmony_ci const SkOpPtT* oStartPtT = coin->oppPtTStart(); 441cb93a386Sopenharmony_ci double priorT = startPtT->fT; 442cb93a386Sopenharmony_ci double oPriorT = oStartPtT->fT; 443cb93a386Sopenharmony_ci FAIL_IF(!startPtT->contains(oStartPtT)); 444cb93a386Sopenharmony_ci SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd())); 445cb93a386Sopenharmony_ci const SkOpSpanBase* start = startPtT->span(); 446cb93a386Sopenharmony_ci const SkOpSpanBase* oStart = oStartPtT->span(); 447cb93a386Sopenharmony_ci const SkOpSpanBase* end = coin->coinPtTEnd()->span(); 448cb93a386Sopenharmony_ci const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span(); 449cb93a386Sopenharmony_ci FAIL_IF(oEnd->deleted()); 450cb93a386Sopenharmony_ci FAIL_IF(!start->upCastable()); 451cb93a386Sopenharmony_ci const SkOpSpanBase* test = start->upCast()->next(); 452cb93a386Sopenharmony_ci FAIL_IF(!coin->flipped() && !oStart->upCastable()); 453cb93a386Sopenharmony_ci const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next(); 454cb93a386Sopenharmony_ci FAIL_IF(!oTest); 455cb93a386Sopenharmony_ci SkOpSegment* seg = start->segment(); 456cb93a386Sopenharmony_ci SkOpSegment* oSeg = oStart->segment(); 457cb93a386Sopenharmony_ci while (test != end || oTest != oEnd) { 458cb93a386Sopenharmony_ci const SkOpPtT* containedOpp = test->ptT()->contains(oSeg); 459cb93a386Sopenharmony_ci const SkOpPtT* containedThis = oTest->ptT()->contains(seg); 460cb93a386Sopenharmony_ci if (!containedOpp || !containedThis) { 461cb93a386Sopenharmony_ci // choose the ends, or the first common pt-t list shared by both 462cb93a386Sopenharmony_ci double nextT, oNextT; 463cb93a386Sopenharmony_ci if (containedOpp) { 464cb93a386Sopenharmony_ci nextT = test->t(); 465cb93a386Sopenharmony_ci oNextT = containedOpp->fT; 466cb93a386Sopenharmony_ci } else if (containedThis) { 467cb93a386Sopenharmony_ci nextT = containedThis->fT; 468cb93a386Sopenharmony_ci oNextT = oTest->t(); 469cb93a386Sopenharmony_ci } else { 470cb93a386Sopenharmony_ci // iterate through until a pt-t list found that contains the other 471cb93a386Sopenharmony_ci const SkOpSpanBase* walk = test; 472cb93a386Sopenharmony_ci const SkOpPtT* walkOpp; 473cb93a386Sopenharmony_ci do { 474cb93a386Sopenharmony_ci FAIL_IF(!walk->upCastable()); 475cb93a386Sopenharmony_ci walk = walk->upCast()->next(); 476cb93a386Sopenharmony_ci } while (!(walkOpp = walk->ptT()->contains(oSeg)) 477cb93a386Sopenharmony_ci && walk != coin->coinPtTEnd()->span()); 478cb93a386Sopenharmony_ci FAIL_IF(!walkOpp); 479cb93a386Sopenharmony_ci nextT = walk->t(); 480cb93a386Sopenharmony_ci oNextT = walkOpp->fT; 481cb93a386Sopenharmony_ci } 482cb93a386Sopenharmony_ci // use t ranges to guess which one is missing 483cb93a386Sopenharmony_ci double startRange = nextT - priorT; 484cb93a386Sopenharmony_ci FAIL_IF(!startRange); 485cb93a386Sopenharmony_ci double startPart = (test->t() - priorT) / startRange; 486cb93a386Sopenharmony_ci double oStartRange = oNextT - oPriorT; 487cb93a386Sopenharmony_ci FAIL_IF(!oStartRange); 488cb93a386Sopenharmony_ci double oStartPart = (oTest->t() - oPriorT) / oStartRange; 489cb93a386Sopenharmony_ci FAIL_IF(startPart == oStartPart); 490cb93a386Sopenharmony_ci bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart 491cb93a386Sopenharmony_ci : !!containedThis; 492cb93a386Sopenharmony_ci bool startOver = false; 493cb93a386Sopenharmony_ci bool success = addToOpp ? oSeg->addExpanded( 494cb93a386Sopenharmony_ci oPriorT + oStartRange * startPart, test, &startOver) 495cb93a386Sopenharmony_ci : seg->addExpanded( 496cb93a386Sopenharmony_ci priorT + startRange * oStartPart, oTest, &startOver); 497cb93a386Sopenharmony_ci FAIL_IF(!success); 498cb93a386Sopenharmony_ci if (startOver) { 499cb93a386Sopenharmony_ci test = start; 500cb93a386Sopenharmony_ci oTest = oStart; 501cb93a386Sopenharmony_ci } 502cb93a386Sopenharmony_ci end = coin->coinPtTEnd()->span(); 503cb93a386Sopenharmony_ci oEnd = coin->oppPtTEnd()->span(); 504cb93a386Sopenharmony_ci } 505cb93a386Sopenharmony_ci if (test != end) { 506cb93a386Sopenharmony_ci FAIL_IF(!test->upCastable()); 507cb93a386Sopenharmony_ci priorT = test->t(); 508cb93a386Sopenharmony_ci test = test->upCast()->next(); 509cb93a386Sopenharmony_ci } 510cb93a386Sopenharmony_ci if (oTest != oEnd) { 511cb93a386Sopenharmony_ci oPriorT = oTest->t(); 512cb93a386Sopenharmony_ci if (coin->flipped()) { 513cb93a386Sopenharmony_ci oTest = oTest->prev(); 514cb93a386Sopenharmony_ci } else { 515cb93a386Sopenharmony_ci FAIL_IF(!oTest->upCastable()); 516cb93a386Sopenharmony_ci oTest = oTest->upCast()->next(); 517cb93a386Sopenharmony_ci } 518cb93a386Sopenharmony_ci FAIL_IF(!oTest); 519cb93a386Sopenharmony_ci } 520cb93a386Sopenharmony_ci 521cb93a386Sopenharmony_ci } 522cb93a386Sopenharmony_ci } while ((coin = coin->next())); 523cb93a386Sopenharmony_ci return true; 524cb93a386Sopenharmony_ci} 525cb93a386Sopenharmony_ci 526cb93a386Sopenharmony_ci// given a t span, map the same range on the coincident span 527cb93a386Sopenharmony_ci/* 528cb93a386Sopenharmony_cithe curves may not scale linearly, so interpolation may only happen within known points 529cb93a386Sopenharmony_ciremap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s 530cb93a386Sopenharmony_cithen repeat to capture over1e 531cb93a386Sopenharmony_ci*/ 532cb93a386Sopenharmony_cidouble SkOpCoincidence::TRange(const SkOpPtT* overS, double t, 533cb93a386Sopenharmony_ci const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) { 534cb93a386Sopenharmony_ci const SkOpSpanBase* work = overS->span(); 535cb93a386Sopenharmony_ci const SkOpPtT* foundStart = nullptr; 536cb93a386Sopenharmony_ci const SkOpPtT* foundEnd = nullptr; 537cb93a386Sopenharmony_ci const SkOpPtT* coinStart = nullptr; 538cb93a386Sopenharmony_ci const SkOpPtT* coinEnd = nullptr; 539cb93a386Sopenharmony_ci do { 540cb93a386Sopenharmony_ci const SkOpPtT* contained = work->contains(coinSeg); 541cb93a386Sopenharmony_ci if (!contained) { 542cb93a386Sopenharmony_ci if (work->final()) { 543cb93a386Sopenharmony_ci break; 544cb93a386Sopenharmony_ci } 545cb93a386Sopenharmony_ci continue; 546cb93a386Sopenharmony_ci } 547cb93a386Sopenharmony_ci if (work->t() <= t) { 548cb93a386Sopenharmony_ci coinStart = contained; 549cb93a386Sopenharmony_ci foundStart = work->ptT(); 550cb93a386Sopenharmony_ci } 551cb93a386Sopenharmony_ci if (work->t() >= t) { 552cb93a386Sopenharmony_ci coinEnd = contained; 553cb93a386Sopenharmony_ci foundEnd = work->ptT(); 554cb93a386Sopenharmony_ci break; 555cb93a386Sopenharmony_ci } 556cb93a386Sopenharmony_ci SkASSERT(work->ptT() != overE); 557cb93a386Sopenharmony_ci } while ((work = work->upCast()->next())); 558cb93a386Sopenharmony_ci if (!coinStart || !coinEnd) { 559cb93a386Sopenharmony_ci return 1; 560cb93a386Sopenharmony_ci } 561cb93a386Sopenharmony_ci // while overS->fT <=t and overS contains coinSeg 562cb93a386Sopenharmony_ci double denom = foundEnd->fT - foundStart->fT; 563cb93a386Sopenharmony_ci double sRatio = denom ? (t - foundStart->fT) / denom : 1; 564cb93a386Sopenharmony_ci return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio; 565cb93a386Sopenharmony_ci} 566cb93a386Sopenharmony_ci 567cb93a386Sopenharmony_ci// return true if span overlaps existing and needs to adjust the coincident list 568cb93a386Sopenharmony_cibool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check, 569cb93a386Sopenharmony_ci const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, 570cb93a386Sopenharmony_ci double coinTs, double coinTe, double oppTs, double oppTe, 571cb93a386Sopenharmony_ci SkTDArray<SkCoincidentSpans*>* overlaps) const { 572cb93a386Sopenharmony_ci if (!Ordered(coinSeg, oppSeg)) { 573cb93a386Sopenharmony_ci if (oppTs < oppTe) { 574cb93a386Sopenharmony_ci return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe, 575cb93a386Sopenharmony_ci overlaps); 576cb93a386Sopenharmony_ci } 577cb93a386Sopenharmony_ci return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps); 578cb93a386Sopenharmony_ci } 579cb93a386Sopenharmony_ci bool swapOpp = oppTs > oppTe; 580cb93a386Sopenharmony_ci if (swapOpp) { 581cb93a386Sopenharmony_ci using std::swap; 582cb93a386Sopenharmony_ci swap(oppTs, oppTe); 583cb93a386Sopenharmony_ci } 584cb93a386Sopenharmony_ci do { 585cb93a386Sopenharmony_ci if (check->coinPtTStart()->segment() != coinSeg) { 586cb93a386Sopenharmony_ci continue; 587cb93a386Sopenharmony_ci } 588cb93a386Sopenharmony_ci if (check->oppPtTStart()->segment() != oppSeg) { 589cb93a386Sopenharmony_ci continue; 590cb93a386Sopenharmony_ci } 591cb93a386Sopenharmony_ci double checkTs = check->coinPtTStart()->fT; 592cb93a386Sopenharmony_ci double checkTe = check->coinPtTEnd()->fT; 593cb93a386Sopenharmony_ci bool coinOutside = coinTe < checkTs || coinTs > checkTe; 594cb93a386Sopenharmony_ci double oCheckTs = check->oppPtTStart()->fT; 595cb93a386Sopenharmony_ci double oCheckTe = check->oppPtTEnd()->fT; 596cb93a386Sopenharmony_ci if (swapOpp) { 597cb93a386Sopenharmony_ci if (oCheckTs <= oCheckTe) { 598cb93a386Sopenharmony_ci return false; 599cb93a386Sopenharmony_ci } 600cb93a386Sopenharmony_ci using std::swap; 601cb93a386Sopenharmony_ci swap(oCheckTs, oCheckTe); 602cb93a386Sopenharmony_ci } 603cb93a386Sopenharmony_ci bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe; 604cb93a386Sopenharmony_ci if (coinOutside && oppOutside) { 605cb93a386Sopenharmony_ci continue; 606cb93a386Sopenharmony_ci } 607cb93a386Sopenharmony_ci bool coinInside = coinTe <= checkTe && coinTs >= checkTs; 608cb93a386Sopenharmony_ci bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs; 609cb93a386Sopenharmony_ci if (coinInside && oppInside) { // already included, do nothing 610cb93a386Sopenharmony_ci return false; 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci *overlaps->append() = check; // partial overlap, extend existing entry 613cb93a386Sopenharmony_ci } while ((check = check->next())); 614cb93a386Sopenharmony_ci return true; 615cb93a386Sopenharmony_ci} 616cb93a386Sopenharmony_ci 617cb93a386Sopenharmony_ci/* Please keep this in sync with debugAddIfMissing() */ 618cb93a386Sopenharmony_ci// note that over1s, over1e, over2s, over2e are ordered 619cb93a386Sopenharmony_cibool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s, 620cb93a386Sopenharmony_ci double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added 621cb93a386Sopenharmony_ci SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) { 622cb93a386Sopenharmony_ci SkASSERT(tStart < tEnd); 623cb93a386Sopenharmony_ci SkASSERT(over1s->fT < over1e->fT); 624cb93a386Sopenharmony_ci SkASSERT(between(over1s->fT, tStart, over1e->fT)); 625cb93a386Sopenharmony_ci SkASSERT(between(over1s->fT, tEnd, over1e->fT)); 626cb93a386Sopenharmony_ci SkASSERT(over2s->fT < over2e->fT); 627cb93a386Sopenharmony_ci SkASSERT(between(over2s->fT, tStart, over2e->fT)); 628cb93a386Sopenharmony_ci SkASSERT(between(over2s->fT, tEnd, over2e->fT)); 629cb93a386Sopenharmony_ci SkASSERT(over1s->segment() == over1e->segment()); 630cb93a386Sopenharmony_ci SkASSERT(over2s->segment() == over2e->segment()); 631cb93a386Sopenharmony_ci SkASSERT(over1s->segment() == over2s->segment()); 632cb93a386Sopenharmony_ci SkASSERT(over1s->segment() != coinSeg); 633cb93a386Sopenharmony_ci SkASSERT(over1s->segment() != oppSeg); 634cb93a386Sopenharmony_ci SkASSERT(coinSeg != oppSeg); 635cb93a386Sopenharmony_ci double coinTs, coinTe, oppTs, oppTe; 636cb93a386Sopenharmony_ci coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e)); 637cb93a386Sopenharmony_ci coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e)); 638cb93a386Sopenharmony_ci SkOpSpanBase::Collapsed result = coinSeg->collapsed(coinTs, coinTe); 639cb93a386Sopenharmony_ci if (SkOpSpanBase::Collapsed::kNo != result) { 640cb93a386Sopenharmony_ci return SkOpSpanBase::Collapsed::kYes == result; 641cb93a386Sopenharmony_ci } 642cb93a386Sopenharmony_ci oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e)); 643cb93a386Sopenharmony_ci oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e)); 644cb93a386Sopenharmony_ci result = oppSeg->collapsed(oppTs, oppTe); 645cb93a386Sopenharmony_ci if (SkOpSpanBase::Collapsed::kNo != result) { 646cb93a386Sopenharmony_ci return SkOpSpanBase::Collapsed::kYes == result; 647cb93a386Sopenharmony_ci } 648cb93a386Sopenharmony_ci if (coinTs > coinTe) { 649cb93a386Sopenharmony_ci using std::swap; 650cb93a386Sopenharmony_ci swap(coinTs, coinTe); 651cb93a386Sopenharmony_ci swap(oppTs, oppTe); 652cb93a386Sopenharmony_ci } 653cb93a386Sopenharmony_ci (void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added); 654cb93a386Sopenharmony_ci return true; 655cb93a386Sopenharmony_ci} 656cb93a386Sopenharmony_ci 657cb93a386Sopenharmony_ci/* Please keep this in sync with debugAddOrOverlap() */ 658cb93a386Sopenharmony_ci// If this is called by addEndMovedSpans(), a returned false propogates out to an abort. 659cb93a386Sopenharmony_ci// If this is called by AddIfMissing(), a returned false indicates there was nothing to add 660cb93a386Sopenharmony_cibool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg, 661cb93a386Sopenharmony_ci double coinTs, double coinTe, double oppTs, double oppTe, bool* added) { 662cb93a386Sopenharmony_ci SkTDArray<SkCoincidentSpans*> overlaps; 663cb93a386Sopenharmony_ci FAIL_IF(!fTop); 664cb93a386Sopenharmony_ci if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) { 665cb93a386Sopenharmony_ci return true; 666cb93a386Sopenharmony_ci } 667cb93a386Sopenharmony_ci if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs, 668cb93a386Sopenharmony_ci coinTe, oppTs, oppTe, &overlaps)) { 669cb93a386Sopenharmony_ci return true; 670cb93a386Sopenharmony_ci } 671cb93a386Sopenharmony_ci SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr; 672cb93a386Sopenharmony_ci for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing 673cb93a386Sopenharmony_ci SkCoincidentSpans* test = overlaps[index]; 674cb93a386Sopenharmony_ci if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) { 675cb93a386Sopenharmony_ci overlap->setCoinPtTStart(test->coinPtTStart()); 676cb93a386Sopenharmony_ci } 677cb93a386Sopenharmony_ci if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) { 678cb93a386Sopenharmony_ci overlap->setCoinPtTEnd(test->coinPtTEnd()); 679cb93a386Sopenharmony_ci } 680cb93a386Sopenharmony_ci if (overlap->flipped() 681cb93a386Sopenharmony_ci ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT 682cb93a386Sopenharmony_ci : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) { 683cb93a386Sopenharmony_ci overlap->setOppPtTStart(test->oppPtTStart()); 684cb93a386Sopenharmony_ci } 685cb93a386Sopenharmony_ci if (overlap->flipped() 686cb93a386Sopenharmony_ci ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT 687cb93a386Sopenharmony_ci : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) { 688cb93a386Sopenharmony_ci overlap->setOppPtTEnd(test->oppPtTEnd()); 689cb93a386Sopenharmony_ci } 690cb93a386Sopenharmony_ci if (!fHead || !this->release(fHead, test)) { 691cb93a386Sopenharmony_ci SkAssertResult(this->release(fTop, test)); 692cb93a386Sopenharmony_ci } 693cb93a386Sopenharmony_ci } 694cb93a386Sopenharmony_ci const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg); 695cb93a386Sopenharmony_ci const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg); 696cb93a386Sopenharmony_ci if (overlap && cs && ce && overlap->contains(cs, ce)) { 697cb93a386Sopenharmony_ci return true; 698cb93a386Sopenharmony_ci } 699cb93a386Sopenharmony_ci FAIL_IF(cs == ce && cs); 700cb93a386Sopenharmony_ci const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg); 701cb93a386Sopenharmony_ci const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg); 702cb93a386Sopenharmony_ci if (overlap && os && oe && overlap->contains(os, oe)) { 703cb93a386Sopenharmony_ci return true; 704cb93a386Sopenharmony_ci } 705cb93a386Sopenharmony_ci FAIL_IF(cs && cs->deleted()); 706cb93a386Sopenharmony_ci FAIL_IF(os && os->deleted()); 707cb93a386Sopenharmony_ci FAIL_IF(ce && ce->deleted()); 708cb93a386Sopenharmony_ci FAIL_IF(oe && oe->deleted()); 709cb93a386Sopenharmony_ci const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr; 710cb93a386Sopenharmony_ci const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr; 711cb93a386Sopenharmony_ci FAIL_IF(csExisting && csExisting == ceExisting); 712cb93a386Sopenharmony_ci// FAIL_IF(csExisting && (csExisting == ce || 713cb93a386Sopenharmony_ci// csExisting->contains(ceExisting ? ceExisting : ce))); 714cb93a386Sopenharmony_ci FAIL_IF(ceExisting && (ceExisting == cs || 715cb93a386Sopenharmony_ci ceExisting->contains(csExisting ? csExisting : cs))); 716cb93a386Sopenharmony_ci const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr; 717cb93a386Sopenharmony_ci const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr; 718cb93a386Sopenharmony_ci FAIL_IF(osExisting && osExisting == oeExisting); 719cb93a386Sopenharmony_ci FAIL_IF(osExisting && (osExisting == oe || 720cb93a386Sopenharmony_ci osExisting->contains(oeExisting ? oeExisting : oe))); 721cb93a386Sopenharmony_ci FAIL_IF(oeExisting && (oeExisting == os || 722cb93a386Sopenharmony_ci oeExisting->contains(osExisting ? osExisting : os))); 723cb93a386Sopenharmony_ci // extra line in debug code 724cb93a386Sopenharmony_ci this->debugValidate(); 725cb93a386Sopenharmony_ci if (!cs || !os) { 726cb93a386Sopenharmony_ci SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs) 727cb93a386Sopenharmony_ci : coinSeg->addT(coinTs); 728cb93a386Sopenharmony_ci if (csWritable == ce) { 729cb93a386Sopenharmony_ci return true; 730cb93a386Sopenharmony_ci } 731cb93a386Sopenharmony_ci SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os) 732cb93a386Sopenharmony_ci : oppSeg->addT(oppTs); 733cb93a386Sopenharmony_ci FAIL_IF(!csWritable || !osWritable); 734cb93a386Sopenharmony_ci csWritable->span()->addOpp(osWritable->span()); 735cb93a386Sopenharmony_ci cs = csWritable; 736cb93a386Sopenharmony_ci os = osWritable->active(); 737cb93a386Sopenharmony_ci FAIL_IF(!os); 738cb93a386Sopenharmony_ci FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted())); 739cb93a386Sopenharmony_ci } 740cb93a386Sopenharmony_ci if (!ce || !oe) { 741cb93a386Sopenharmony_ci SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce) 742cb93a386Sopenharmony_ci : coinSeg->addT(coinTe); 743cb93a386Sopenharmony_ci SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe) 744cb93a386Sopenharmony_ci : oppSeg->addT(oppTe); 745cb93a386Sopenharmony_ci FAIL_IF(!ceWritable->span()->addOpp(oeWritable->span())); 746cb93a386Sopenharmony_ci ce = ceWritable; 747cb93a386Sopenharmony_ci oe = oeWritable; 748cb93a386Sopenharmony_ci } 749cb93a386Sopenharmony_ci this->debugValidate(); 750cb93a386Sopenharmony_ci FAIL_IF(cs->deleted()); 751cb93a386Sopenharmony_ci FAIL_IF(os->deleted()); 752cb93a386Sopenharmony_ci FAIL_IF(ce->deleted()); 753cb93a386Sopenharmony_ci FAIL_IF(oe->deleted()); 754cb93a386Sopenharmony_ci FAIL_IF(cs->contains(ce) || os->contains(oe)); 755cb93a386Sopenharmony_ci bool result = true; 756cb93a386Sopenharmony_ci if (overlap) { 757cb93a386Sopenharmony_ci if (overlap->coinPtTStart()->segment() == coinSeg) { 758cb93a386Sopenharmony_ci result = overlap->extend(cs, ce, os, oe); 759cb93a386Sopenharmony_ci } else { 760cb93a386Sopenharmony_ci if (os->fT > oe->fT) { 761cb93a386Sopenharmony_ci using std::swap; 762cb93a386Sopenharmony_ci swap(cs, ce); 763cb93a386Sopenharmony_ci swap(os, oe); 764cb93a386Sopenharmony_ci } 765cb93a386Sopenharmony_ci result = overlap->extend(os, oe, cs, ce); 766cb93a386Sopenharmony_ci } 767cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE 768cb93a386Sopenharmony_ci if (result) { 769cb93a386Sopenharmony_ci overlaps[0]->debugShow(); 770cb93a386Sopenharmony_ci } 771cb93a386Sopenharmony_ci#endif 772cb93a386Sopenharmony_ci } else { 773cb93a386Sopenharmony_ci this->add(cs, ce, os, oe); 774cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE 775cb93a386Sopenharmony_ci fHead->debugShow(); 776cb93a386Sopenharmony_ci#endif 777cb93a386Sopenharmony_ci } 778cb93a386Sopenharmony_ci this->debugValidate(); 779cb93a386Sopenharmony_ci if (result) { 780cb93a386Sopenharmony_ci *added = true; 781cb93a386Sopenharmony_ci } 782cb93a386Sopenharmony_ci return true; 783cb93a386Sopenharmony_ci} 784cb93a386Sopenharmony_ci 785cb93a386Sopenharmony_ci// Please keep this in sync with debugAddMissing() 786cb93a386Sopenharmony_ci/* detects overlaps of different coincident runs on same segment */ 787cb93a386Sopenharmony_ci/* does not detect overlaps for pairs without any segments in common */ 788cb93a386Sopenharmony_ci// returns true if caller should loop again 789cb93a386Sopenharmony_cibool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { 790cb93a386Sopenharmony_ci SkCoincidentSpans* outer = fHead; 791cb93a386Sopenharmony_ci *added = false; 792cb93a386Sopenharmony_ci if (!outer) { 793cb93a386Sopenharmony_ci return true; 794cb93a386Sopenharmony_ci } 795cb93a386Sopenharmony_ci fTop = outer; 796cb93a386Sopenharmony_ci fHead = nullptr; 797cb93a386Sopenharmony_ci do { 798cb93a386Sopenharmony_ci // addifmissing can modify the list that this is walking 799cb93a386Sopenharmony_ci // save head so that walker can iterate over old data unperturbed 800cb93a386Sopenharmony_ci // addifmissing adds to head freely then add saved head in the end 801cb93a386Sopenharmony_ci const SkOpPtT* ocs = outer->coinPtTStart(); 802cb93a386Sopenharmony_ci FAIL_IF(ocs->deleted()); 803cb93a386Sopenharmony_ci const SkOpSegment* outerCoin = ocs->segment(); 804cb93a386Sopenharmony_ci FAIL_IF(outerCoin->done()); 805cb93a386Sopenharmony_ci const SkOpPtT* oos = outer->oppPtTStart(); 806cb93a386Sopenharmony_ci if (oos->deleted()) { 807cb93a386Sopenharmony_ci return true; 808cb93a386Sopenharmony_ci } 809cb93a386Sopenharmony_ci const SkOpSegment* outerOpp = oos->segment(); 810cb93a386Sopenharmony_ci SkOPASSERT(!outerOpp->done()); 811cb93a386Sopenharmony_ci SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin); 812cb93a386Sopenharmony_ci SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp); 813cb93a386Sopenharmony_ci SkCoincidentSpans* inner = outer; 814cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_FUZZER 815cb93a386Sopenharmony_ci int safetyNet = 1000; 816cb93a386Sopenharmony_ci#endif 817cb93a386Sopenharmony_ci while ((inner = inner->next())) { 818cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_FUZZER 819cb93a386Sopenharmony_ci if (!--safetyNet) { 820cb93a386Sopenharmony_ci return false; 821cb93a386Sopenharmony_ci } 822cb93a386Sopenharmony_ci#endif 823cb93a386Sopenharmony_ci this->debugValidate(); 824cb93a386Sopenharmony_ci double overS, overE; 825cb93a386Sopenharmony_ci const SkOpPtT* ics = inner->coinPtTStart(); 826cb93a386Sopenharmony_ci FAIL_IF(ics->deleted()); 827cb93a386Sopenharmony_ci const SkOpSegment* innerCoin = ics->segment(); 828cb93a386Sopenharmony_ci FAIL_IF(innerCoin->done()); 829cb93a386Sopenharmony_ci const SkOpPtT* ios = inner->oppPtTStart(); 830cb93a386Sopenharmony_ci FAIL_IF(ios->deleted()); 831cb93a386Sopenharmony_ci const SkOpSegment* innerOpp = ios->segment(); 832cb93a386Sopenharmony_ci SkOPASSERT(!innerOpp->done()); 833cb93a386Sopenharmony_ci SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin); 834cb93a386Sopenharmony_ci SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp); 835cb93a386Sopenharmony_ci if (outerCoin == innerCoin) { 836cb93a386Sopenharmony_ci const SkOpPtT* oce = outer->coinPtTEnd(); 837cb93a386Sopenharmony_ci if (oce->deleted()) { 838cb93a386Sopenharmony_ci return true; 839cb93a386Sopenharmony_ci } 840cb93a386Sopenharmony_ci const SkOpPtT* ice = inner->coinPtTEnd(); 841cb93a386Sopenharmony_ci FAIL_IF(ice->deleted()); 842cb93a386Sopenharmony_ci if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) { 843cb93a386Sopenharmony_ci FAIL_IF(!this->addIfMissing(ocs->starter(oce), ics->starter(ice), 844cb93a386Sopenharmony_ci overS, overE, outerOppWritable, innerOppWritable, added 845cb93a386Sopenharmony_ci SkDEBUGPARAMS(ocs->debugEnder(oce)) 846cb93a386Sopenharmony_ci SkDEBUGPARAMS(ics->debugEnder(ice)))); 847cb93a386Sopenharmony_ci } 848cb93a386Sopenharmony_ci } else if (outerCoin == innerOpp) { 849cb93a386Sopenharmony_ci const SkOpPtT* oce = outer->coinPtTEnd(); 850cb93a386Sopenharmony_ci FAIL_IF(oce->deleted()); 851cb93a386Sopenharmony_ci const SkOpPtT* ioe = inner->oppPtTEnd(); 852cb93a386Sopenharmony_ci FAIL_IF(ioe->deleted()); 853cb93a386Sopenharmony_ci if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) { 854cb93a386Sopenharmony_ci FAIL_IF(!this->addIfMissing(ocs->starter(oce), ios->starter(ioe), 855cb93a386Sopenharmony_ci overS, overE, outerOppWritable, innerCoinWritable, added 856cb93a386Sopenharmony_ci SkDEBUGPARAMS(ocs->debugEnder(oce)) 857cb93a386Sopenharmony_ci SkDEBUGPARAMS(ios->debugEnder(ioe)))); 858cb93a386Sopenharmony_ci } 859cb93a386Sopenharmony_ci } else if (outerOpp == innerCoin) { 860cb93a386Sopenharmony_ci const SkOpPtT* ooe = outer->oppPtTEnd(); 861cb93a386Sopenharmony_ci FAIL_IF(ooe->deleted()); 862cb93a386Sopenharmony_ci const SkOpPtT* ice = inner->coinPtTEnd(); 863cb93a386Sopenharmony_ci FAIL_IF(ice->deleted()); 864cb93a386Sopenharmony_ci SkASSERT(outerCoin != innerOpp); 865cb93a386Sopenharmony_ci if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) { 866cb93a386Sopenharmony_ci FAIL_IF(!this->addIfMissing(oos->starter(ooe), ics->starter(ice), 867cb93a386Sopenharmony_ci overS, overE, outerCoinWritable, innerOppWritable, added 868cb93a386Sopenharmony_ci SkDEBUGPARAMS(oos->debugEnder(ooe)) 869cb93a386Sopenharmony_ci SkDEBUGPARAMS(ics->debugEnder(ice)))); 870cb93a386Sopenharmony_ci } 871cb93a386Sopenharmony_ci } else if (outerOpp == innerOpp) { 872cb93a386Sopenharmony_ci const SkOpPtT* ooe = outer->oppPtTEnd(); 873cb93a386Sopenharmony_ci FAIL_IF(ooe->deleted()); 874cb93a386Sopenharmony_ci const SkOpPtT* ioe = inner->oppPtTEnd(); 875cb93a386Sopenharmony_ci if (ioe->deleted()) { 876cb93a386Sopenharmony_ci return true; 877cb93a386Sopenharmony_ci } 878cb93a386Sopenharmony_ci SkASSERT(outerCoin != innerCoin); 879cb93a386Sopenharmony_ci if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) { 880cb93a386Sopenharmony_ci FAIL_IF(!this->addIfMissing(oos->starter(ooe), ios->starter(ioe), 881cb93a386Sopenharmony_ci overS, overE, outerCoinWritable, innerCoinWritable, added 882cb93a386Sopenharmony_ci SkDEBUGPARAMS(oos->debugEnder(ooe)) 883cb93a386Sopenharmony_ci SkDEBUGPARAMS(ios->debugEnder(ioe)))); 884cb93a386Sopenharmony_ci } 885cb93a386Sopenharmony_ci } 886cb93a386Sopenharmony_ci this->debugValidate(); 887cb93a386Sopenharmony_ci } 888cb93a386Sopenharmony_ci } while ((outer = outer->next())); 889cb93a386Sopenharmony_ci this->restoreHead(); 890cb93a386Sopenharmony_ci return true; 891cb93a386Sopenharmony_ci} 892cb93a386Sopenharmony_ci 893cb93a386Sopenharmony_cibool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o, 894cb93a386Sopenharmony_ci const SkOpSegment* seg2, const SkOpSegment* seg2o, 895cb93a386Sopenharmony_ci const SkOpPtT* overS, const SkOpPtT* overE) { 896cb93a386Sopenharmony_ci const SkOpPtT* s1 = overS->find(seg1); 897cb93a386Sopenharmony_ci const SkOpPtT* e1 = overE->find(seg1); 898cb93a386Sopenharmony_ci FAIL_IF(!s1); 899cb93a386Sopenharmony_ci FAIL_IF(!e1); 900cb93a386Sopenharmony_ci if (!s1->starter(e1)->span()->upCast()->windValue()) { 901cb93a386Sopenharmony_ci s1 = overS->find(seg1o); 902cb93a386Sopenharmony_ci e1 = overE->find(seg1o); 903cb93a386Sopenharmony_ci FAIL_IF(!s1); 904cb93a386Sopenharmony_ci FAIL_IF(!e1); 905cb93a386Sopenharmony_ci if (!s1->starter(e1)->span()->upCast()->windValue()) { 906cb93a386Sopenharmony_ci return true; 907cb93a386Sopenharmony_ci } 908cb93a386Sopenharmony_ci } 909cb93a386Sopenharmony_ci const SkOpPtT* s2 = overS->find(seg2); 910cb93a386Sopenharmony_ci const SkOpPtT* e2 = overE->find(seg2); 911cb93a386Sopenharmony_ci FAIL_IF(!s2); 912cb93a386Sopenharmony_ci FAIL_IF(!e2); 913cb93a386Sopenharmony_ci if (!s2->starter(e2)->span()->upCast()->windValue()) { 914cb93a386Sopenharmony_ci s2 = overS->find(seg2o); 915cb93a386Sopenharmony_ci e2 = overE->find(seg2o); 916cb93a386Sopenharmony_ci FAIL_IF(!s2); 917cb93a386Sopenharmony_ci FAIL_IF(!e2); 918cb93a386Sopenharmony_ci if (!s2->starter(e2)->span()->upCast()->windValue()) { 919cb93a386Sopenharmony_ci return true; 920cb93a386Sopenharmony_ci } 921cb93a386Sopenharmony_ci } 922cb93a386Sopenharmony_ci if (s1->segment() == s2->segment()) { 923cb93a386Sopenharmony_ci return true; 924cb93a386Sopenharmony_ci } 925cb93a386Sopenharmony_ci if (s1->fT > e1->fT) { 926cb93a386Sopenharmony_ci using std::swap; 927cb93a386Sopenharmony_ci swap(s1, e1); 928cb93a386Sopenharmony_ci swap(s2, e2); 929cb93a386Sopenharmony_ci } 930cb93a386Sopenharmony_ci this->add(s1, e1, s2, e2); 931cb93a386Sopenharmony_ci return true; 932cb93a386Sopenharmony_ci} 933cb93a386Sopenharmony_ci 934cb93a386Sopenharmony_cibool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const { 935cb93a386Sopenharmony_ci if (this->contains(fHead, seg, opp, oppT)) { 936cb93a386Sopenharmony_ci return true; 937cb93a386Sopenharmony_ci } 938cb93a386Sopenharmony_ci if (this->contains(fTop, seg, opp, oppT)) { 939cb93a386Sopenharmony_ci return true; 940cb93a386Sopenharmony_ci } 941cb93a386Sopenharmony_ci return false; 942cb93a386Sopenharmony_ci} 943cb93a386Sopenharmony_ci 944cb93a386Sopenharmony_cibool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg, 945cb93a386Sopenharmony_ci const SkOpSegment* opp, double oppT) const { 946cb93a386Sopenharmony_ci if (!coin) { 947cb93a386Sopenharmony_ci return false; 948cb93a386Sopenharmony_ci } 949cb93a386Sopenharmony_ci do { 950cb93a386Sopenharmony_ci if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp 951cb93a386Sopenharmony_ci && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) { 952cb93a386Sopenharmony_ci return true; 953cb93a386Sopenharmony_ci } 954cb93a386Sopenharmony_ci if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp 955cb93a386Sopenharmony_ci && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) { 956cb93a386Sopenharmony_ci return true; 957cb93a386Sopenharmony_ci } 958cb93a386Sopenharmony_ci } while ((coin = coin->next())); 959cb93a386Sopenharmony_ci return false; 960cb93a386Sopenharmony_ci} 961cb93a386Sopenharmony_ci 962cb93a386Sopenharmony_cibool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 963cb93a386Sopenharmony_ci const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const { 964cb93a386Sopenharmony_ci const SkCoincidentSpans* test = fHead; 965cb93a386Sopenharmony_ci if (!test) { 966cb93a386Sopenharmony_ci return false; 967cb93a386Sopenharmony_ci } 968cb93a386Sopenharmony_ci const SkOpSegment* coinSeg = coinPtTStart->segment(); 969cb93a386Sopenharmony_ci const SkOpSegment* oppSeg = oppPtTStart->segment(); 970cb93a386Sopenharmony_ci if (!Ordered(coinPtTStart, oppPtTStart)) { 971cb93a386Sopenharmony_ci using std::swap; 972cb93a386Sopenharmony_ci swap(coinSeg, oppSeg); 973cb93a386Sopenharmony_ci swap(coinPtTStart, oppPtTStart); 974cb93a386Sopenharmony_ci swap(coinPtTEnd, oppPtTEnd); 975cb93a386Sopenharmony_ci if (coinPtTStart->fT > coinPtTEnd->fT) { 976cb93a386Sopenharmony_ci swap(coinPtTStart, coinPtTEnd); 977cb93a386Sopenharmony_ci swap(oppPtTStart, oppPtTEnd); 978cb93a386Sopenharmony_ci } 979cb93a386Sopenharmony_ci } 980cb93a386Sopenharmony_ci double oppMinT = std::min(oppPtTStart->fT, oppPtTEnd->fT); 981cb93a386Sopenharmony_ci double oppMaxT = std::max(oppPtTStart->fT, oppPtTEnd->fT); 982cb93a386Sopenharmony_ci do { 983cb93a386Sopenharmony_ci if (coinSeg != test->coinPtTStart()->segment()) { 984cb93a386Sopenharmony_ci continue; 985cb93a386Sopenharmony_ci } 986cb93a386Sopenharmony_ci if (coinPtTStart->fT < test->coinPtTStart()->fT) { 987cb93a386Sopenharmony_ci continue; 988cb93a386Sopenharmony_ci } 989cb93a386Sopenharmony_ci if (coinPtTEnd->fT > test->coinPtTEnd()->fT) { 990cb93a386Sopenharmony_ci continue; 991cb93a386Sopenharmony_ci } 992cb93a386Sopenharmony_ci if (oppSeg != test->oppPtTStart()->segment()) { 993cb93a386Sopenharmony_ci continue; 994cb93a386Sopenharmony_ci } 995cb93a386Sopenharmony_ci if (oppMinT < std::min(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) { 996cb93a386Sopenharmony_ci continue; 997cb93a386Sopenharmony_ci } 998cb93a386Sopenharmony_ci if (oppMaxT > std::max(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) { 999cb93a386Sopenharmony_ci continue; 1000cb93a386Sopenharmony_ci } 1001cb93a386Sopenharmony_ci return true; 1002cb93a386Sopenharmony_ci } while ((test = test->next())); 1003cb93a386Sopenharmony_ci return false; 1004cb93a386Sopenharmony_ci} 1005cb93a386Sopenharmony_ci 1006cb93a386Sopenharmony_civoid SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 1007cb93a386Sopenharmony_ci DEBUG_SET_PHASE(); 1008cb93a386Sopenharmony_ci SkCoincidentSpans* coin = fHead; 1009cb93a386Sopenharmony_ci if (!coin) { 1010cb93a386Sopenharmony_ci return; 1011cb93a386Sopenharmony_ci } 1012cb93a386Sopenharmony_ci do { 1013cb93a386Sopenharmony_ci coin->correctEnds(); 1014cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1015cb93a386Sopenharmony_ci} 1016cb93a386Sopenharmony_ci 1017cb93a386Sopenharmony_ci// walk span sets in parallel, moving winding from one to the other 1018cb93a386Sopenharmony_cibool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 1019cb93a386Sopenharmony_ci DEBUG_SET_PHASE(); 1020cb93a386Sopenharmony_ci SkCoincidentSpans* coin = fHead; 1021cb93a386Sopenharmony_ci if (!coin) { 1022cb93a386Sopenharmony_ci return true; 1023cb93a386Sopenharmony_ci } 1024cb93a386Sopenharmony_ci do { 1025cb93a386Sopenharmony_ci SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span(); 1026cb93a386Sopenharmony_ci FAIL_IF(!startSpan->upCastable()); 1027cb93a386Sopenharmony_ci SkOpSpan* start = startSpan->upCast(); 1028cb93a386Sopenharmony_ci if (start->deleted()) { 1029cb93a386Sopenharmony_ci continue; 1030cb93a386Sopenharmony_ci } 1031cb93a386Sopenharmony_ci const SkOpSpanBase* end = coin->coinPtTEnd()->span(); 1032cb93a386Sopenharmony_ci FAIL_IF(start != start->starter(end)); 1033cb93a386Sopenharmony_ci bool flipped = coin->flipped(); 1034cb93a386Sopenharmony_ci SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable() 1035cb93a386Sopenharmony_ci : coin->oppPtTStartWritable())->span(); 1036cb93a386Sopenharmony_ci FAIL_IF(!oStartBase->upCastable()); 1037cb93a386Sopenharmony_ci SkOpSpan* oStart = oStartBase->upCast(); 1038cb93a386Sopenharmony_ci if (oStart->deleted()) { 1039cb93a386Sopenharmony_ci continue; 1040cb93a386Sopenharmony_ci } 1041cb93a386Sopenharmony_ci const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span(); 1042cb93a386Sopenharmony_ci SkASSERT(oStart == oStart->starter(oEnd)); 1043cb93a386Sopenharmony_ci SkOpSegment* segment = start->segment(); 1044cb93a386Sopenharmony_ci SkOpSegment* oSegment = oStart->segment(); 1045cb93a386Sopenharmony_ci bool operandSwap = segment->operand() != oSegment->operand(); 1046cb93a386Sopenharmony_ci if (flipped) { 1047cb93a386Sopenharmony_ci if (oEnd->deleted()) { 1048cb93a386Sopenharmony_ci continue; 1049cb93a386Sopenharmony_ci } 1050cb93a386Sopenharmony_ci do { 1051cb93a386Sopenharmony_ci SkOpSpanBase* oNext = oStart->next(); 1052cb93a386Sopenharmony_ci if (oNext == oEnd) { 1053cb93a386Sopenharmony_ci break; 1054cb93a386Sopenharmony_ci } 1055cb93a386Sopenharmony_ci FAIL_IF(!oNext->upCastable()); 1056cb93a386Sopenharmony_ci oStart = oNext->upCast(); 1057cb93a386Sopenharmony_ci } while (true); 1058cb93a386Sopenharmony_ci } 1059cb93a386Sopenharmony_ci do { 1060cb93a386Sopenharmony_ci int windValue = start->windValue(); 1061cb93a386Sopenharmony_ci int oppValue = start->oppValue(); 1062cb93a386Sopenharmony_ci int oWindValue = oStart->windValue(); 1063cb93a386Sopenharmony_ci int oOppValue = oStart->oppValue(); 1064cb93a386Sopenharmony_ci // winding values are added or subtracted depending on direction and wind type 1065cb93a386Sopenharmony_ci // same or opposite values are summed depending on the operand value 1066cb93a386Sopenharmony_ci int windDiff = operandSwap ? oOppValue : oWindValue; 1067cb93a386Sopenharmony_ci int oWindDiff = operandSwap ? oppValue : windValue; 1068cb93a386Sopenharmony_ci if (!flipped) { 1069cb93a386Sopenharmony_ci windDiff = -windDiff; 1070cb93a386Sopenharmony_ci oWindDiff = -oWindDiff; 1071cb93a386Sopenharmony_ci } 1072cb93a386Sopenharmony_ci bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff 1073cb93a386Sopenharmony_ci && oWindValue <= oWindDiff)); 1074cb93a386Sopenharmony_ci if (addToStart ? start->done() : oStart->done()) { 1075cb93a386Sopenharmony_ci addToStart ^= true; 1076cb93a386Sopenharmony_ci } 1077cb93a386Sopenharmony_ci if (addToStart) { 1078cb93a386Sopenharmony_ci if (operandSwap) { 1079cb93a386Sopenharmony_ci using std::swap; 1080cb93a386Sopenharmony_ci swap(oWindValue, oOppValue); 1081cb93a386Sopenharmony_ci } 1082cb93a386Sopenharmony_ci if (flipped) { 1083cb93a386Sopenharmony_ci windValue -= oWindValue; 1084cb93a386Sopenharmony_ci oppValue -= oOppValue; 1085cb93a386Sopenharmony_ci } else { 1086cb93a386Sopenharmony_ci windValue += oWindValue; 1087cb93a386Sopenharmony_ci oppValue += oOppValue; 1088cb93a386Sopenharmony_ci } 1089cb93a386Sopenharmony_ci if (segment->isXor()) { 1090cb93a386Sopenharmony_ci windValue &= 1; 1091cb93a386Sopenharmony_ci } 1092cb93a386Sopenharmony_ci if (segment->oppXor()) { 1093cb93a386Sopenharmony_ci oppValue &= 1; 1094cb93a386Sopenharmony_ci } 1095cb93a386Sopenharmony_ci oWindValue = oOppValue = 0; 1096cb93a386Sopenharmony_ci } else { 1097cb93a386Sopenharmony_ci if (operandSwap) { 1098cb93a386Sopenharmony_ci using std::swap; 1099cb93a386Sopenharmony_ci swap(windValue, oppValue); 1100cb93a386Sopenharmony_ci } 1101cb93a386Sopenharmony_ci if (flipped) { 1102cb93a386Sopenharmony_ci oWindValue -= windValue; 1103cb93a386Sopenharmony_ci oOppValue -= oppValue; 1104cb93a386Sopenharmony_ci } else { 1105cb93a386Sopenharmony_ci oWindValue += windValue; 1106cb93a386Sopenharmony_ci oOppValue += oppValue; 1107cb93a386Sopenharmony_ci } 1108cb93a386Sopenharmony_ci if (oSegment->isXor()) { 1109cb93a386Sopenharmony_ci oWindValue &= 1; 1110cb93a386Sopenharmony_ci } 1111cb93a386Sopenharmony_ci if (oSegment->oppXor()) { 1112cb93a386Sopenharmony_ci oOppValue &= 1; 1113cb93a386Sopenharmony_ci } 1114cb93a386Sopenharmony_ci windValue = oppValue = 0; 1115cb93a386Sopenharmony_ci } 1116cb93a386Sopenharmony_ci#if 0 && DEBUG_COINCIDENCE 1117cb93a386Sopenharmony_ci SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(), 1118cb93a386Sopenharmony_ci start->debugID(), windValue, oppValue); 1119cb93a386Sopenharmony_ci SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(), 1120cb93a386Sopenharmony_ci oStart->debugID(), oWindValue, oOppValue); 1121cb93a386Sopenharmony_ci#endif 1122cb93a386Sopenharmony_ci FAIL_IF(windValue <= -1); 1123cb93a386Sopenharmony_ci start->setWindValue(windValue); 1124cb93a386Sopenharmony_ci start->setOppValue(oppValue); 1125cb93a386Sopenharmony_ci FAIL_IF(oWindValue <= -1); 1126cb93a386Sopenharmony_ci oStart->setWindValue(oWindValue); 1127cb93a386Sopenharmony_ci oStart->setOppValue(oOppValue); 1128cb93a386Sopenharmony_ci if (!windValue && !oppValue) { 1129cb93a386Sopenharmony_ci segment->markDone(start); 1130cb93a386Sopenharmony_ci } 1131cb93a386Sopenharmony_ci if (!oWindValue && !oOppValue) { 1132cb93a386Sopenharmony_ci oSegment->markDone(oStart); 1133cb93a386Sopenharmony_ci } 1134cb93a386Sopenharmony_ci SkOpSpanBase* next = start->next(); 1135cb93a386Sopenharmony_ci SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next(); 1136cb93a386Sopenharmony_ci if (next == end) { 1137cb93a386Sopenharmony_ci break; 1138cb93a386Sopenharmony_ci } 1139cb93a386Sopenharmony_ci FAIL_IF(!next->upCastable()); 1140cb93a386Sopenharmony_ci start = next->upCast(); 1141cb93a386Sopenharmony_ci // if the opposite ran out too soon, just reuse the last span 1142cb93a386Sopenharmony_ci if (!oNext || !oNext->upCastable()) { 1143cb93a386Sopenharmony_ci oNext = oStart; 1144cb93a386Sopenharmony_ci } 1145cb93a386Sopenharmony_ci oStart = oNext->upCast(); 1146cb93a386Sopenharmony_ci } while (true); 1147cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1148cb93a386Sopenharmony_ci return true; 1149cb93a386Sopenharmony_ci} 1150cb93a386Sopenharmony_ci 1151cb93a386Sopenharmony_ci// Please keep this in sync with debugRelease() 1152cb93a386Sopenharmony_cibool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) { 1153cb93a386Sopenharmony_ci SkCoincidentSpans* head = coin; 1154cb93a386Sopenharmony_ci SkCoincidentSpans* prev = nullptr; 1155cb93a386Sopenharmony_ci SkCoincidentSpans* next; 1156cb93a386Sopenharmony_ci do { 1157cb93a386Sopenharmony_ci next = coin->next(); 1158cb93a386Sopenharmony_ci if (coin == remove) { 1159cb93a386Sopenharmony_ci if (prev) { 1160cb93a386Sopenharmony_ci prev->setNext(next); 1161cb93a386Sopenharmony_ci } else if (head == fHead) { 1162cb93a386Sopenharmony_ci fHead = next; 1163cb93a386Sopenharmony_ci } else { 1164cb93a386Sopenharmony_ci fTop = next; 1165cb93a386Sopenharmony_ci } 1166cb93a386Sopenharmony_ci break; 1167cb93a386Sopenharmony_ci } 1168cb93a386Sopenharmony_ci prev = coin; 1169cb93a386Sopenharmony_ci } while ((coin = next)); 1170cb93a386Sopenharmony_ci return coin != nullptr; 1171cb93a386Sopenharmony_ci} 1172cb93a386Sopenharmony_ci 1173cb93a386Sopenharmony_civoid SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) { 1174cb93a386Sopenharmony_ci if (!coin) { 1175cb93a386Sopenharmony_ci return; 1176cb93a386Sopenharmony_ci } 1177cb93a386Sopenharmony_ci SkCoincidentSpans* head = coin; 1178cb93a386Sopenharmony_ci SkCoincidentSpans* prev = nullptr; 1179cb93a386Sopenharmony_ci SkCoincidentSpans* next; 1180cb93a386Sopenharmony_ci do { 1181cb93a386Sopenharmony_ci next = coin->next(); 1182cb93a386Sopenharmony_ci if (coin->coinPtTStart()->deleted()) { 1183cb93a386Sopenharmony_ci SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() : 1184cb93a386Sopenharmony_ci coin->oppPtTStart()->deleted()); 1185cb93a386Sopenharmony_ci if (prev) { 1186cb93a386Sopenharmony_ci prev->setNext(next); 1187cb93a386Sopenharmony_ci } else if (head == fHead) { 1188cb93a386Sopenharmony_ci fHead = next; 1189cb93a386Sopenharmony_ci } else { 1190cb93a386Sopenharmony_ci fTop = next; 1191cb93a386Sopenharmony_ci } 1192cb93a386Sopenharmony_ci } else { 1193cb93a386Sopenharmony_ci SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() : 1194cb93a386Sopenharmony_ci !coin->oppPtTStart()->deleted()); 1195cb93a386Sopenharmony_ci prev = coin; 1196cb93a386Sopenharmony_ci } 1197cb93a386Sopenharmony_ci } while ((coin = next)); 1198cb93a386Sopenharmony_ci} 1199cb93a386Sopenharmony_ci 1200cb93a386Sopenharmony_civoid SkOpCoincidence::releaseDeleted() { 1201cb93a386Sopenharmony_ci this->releaseDeleted(fHead); 1202cb93a386Sopenharmony_ci this->releaseDeleted(fTop); 1203cb93a386Sopenharmony_ci} 1204cb93a386Sopenharmony_ci 1205cb93a386Sopenharmony_civoid SkOpCoincidence::restoreHead() { 1206cb93a386Sopenharmony_ci SkCoincidentSpans** headPtr = &fHead; 1207cb93a386Sopenharmony_ci while (*headPtr) { 1208cb93a386Sopenharmony_ci headPtr = (*headPtr)->nextPtr(); 1209cb93a386Sopenharmony_ci } 1210cb93a386Sopenharmony_ci *headPtr = fTop; 1211cb93a386Sopenharmony_ci fTop = nullptr; 1212cb93a386Sopenharmony_ci // segments may have collapsed in the meantime; remove empty referenced segments 1213cb93a386Sopenharmony_ci headPtr = &fHead; 1214cb93a386Sopenharmony_ci while (*headPtr) { 1215cb93a386Sopenharmony_ci SkCoincidentSpans* test = *headPtr; 1216cb93a386Sopenharmony_ci if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) { 1217cb93a386Sopenharmony_ci *headPtr = test->next(); 1218cb93a386Sopenharmony_ci continue; 1219cb93a386Sopenharmony_ci } 1220cb93a386Sopenharmony_ci headPtr = (*headPtr)->nextPtr(); 1221cb93a386Sopenharmony_ci } 1222cb93a386Sopenharmony_ci} 1223cb93a386Sopenharmony_ci 1224cb93a386Sopenharmony_ci// Please keep this in sync with debugExpand() 1225cb93a386Sopenharmony_ci// expand the range by checking adjacent spans for coincidence 1226cb93a386Sopenharmony_cibool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 1227cb93a386Sopenharmony_ci DEBUG_SET_PHASE(); 1228cb93a386Sopenharmony_ci SkCoincidentSpans* coin = fHead; 1229cb93a386Sopenharmony_ci if (!coin) { 1230cb93a386Sopenharmony_ci return false; 1231cb93a386Sopenharmony_ci } 1232cb93a386Sopenharmony_ci bool expanded = false; 1233cb93a386Sopenharmony_ci do { 1234cb93a386Sopenharmony_ci if (coin->expand()) { 1235cb93a386Sopenharmony_ci // check to see if multiple spans expanded so they are now identical 1236cb93a386Sopenharmony_ci SkCoincidentSpans* test = fHead; 1237cb93a386Sopenharmony_ci do { 1238cb93a386Sopenharmony_ci if (coin == test) { 1239cb93a386Sopenharmony_ci continue; 1240cb93a386Sopenharmony_ci } 1241cb93a386Sopenharmony_ci if (coin->coinPtTStart() == test->coinPtTStart() 1242cb93a386Sopenharmony_ci && coin->oppPtTStart() == test->oppPtTStart()) { 1243cb93a386Sopenharmony_ci this->release(fHead, test); 1244cb93a386Sopenharmony_ci break; 1245cb93a386Sopenharmony_ci } 1246cb93a386Sopenharmony_ci } while ((test = test->next())); 1247cb93a386Sopenharmony_ci expanded = true; 1248cb93a386Sopenharmony_ci } 1249cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1250cb93a386Sopenharmony_ci return expanded; 1251cb93a386Sopenharmony_ci} 1252cb93a386Sopenharmony_ci 1253cb93a386Sopenharmony_cibool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const { 1254cb93a386Sopenharmony_ci DEBUG_SET_PHASE(); 1255cb93a386Sopenharmony_ci overlaps->fHead = overlaps->fTop = nullptr; 1256cb93a386Sopenharmony_ci SkCoincidentSpans* outer = fHead; 1257cb93a386Sopenharmony_ci while (outer) { 1258cb93a386Sopenharmony_ci const SkOpSegment* outerCoin = outer->coinPtTStart()->segment(); 1259cb93a386Sopenharmony_ci const SkOpSegment* outerOpp = outer->oppPtTStart()->segment(); 1260cb93a386Sopenharmony_ci SkCoincidentSpans* inner = outer; 1261cb93a386Sopenharmony_ci while ((inner = inner->next())) { 1262cb93a386Sopenharmony_ci const SkOpSegment* innerCoin = inner->coinPtTStart()->segment(); 1263cb93a386Sopenharmony_ci if (outerCoin == innerCoin) { 1264cb93a386Sopenharmony_ci continue; // both winners are the same segment, so there's no additional overlap 1265cb93a386Sopenharmony_ci } 1266cb93a386Sopenharmony_ci const SkOpSegment* innerOpp = inner->oppPtTStart()->segment(); 1267cb93a386Sopenharmony_ci const SkOpPtT* overlapS; 1268cb93a386Sopenharmony_ci const SkOpPtT* overlapE; 1269cb93a386Sopenharmony_ci if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(), 1270cb93a386Sopenharmony_ci outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS, 1271cb93a386Sopenharmony_ci &overlapE)) 1272cb93a386Sopenharmony_ci || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(), 1273cb93a386Sopenharmony_ci outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(), 1274cb93a386Sopenharmony_ci &overlapS, &overlapE)) 1275cb93a386Sopenharmony_ci || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(), 1276cb93a386Sopenharmony_ci outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(), 1277cb93a386Sopenharmony_ci &overlapS, &overlapE))) { 1278cb93a386Sopenharmony_ci if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp, 1279cb93a386Sopenharmony_ci overlapS, overlapE)) { 1280cb93a386Sopenharmony_ci return false; 1281cb93a386Sopenharmony_ci } 1282cb93a386Sopenharmony_ci } 1283cb93a386Sopenharmony_ci } 1284cb93a386Sopenharmony_ci outer = outer->next(); 1285cb93a386Sopenharmony_ci } 1286cb93a386Sopenharmony_ci return true; 1287cb93a386Sopenharmony_ci} 1288cb93a386Sopenharmony_ci 1289cb93a386Sopenharmony_civoid SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) { 1290cb93a386Sopenharmony_ci SkOPASSERT(deleted != kept); 1291cb93a386Sopenharmony_ci if (fHead) { 1292cb93a386Sopenharmony_ci this->fixUp(fHead, deleted, kept); 1293cb93a386Sopenharmony_ci } 1294cb93a386Sopenharmony_ci if (fTop) { 1295cb93a386Sopenharmony_ci this->fixUp(fTop, deleted, kept); 1296cb93a386Sopenharmony_ci } 1297cb93a386Sopenharmony_ci} 1298cb93a386Sopenharmony_ci 1299cb93a386Sopenharmony_civoid SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) { 1300cb93a386Sopenharmony_ci SkCoincidentSpans* head = coin; 1301cb93a386Sopenharmony_ci do { 1302cb93a386Sopenharmony_ci if (coin->coinPtTStart() == deleted) { 1303cb93a386Sopenharmony_ci if (coin->coinPtTEnd()->span() == kept->span()) { 1304cb93a386Sopenharmony_ci this->release(head, coin); 1305cb93a386Sopenharmony_ci continue; 1306cb93a386Sopenharmony_ci } 1307cb93a386Sopenharmony_ci coin->setCoinPtTStart(kept); 1308cb93a386Sopenharmony_ci } 1309cb93a386Sopenharmony_ci if (coin->coinPtTEnd() == deleted) { 1310cb93a386Sopenharmony_ci if (coin->coinPtTStart()->span() == kept->span()) { 1311cb93a386Sopenharmony_ci this->release(head, coin); 1312cb93a386Sopenharmony_ci continue; 1313cb93a386Sopenharmony_ci } 1314cb93a386Sopenharmony_ci coin->setCoinPtTEnd(kept); 1315cb93a386Sopenharmony_ci } 1316cb93a386Sopenharmony_ci if (coin->oppPtTStart() == deleted) { 1317cb93a386Sopenharmony_ci if (coin->oppPtTEnd()->span() == kept->span()) { 1318cb93a386Sopenharmony_ci this->release(head, coin); 1319cb93a386Sopenharmony_ci continue; 1320cb93a386Sopenharmony_ci } 1321cb93a386Sopenharmony_ci coin->setOppPtTStart(kept); 1322cb93a386Sopenharmony_ci } 1323cb93a386Sopenharmony_ci if (coin->oppPtTEnd() == deleted) { 1324cb93a386Sopenharmony_ci if (coin->oppPtTStart()->span() == kept->span()) { 1325cb93a386Sopenharmony_ci this->release(head, coin); 1326cb93a386Sopenharmony_ci continue; 1327cb93a386Sopenharmony_ci } 1328cb93a386Sopenharmony_ci coin->setOppPtTEnd(kept); 1329cb93a386Sopenharmony_ci } 1330cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1331cb93a386Sopenharmony_ci} 1332cb93a386Sopenharmony_ci 1333cb93a386Sopenharmony_ci// Please keep this in sync with debugMark() 1334cb93a386Sopenharmony_ci/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */ 1335cb93a386Sopenharmony_cibool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { 1336cb93a386Sopenharmony_ci DEBUG_SET_PHASE(); 1337cb93a386Sopenharmony_ci SkCoincidentSpans* coin = fHead; 1338cb93a386Sopenharmony_ci if (!coin) { 1339cb93a386Sopenharmony_ci return true; 1340cb93a386Sopenharmony_ci } 1341cb93a386Sopenharmony_ci do { 1342cb93a386Sopenharmony_ci SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span(); 1343cb93a386Sopenharmony_ci FAIL_IF(!startBase->upCastable()); 1344cb93a386Sopenharmony_ci SkOpSpan* start = startBase->upCast(); 1345cb93a386Sopenharmony_ci FAIL_IF(start->deleted()); 1346cb93a386Sopenharmony_ci SkOpSpanBase* end = coin->coinPtTEndWritable()->span(); 1347cb93a386Sopenharmony_ci SkOPASSERT(!end->deleted()); 1348cb93a386Sopenharmony_ci SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span(); 1349cb93a386Sopenharmony_ci SkOPASSERT(!oStart->deleted()); 1350cb93a386Sopenharmony_ci SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span(); 1351cb93a386Sopenharmony_ci FAIL_IF(oEnd->deleted()); 1352cb93a386Sopenharmony_ci bool flipped = coin->flipped(); 1353cb93a386Sopenharmony_ci if (flipped) { 1354cb93a386Sopenharmony_ci using std::swap; 1355cb93a386Sopenharmony_ci swap(oStart, oEnd); 1356cb93a386Sopenharmony_ci } 1357cb93a386Sopenharmony_ci /* coin and opp spans may not match up. Mark the ends, and then let the interior 1358cb93a386Sopenharmony_ci get marked as many times as the spans allow */ 1359cb93a386Sopenharmony_ci FAIL_IF(!oStart->upCastable()); 1360cb93a386Sopenharmony_ci start->insertCoincidence(oStart->upCast()); 1361cb93a386Sopenharmony_ci end->insertCoinEnd(oEnd); 1362cb93a386Sopenharmony_ci const SkOpSegment* segment = start->segment(); 1363cb93a386Sopenharmony_ci const SkOpSegment* oSegment = oStart->segment(); 1364cb93a386Sopenharmony_ci SkOpSpanBase* next = start; 1365cb93a386Sopenharmony_ci SkOpSpanBase* oNext = oStart; 1366cb93a386Sopenharmony_ci bool ordered; 1367cb93a386Sopenharmony_ci FAIL_IF(!coin->ordered(&ordered)); 1368cb93a386Sopenharmony_ci while ((next = next->upCast()->next()) != end) { 1369cb93a386Sopenharmony_ci FAIL_IF(!next->upCastable()); 1370cb93a386Sopenharmony_ci FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered)); 1371cb93a386Sopenharmony_ci } 1372cb93a386Sopenharmony_ci while ((oNext = oNext->upCast()->next()) != oEnd) { 1373cb93a386Sopenharmony_ci FAIL_IF(!oNext->upCastable()); 1374cb93a386Sopenharmony_ci FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered)); 1375cb93a386Sopenharmony_ci } 1376cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1377cb93a386Sopenharmony_ci return true; 1378cb93a386Sopenharmony_ci} 1379cb93a386Sopenharmony_ci 1380cb93a386Sopenharmony_ci// Please keep in sync with debugMarkCollapsed() 1381cb93a386Sopenharmony_civoid SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) { 1382cb93a386Sopenharmony_ci SkCoincidentSpans* head = coin; 1383cb93a386Sopenharmony_ci while (coin) { 1384cb93a386Sopenharmony_ci if (coin->collapsed(test)) { 1385cb93a386Sopenharmony_ci if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) { 1386cb93a386Sopenharmony_ci coin->coinPtTStartWritable()->segment()->markAllDone(); 1387cb93a386Sopenharmony_ci } 1388cb93a386Sopenharmony_ci if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) { 1389cb93a386Sopenharmony_ci coin->oppPtTStartWritable()->segment()->markAllDone(); 1390cb93a386Sopenharmony_ci } 1391cb93a386Sopenharmony_ci this->release(head, coin); 1392cb93a386Sopenharmony_ci } 1393cb93a386Sopenharmony_ci coin = coin->next(); 1394cb93a386Sopenharmony_ci } 1395cb93a386Sopenharmony_ci} 1396cb93a386Sopenharmony_ci 1397cb93a386Sopenharmony_ci// Please keep in sync with debugMarkCollapsed() 1398cb93a386Sopenharmony_civoid SkOpCoincidence::markCollapsed(SkOpPtT* test) { 1399cb93a386Sopenharmony_ci markCollapsed(fHead, test); 1400cb93a386Sopenharmony_ci markCollapsed(fTop, test); 1401cb93a386Sopenharmony_ci} 1402cb93a386Sopenharmony_ci 1403cb93a386Sopenharmony_cibool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) { 1404cb93a386Sopenharmony_ci if (coinSeg->verb() < oppSeg->verb()) { 1405cb93a386Sopenharmony_ci return true; 1406cb93a386Sopenharmony_ci } 1407cb93a386Sopenharmony_ci if (coinSeg->verb() > oppSeg->verb()) { 1408cb93a386Sopenharmony_ci return false; 1409cb93a386Sopenharmony_ci } 1410cb93a386Sopenharmony_ci int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2; 1411cb93a386Sopenharmony_ci const SkScalar* cPt = &coinSeg->pts()[0].fX; 1412cb93a386Sopenharmony_ci const SkScalar* oPt = &oppSeg->pts()[0].fX; 1413cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 1414cb93a386Sopenharmony_ci if (*cPt < *oPt) { 1415cb93a386Sopenharmony_ci return true; 1416cb93a386Sopenharmony_ci } 1417cb93a386Sopenharmony_ci if (*cPt > *oPt) { 1418cb93a386Sopenharmony_ci return false; 1419cb93a386Sopenharmony_ci } 1420cb93a386Sopenharmony_ci ++cPt; 1421cb93a386Sopenharmony_ci ++oPt; 1422cb93a386Sopenharmony_ci } 1423cb93a386Sopenharmony_ci return true; 1424cb93a386Sopenharmony_ci} 1425cb93a386Sopenharmony_ci 1426cb93a386Sopenharmony_cibool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e, 1427cb93a386Sopenharmony_ci const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const { 1428cb93a386Sopenharmony_ci SkASSERT(coin1s->segment() == coin2s->segment()); 1429cb93a386Sopenharmony_ci *overS = std::max(std::min(coin1s->fT, coin1e->fT), std::min(coin2s->fT, coin2e->fT)); 1430cb93a386Sopenharmony_ci *overE = std::min(std::max(coin1s->fT, coin1e->fT), std::max(coin2s->fT, coin2e->fT)); 1431cb93a386Sopenharmony_ci return *overS < *overE; 1432cb93a386Sopenharmony_ci} 1433cb93a386Sopenharmony_ci 1434cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with debugRelease() 1435cb93a386Sopenharmony_civoid SkOpCoincidence::release(const SkOpSegment* deleted) { 1436cb93a386Sopenharmony_ci SkCoincidentSpans* coin = fHead; 1437cb93a386Sopenharmony_ci if (!coin) { 1438cb93a386Sopenharmony_ci return; 1439cb93a386Sopenharmony_ci } 1440cb93a386Sopenharmony_ci do { 1441cb93a386Sopenharmony_ci if (coin->coinPtTStart()->segment() == deleted 1442cb93a386Sopenharmony_ci || coin->coinPtTEnd()->segment() == deleted 1443cb93a386Sopenharmony_ci || coin->oppPtTStart()->segment() == deleted 1444cb93a386Sopenharmony_ci || coin->oppPtTEnd()->segment() == deleted) { 1445cb93a386Sopenharmony_ci this->release(fHead, coin); 1446cb93a386Sopenharmony_ci } 1447cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1448cb93a386Sopenharmony_ci} 1449