1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 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/core/SkPointPriv.h" 8cb93a386Sopenharmony_ci#include "src/pathops/SkOpCoincidence.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkOpContour.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkOpSegment.h" 11cb93a386Sopenharmony_ci#include "src/pathops/SkPathWriter.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci#include <utility> 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci/* 16cb93a386Sopenharmony_ciAfter computing raw intersections, post process all segments to: 17cb93a386Sopenharmony_ci- find small collections of points that can be collapsed to a single point 18cb93a386Sopenharmony_ci- find missing intersections to resolve differences caused by different algorithms 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ciConsider segments containing tiny or small intervals. Consider coincident segments 21cb93a386Sopenharmony_cibecause coincidence finds intersections through distance measurement that non-coincident 22cb93a386Sopenharmony_ciintersection tests cannot. 23cb93a386Sopenharmony_ci */ 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci#define F (false) // discard the edge 26cb93a386Sopenharmony_ci#define T (true) // keep the edge 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_cistatic const bool gUnaryActiveEdge[2][2] = { 29cb93a386Sopenharmony_ci// from=0 from=1 30cb93a386Sopenharmony_ci// to=0,1 to=0,1 31cb93a386Sopenharmony_ci {F, T}, {T, F}, 32cb93a386Sopenharmony_ci}; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cistatic const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = { 35cb93a386Sopenharmony_ci// miFrom=0 miFrom=1 36cb93a386Sopenharmony_ci// miTo=0 miTo=1 miTo=0 miTo=1 37cb93a386Sopenharmony_ci// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 38cb93a386Sopenharmony_ci// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 39cb93a386Sopenharmony_ci {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su 40cb93a386Sopenharmony_ci {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su 41cb93a386Sopenharmony_ci {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su 42cb93a386Sopenharmony_ci {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su 43cb93a386Sopenharmony_ci}; 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci#undef F 46cb93a386Sopenharmony_ci#undef T 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ciSkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr, 49cb93a386Sopenharmony_ci SkOpSpanBase** endPtr, bool* done) { 50cb93a386Sopenharmony_ci if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) { 51cb93a386Sopenharmony_ci return result; 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) { 54cb93a386Sopenharmony_ci return result; 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci return nullptr; 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ciSkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr, 60cb93a386Sopenharmony_ci SkOpSpanBase** endPtr, bool* done) { 61cb93a386Sopenharmony_ci SkOpSpan* upSpan = start->upCastable(); 62cb93a386Sopenharmony_ci if (upSpan) { 63cb93a386Sopenharmony_ci if (upSpan->windValue() || upSpan->oppValue()) { 64cb93a386Sopenharmony_ci SkOpSpanBase* next = upSpan->next(); 65cb93a386Sopenharmony_ci if (!*endPtr) { 66cb93a386Sopenharmony_ci *startPtr = start; 67cb93a386Sopenharmony_ci *endPtr = next; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci if (!upSpan->done()) { 70cb93a386Sopenharmony_ci if (upSpan->windSum() != SK_MinS32) { 71cb93a386Sopenharmony_ci return spanToAngle(start, next); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci *done = false; 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci } else { 76cb93a386Sopenharmony_ci SkASSERT(upSpan->done()); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci SkOpSpan* downSpan = start->prev(); 80cb93a386Sopenharmony_ci // edge leading into junction 81cb93a386Sopenharmony_ci if (downSpan) { 82cb93a386Sopenharmony_ci if (downSpan->windValue() || downSpan->oppValue()) { 83cb93a386Sopenharmony_ci if (!*endPtr) { 84cb93a386Sopenharmony_ci *startPtr = start; 85cb93a386Sopenharmony_ci *endPtr = downSpan; 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci if (!downSpan->done()) { 88cb93a386Sopenharmony_ci if (downSpan->windSum() != SK_MinS32) { 89cb93a386Sopenharmony_ci return spanToAngle(start, downSpan); 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci *done = false; 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } else { 94cb93a386Sopenharmony_ci SkASSERT(downSpan->done()); 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci return nullptr; 98cb93a386Sopenharmony_ci} 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ciSkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr, 101cb93a386Sopenharmony_ci SkOpSpanBase** endPtr, bool* done) { 102cb93a386Sopenharmony_ci SkOpPtT* oPtT = start->ptT()->next(); 103cb93a386Sopenharmony_ci SkOpSegment* other = oPtT->segment(); 104cb93a386Sopenharmony_ci SkOpSpanBase* oSpan = oPtT->span(); 105cb93a386Sopenharmony_ci return other->activeAngleInner(oSpan, startPtr, endPtr, done); 106cb93a386Sopenharmony_ci} 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_cibool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask, 109cb93a386Sopenharmony_ci SkPathOp op) { 110cb93a386Sopenharmony_ci int sumMiWinding = this->updateWinding(end, start); 111cb93a386Sopenharmony_ci int sumSuWinding = this->updateOppWinding(end, start); 112cb93a386Sopenharmony_ci#if DEBUG_LIMIT_WIND_SUM 113cb93a386Sopenharmony_ci SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); 114cb93a386Sopenharmony_ci SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); 115cb93a386Sopenharmony_ci#endif 116cb93a386Sopenharmony_ci if (this->operand()) { 117cb93a386Sopenharmony_ci using std::swap; 118cb93a386Sopenharmony_ci swap(sumMiWinding, sumSuWinding); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding); 121cb93a386Sopenharmony_ci} 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_cibool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end, 124cb93a386Sopenharmony_ci SkPathOp op, int* sumMiWinding, int* sumSuWinding) { 125cb93a386Sopenharmony_ci int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; 126cb93a386Sopenharmony_ci this->setUpWindings(start, end, sumMiWinding, sumSuWinding, 127cb93a386Sopenharmony_ci &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 128cb93a386Sopenharmony_ci bool miFrom; 129cb93a386Sopenharmony_ci bool miTo; 130cb93a386Sopenharmony_ci bool suFrom; 131cb93a386Sopenharmony_ci bool suTo; 132cb93a386Sopenharmony_ci if (operand()) { 133cb93a386Sopenharmony_ci miFrom = (oppMaxWinding & xorMiMask) != 0; 134cb93a386Sopenharmony_ci miTo = (oppSumWinding & xorMiMask) != 0; 135cb93a386Sopenharmony_ci suFrom = (maxWinding & xorSuMask) != 0; 136cb93a386Sopenharmony_ci suTo = (sumWinding & xorSuMask) != 0; 137cb93a386Sopenharmony_ci } else { 138cb93a386Sopenharmony_ci miFrom = (maxWinding & xorMiMask) != 0; 139cb93a386Sopenharmony_ci miTo = (sumWinding & xorMiMask) != 0; 140cb93a386Sopenharmony_ci suFrom = (oppMaxWinding & xorSuMask) != 0; 141cb93a386Sopenharmony_ci suTo = (oppSumWinding & xorSuMask) != 0; 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; 144cb93a386Sopenharmony_ci#if DEBUG_ACTIVE_OP 145cb93a386Sopenharmony_ci SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", 146cb93a386Sopenharmony_ci __FUNCTION__, debugID(), start->t(), end->t(), 147cb93a386Sopenharmony_ci SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); 148cb93a386Sopenharmony_ci#endif 149cb93a386Sopenharmony_ci return result; 150cb93a386Sopenharmony_ci} 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_cibool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) { 153cb93a386Sopenharmony_ci int sumWinding = updateWinding(end, start); 154cb93a386Sopenharmony_ci return activeWinding(start, end, &sumWinding); 155cb93a386Sopenharmony_ci} 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_cibool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) { 158cb93a386Sopenharmony_ci int maxWinding; 159cb93a386Sopenharmony_ci setUpWinding(start, end, &maxWinding, sumWinding); 160cb93a386Sopenharmony_ci bool from = maxWinding != 0; 161cb93a386Sopenharmony_ci bool to = *sumWinding != 0; 162cb93a386Sopenharmony_ci bool result = gUnaryActiveEdge[from][to]; 163cb93a386Sopenharmony_ci return result; 164cb93a386Sopenharmony_ci} 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_cibool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, 167cb93a386Sopenharmony_ci SkPathWriter* path) const { 168cb93a386Sopenharmony_ci const SkOpSpan* spanStart = start->starter(end); 169cb93a386Sopenharmony_ci FAIL_IF(spanStart->alreadyAdded()); 170cb93a386Sopenharmony_ci const_cast<SkOpSpan*>(spanStart)->markAdded(); 171cb93a386Sopenharmony_ci SkDCurveSweep curvePart; 172cb93a386Sopenharmony_ci start->segment()->subDivide(start, end, &curvePart.fCurve); 173cb93a386Sopenharmony_ci curvePart.setCurveHullSweep(fVerb); 174cb93a386Sopenharmony_ci SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb; 175cb93a386Sopenharmony_ci path->deferredMove(start->ptT()); 176cb93a386Sopenharmony_ci switch (verb) { 177cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 178cb93a386Sopenharmony_ci FAIL_IF(!path->deferredLine(end->ptT())); 179cb93a386Sopenharmony_ci break; 180cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 181cb93a386Sopenharmony_ci path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT()); 182cb93a386Sopenharmony_ci break; 183cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 184cb93a386Sopenharmony_ci path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(), 185cb93a386Sopenharmony_ci curvePart.fCurve.fConic.fWeight); 186cb93a386Sopenharmony_ci break; 187cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 188cb93a386Sopenharmony_ci path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(), 189cb93a386Sopenharmony_ci curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT()); 190cb93a386Sopenharmony_ci break; 191cb93a386Sopenharmony_ci default: 192cb93a386Sopenharmony_ci SkASSERT(0); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci return true; 195cb93a386Sopenharmony_ci} 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ciconst SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const { 198cb93a386Sopenharmony_ci const SkOpSpanBase* test = &fHead; 199cb93a386Sopenharmony_ci const SkOpPtT* testPtT; 200cb93a386Sopenharmony_ci SkPoint pt = this->ptAtT(t); 201cb93a386Sopenharmony_ci do { 202cb93a386Sopenharmony_ci testPtT = test->ptT(); 203cb93a386Sopenharmony_ci if (testPtT->fT == t) { 204cb93a386Sopenharmony_ci break; 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci if (!this->match(testPtT, this, t, pt)) { 207cb93a386Sopenharmony_ci if (t < testPtT->fT) { 208cb93a386Sopenharmony_ci return nullptr; 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci continue; 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci if (!opp) { 213cb93a386Sopenharmony_ci return testPtT; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci const SkOpPtT* loop = testPtT->next(); 216cb93a386Sopenharmony_ci while (loop != testPtT) { 217cb93a386Sopenharmony_ci if (loop->segment() == this && loop->fT == t && loop->fPt == pt) { 218cb93a386Sopenharmony_ci goto foundMatch; 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci loop = loop->next(); 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci return nullptr; 223cb93a386Sopenharmony_ci } while ((test = test->upCast()->next())); 224cb93a386Sopenharmony_cifoundMatch: 225cb93a386Sopenharmony_ci return opp && !test->contains(opp) ? nullptr : testPtT; 226cb93a386Sopenharmony_ci} 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci// break the span so that the coincident part does not change the angle of the remainder 229cb93a386Sopenharmony_cibool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) { 230cb93a386Sopenharmony_ci if (this->contains(newT)) { 231cb93a386Sopenharmony_ci return true; 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci this->globalState()->resetAllocatedOpSpan(); 234cb93a386Sopenharmony_ci FAIL_IF(!between(0, newT, 1)); 235cb93a386Sopenharmony_ci SkOpPtT* newPtT = this->addT(newT); 236cb93a386Sopenharmony_ci *startOver |= this->globalState()->allocatedOpSpan(); 237cb93a386Sopenharmony_ci if (!newPtT) { 238cb93a386Sopenharmony_ci return false; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci newPtT->fPt = this->ptAtT(newT); 241cb93a386Sopenharmony_ci SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT); 242cb93a386Sopenharmony_ci if (oppPrev) { 243cb93a386Sopenharmony_ci // const cast away to change linked list; pt/t values stays unchanged 244cb93a386Sopenharmony_ci SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test); 245cb93a386Sopenharmony_ci writableTest->mergeMatches(newPtT->span()); 246cb93a386Sopenharmony_ci writableTest->ptT()->addOpp(newPtT, oppPrev); 247cb93a386Sopenharmony_ci writableTest->checkForCollapsedCoincidence(); 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci return true; 250cb93a386Sopenharmony_ci} 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci// Please keep this in sync with debugAddT() 253cb93a386Sopenharmony_ciSkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) { 254cb93a386Sopenharmony_ci debugValidate(); 255cb93a386Sopenharmony_ci SkOpSpanBase* spanBase = &fHead; 256cb93a386Sopenharmony_ci do { 257cb93a386Sopenharmony_ci SkOpPtT* result = spanBase->ptT(); 258cb93a386Sopenharmony_ci if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) { 259cb93a386Sopenharmony_ci spanBase->bumpSpanAdds(); 260cb93a386Sopenharmony_ci return result; 261cb93a386Sopenharmony_ci } 262cb93a386Sopenharmony_ci if (t < result->fT) { 263cb93a386Sopenharmony_ci SkOpSpan* prev = result->span()->prev(); 264cb93a386Sopenharmony_ci FAIL_WITH_NULL_IF(!prev); 265cb93a386Sopenharmony_ci // marks in global state that new op span has been allocated 266cb93a386Sopenharmony_ci SkOpSpan* span = this->insert(prev); 267cb93a386Sopenharmony_ci span->init(this, prev, t, pt); 268cb93a386Sopenharmony_ci this->debugValidate(); 269cb93a386Sopenharmony_ci#if DEBUG_ADD_T 270cb93a386Sopenharmony_ci SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, 271cb93a386Sopenharmony_ci span->segment()->debugID(), span->debugID()); 272cb93a386Sopenharmony_ci#endif 273cb93a386Sopenharmony_ci span->bumpSpanAdds(); 274cb93a386Sopenharmony_ci return span->ptT(); 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci FAIL_WITH_NULL_IF(spanBase == &fTail); 277cb93a386Sopenharmony_ci } while ((spanBase = spanBase->upCast()->next())); 278cb93a386Sopenharmony_ci SkASSERT(0); 279cb93a386Sopenharmony_ci return nullptr; // we never get here, but need this to satisfy compiler 280cb93a386Sopenharmony_ci} 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ciSkOpPtT* SkOpSegment::addT(double t) { 283cb93a386Sopenharmony_ci return addT(t, this->ptAtT(t)); 284cb93a386Sopenharmony_ci} 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_civoid SkOpSegment::calcAngles() { 287cb93a386Sopenharmony_ci bool activePrior = !fHead.isCanceled(); 288cb93a386Sopenharmony_ci if (activePrior && !fHead.simple()) { 289cb93a386Sopenharmony_ci addStartSpan(); 290cb93a386Sopenharmony_ci } 291cb93a386Sopenharmony_ci SkOpSpan* prior = &fHead; 292cb93a386Sopenharmony_ci SkOpSpanBase* spanBase = fHead.next(); 293cb93a386Sopenharmony_ci while (spanBase != &fTail) { 294cb93a386Sopenharmony_ci if (activePrior) { 295cb93a386Sopenharmony_ci SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>(); 296cb93a386Sopenharmony_ci priorAngle->set(spanBase, prior); 297cb93a386Sopenharmony_ci spanBase->setFromAngle(priorAngle); 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci SkOpSpan* span = spanBase->upCast(); 300cb93a386Sopenharmony_ci bool active = !span->isCanceled(); 301cb93a386Sopenharmony_ci SkOpSpanBase* next = span->next(); 302cb93a386Sopenharmony_ci if (active) { 303cb93a386Sopenharmony_ci SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>(); 304cb93a386Sopenharmony_ci angle->set(span, next); 305cb93a386Sopenharmony_ci span->setToAngle(angle); 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci activePrior = active; 308cb93a386Sopenharmony_ci prior = span; 309cb93a386Sopenharmony_ci spanBase = next; 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci if (activePrior && !fTail.simple()) { 312cb93a386Sopenharmony_ci addEndSpan(); 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci} 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci// Please keep this in sync with debugClearAll() 317cb93a386Sopenharmony_civoid SkOpSegment::clearAll() { 318cb93a386Sopenharmony_ci SkOpSpan* span = &fHead; 319cb93a386Sopenharmony_ci do { 320cb93a386Sopenharmony_ci this->clearOne(span); 321cb93a386Sopenharmony_ci } while ((span = span->next()->upCastable())); 322cb93a386Sopenharmony_ci this->globalState()->coincidence()->release(this); 323cb93a386Sopenharmony_ci} 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_ci// Please keep this in sync with debugClearOne() 326cb93a386Sopenharmony_civoid SkOpSegment::clearOne(SkOpSpan* span) { 327cb93a386Sopenharmony_ci span->setWindValue(0); 328cb93a386Sopenharmony_ci span->setOppValue(0); 329cb93a386Sopenharmony_ci this->markDone(span); 330cb93a386Sopenharmony_ci} 331cb93a386Sopenharmony_ci 332cb93a386Sopenharmony_ciSkOpSpanBase::Collapsed SkOpSegment::collapsed(double s, double e) const { 333cb93a386Sopenharmony_ci const SkOpSpanBase* span = &fHead; 334cb93a386Sopenharmony_ci do { 335cb93a386Sopenharmony_ci SkOpSpanBase::Collapsed result = span->collapsed(s, e); 336cb93a386Sopenharmony_ci if (SkOpSpanBase::Collapsed::kNo != result) { 337cb93a386Sopenharmony_ci return result; 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci } while (span->upCastable() && (span = span->upCast()->next())); 340cb93a386Sopenharmony_ci return SkOpSpanBase::Collapsed::kNo; 341cb93a386Sopenharmony_ci} 342cb93a386Sopenharmony_ci 343cb93a386Sopenharmony_cibool SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, 344cb93a386Sopenharmony_ci SkOpAngle::IncludeType includeType) { 345cb93a386Sopenharmony_ci SkOpSegment* baseSegment = baseAngle->segment(); 346cb93a386Sopenharmony_ci int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); 347cb93a386Sopenharmony_ci int sumSuWinding; 348cb93a386Sopenharmony_ci bool binary = includeType >= SkOpAngle::kBinarySingle; 349cb93a386Sopenharmony_ci if (binary) { 350cb93a386Sopenharmony_ci sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); 351cb93a386Sopenharmony_ci if (baseSegment->operand()) { 352cb93a386Sopenharmony_ci using std::swap; 353cb93a386Sopenharmony_ci swap(sumMiWinding, sumSuWinding); 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci SkOpSegment* nextSegment = nextAngle->segment(); 357cb93a386Sopenharmony_ci int maxWinding, sumWinding; 358cb93a386Sopenharmony_ci SkOpSpanBase* last = nullptr; 359cb93a386Sopenharmony_ci if (binary) { 360cb93a386Sopenharmony_ci int oppMaxWinding, oppSumWinding; 361cb93a386Sopenharmony_ci nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, 362cb93a386Sopenharmony_ci &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 363cb93a386Sopenharmony_ci if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, 364cb93a386Sopenharmony_ci nextAngle, &last)) { 365cb93a386Sopenharmony_ci return false; 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci } else { 368cb93a386Sopenharmony_ci nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, 369cb93a386Sopenharmony_ci &maxWinding, &sumWinding); 370cb93a386Sopenharmony_ci if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) { 371cb93a386Sopenharmony_ci return false; 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci nextAngle->setLastMarked(last); 375cb93a386Sopenharmony_ci return true; 376cb93a386Sopenharmony_ci} 377cb93a386Sopenharmony_ci 378cb93a386Sopenharmony_cibool SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle, 379cb93a386Sopenharmony_ci SkOpAngle::IncludeType includeType) { 380cb93a386Sopenharmony_ci SkOpSegment* baseSegment = baseAngle->segment(); 381cb93a386Sopenharmony_ci int sumMiWinding = baseSegment->updateWinding(baseAngle); 382cb93a386Sopenharmony_ci int sumSuWinding; 383cb93a386Sopenharmony_ci bool binary = includeType >= SkOpAngle::kBinarySingle; 384cb93a386Sopenharmony_ci if (binary) { 385cb93a386Sopenharmony_ci sumSuWinding = baseSegment->updateOppWinding(baseAngle); 386cb93a386Sopenharmony_ci if (baseSegment->operand()) { 387cb93a386Sopenharmony_ci using std::swap; 388cb93a386Sopenharmony_ci swap(sumMiWinding, sumSuWinding); 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci } 391cb93a386Sopenharmony_ci SkOpSegment* nextSegment = nextAngle->segment(); 392cb93a386Sopenharmony_ci int maxWinding, sumWinding; 393cb93a386Sopenharmony_ci SkOpSpanBase* last = nullptr; 394cb93a386Sopenharmony_ci if (binary) { 395cb93a386Sopenharmony_ci int oppMaxWinding, oppSumWinding; 396cb93a386Sopenharmony_ci nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, 397cb93a386Sopenharmony_ci &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 398cb93a386Sopenharmony_ci if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, 399cb93a386Sopenharmony_ci nextAngle, &last)) { 400cb93a386Sopenharmony_ci return false; 401cb93a386Sopenharmony_ci } 402cb93a386Sopenharmony_ci } else { 403cb93a386Sopenharmony_ci nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, 404cb93a386Sopenharmony_ci &maxWinding, &sumWinding); 405cb93a386Sopenharmony_ci if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) { 406cb93a386Sopenharmony_ci return false; 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci } 409cb93a386Sopenharmony_ci nextAngle->setLastMarked(last); 410cb93a386Sopenharmony_ci return true; 411cb93a386Sopenharmony_ci} 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci// at this point, the span is already ordered, or unorderable 414cb93a386Sopenharmony_ciint SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end, 415cb93a386Sopenharmony_ci SkOpAngle::IncludeType includeType) { 416cb93a386Sopenharmony_ci SkASSERT(includeType != SkOpAngle::kUnaryXor); 417cb93a386Sopenharmony_ci SkOpAngle* firstAngle = this->spanToAngle(end, start); 418cb93a386Sopenharmony_ci if (nullptr == firstAngle || nullptr == firstAngle->next()) { 419cb93a386Sopenharmony_ci return SK_NaN32; 420cb93a386Sopenharmony_ci } 421cb93a386Sopenharmony_ci // if all angles have a computed winding, 422cb93a386Sopenharmony_ci // or if no adjacent angles are orderable, 423cb93a386Sopenharmony_ci // or if adjacent orderable angles have no computed winding, 424cb93a386Sopenharmony_ci // there's nothing to do 425cb93a386Sopenharmony_ci // if two orderable angles are adjacent, and both are next to orderable angles, 426cb93a386Sopenharmony_ci // and one has winding computed, transfer to the other 427cb93a386Sopenharmony_ci SkOpAngle* baseAngle = nullptr; 428cb93a386Sopenharmony_ci bool tryReverse = false; 429cb93a386Sopenharmony_ci // look for counterclockwise transfers 430cb93a386Sopenharmony_ci SkOpAngle* angle = firstAngle->previous(); 431cb93a386Sopenharmony_ci SkOpAngle* next = angle->next(); 432cb93a386Sopenharmony_ci firstAngle = next; 433cb93a386Sopenharmony_ci do { 434cb93a386Sopenharmony_ci SkOpAngle* prior = angle; 435cb93a386Sopenharmony_ci angle = next; 436cb93a386Sopenharmony_ci next = angle->next(); 437cb93a386Sopenharmony_ci SkASSERT(prior->next() == angle); 438cb93a386Sopenharmony_ci SkASSERT(angle->next() == next); 439cb93a386Sopenharmony_ci if (prior->unorderable() || angle->unorderable() || next->unorderable()) { 440cb93a386Sopenharmony_ci baseAngle = nullptr; 441cb93a386Sopenharmony_ci continue; 442cb93a386Sopenharmony_ci } 443cb93a386Sopenharmony_ci int testWinding = angle->starter()->windSum(); 444cb93a386Sopenharmony_ci if (SK_MinS32 != testWinding) { 445cb93a386Sopenharmony_ci baseAngle = angle; 446cb93a386Sopenharmony_ci tryReverse = true; 447cb93a386Sopenharmony_ci continue; 448cb93a386Sopenharmony_ci } 449cb93a386Sopenharmony_ci if (baseAngle) { 450cb93a386Sopenharmony_ci ComputeOneSum(baseAngle, angle, includeType); 451cb93a386Sopenharmony_ci baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr; 452cb93a386Sopenharmony_ci } 453cb93a386Sopenharmony_ci } while (next != firstAngle); 454cb93a386Sopenharmony_ci if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) { 455cb93a386Sopenharmony_ci firstAngle = baseAngle; 456cb93a386Sopenharmony_ci tryReverse = true; 457cb93a386Sopenharmony_ci } 458cb93a386Sopenharmony_ci if (tryReverse) { 459cb93a386Sopenharmony_ci baseAngle = nullptr; 460cb93a386Sopenharmony_ci SkOpAngle* prior = firstAngle; 461cb93a386Sopenharmony_ci do { 462cb93a386Sopenharmony_ci angle = prior; 463cb93a386Sopenharmony_ci prior = angle->previous(); 464cb93a386Sopenharmony_ci SkASSERT(prior->next() == angle); 465cb93a386Sopenharmony_ci next = angle->next(); 466cb93a386Sopenharmony_ci if (prior->unorderable() || angle->unorderable() || next->unorderable()) { 467cb93a386Sopenharmony_ci baseAngle = nullptr; 468cb93a386Sopenharmony_ci continue; 469cb93a386Sopenharmony_ci } 470cb93a386Sopenharmony_ci int testWinding = angle->starter()->windSum(); 471cb93a386Sopenharmony_ci if (SK_MinS32 != testWinding) { 472cb93a386Sopenharmony_ci baseAngle = angle; 473cb93a386Sopenharmony_ci continue; 474cb93a386Sopenharmony_ci } 475cb93a386Sopenharmony_ci if (baseAngle) { 476cb93a386Sopenharmony_ci ComputeOneSumReverse(baseAngle, angle, includeType); 477cb93a386Sopenharmony_ci baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr; 478cb93a386Sopenharmony_ci } 479cb93a386Sopenharmony_ci } while (prior != firstAngle); 480cb93a386Sopenharmony_ci } 481cb93a386Sopenharmony_ci return start->starter(end)->windSum(); 482cb93a386Sopenharmony_ci} 483cb93a386Sopenharmony_ci 484cb93a386Sopenharmony_cibool SkOpSegment::contains(double newT) const { 485cb93a386Sopenharmony_ci const SkOpSpanBase* spanBase = &fHead; 486cb93a386Sopenharmony_ci do { 487cb93a386Sopenharmony_ci if (spanBase->ptT()->contains(this, newT)) { 488cb93a386Sopenharmony_ci return true; 489cb93a386Sopenharmony_ci } 490cb93a386Sopenharmony_ci if (spanBase == &fTail) { 491cb93a386Sopenharmony_ci break; 492cb93a386Sopenharmony_ci } 493cb93a386Sopenharmony_ci spanBase = spanBase->upCast()->next(); 494cb93a386Sopenharmony_ci } while (true); 495cb93a386Sopenharmony_ci return false; 496cb93a386Sopenharmony_ci} 497cb93a386Sopenharmony_ci 498cb93a386Sopenharmony_civoid SkOpSegment::release(const SkOpSpan* span) { 499cb93a386Sopenharmony_ci if (span->done()) { 500cb93a386Sopenharmony_ci --fDoneCount; 501cb93a386Sopenharmony_ci } 502cb93a386Sopenharmony_ci --fCount; 503cb93a386Sopenharmony_ci SkOPASSERT(fCount >= fDoneCount); 504cb93a386Sopenharmony_ci} 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci#if DEBUG_ANGLE 507cb93a386Sopenharmony_ci// called only by debugCheckNearCoincidence 508cb93a386Sopenharmony_cidouble SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const { 509cb93a386Sopenharmony_ci SkDPoint testPt = this->dPtAtT(t); 510cb93a386Sopenharmony_ci SkDLine testPerp = {{ testPt, testPt }}; 511cb93a386Sopenharmony_ci SkDVector slope = this->dSlopeAtT(t); 512cb93a386Sopenharmony_ci testPerp[1].fX += slope.fY; 513cb93a386Sopenharmony_ci testPerp[1].fY -= slope.fX; 514cb93a386Sopenharmony_ci SkIntersections i; 515cb93a386Sopenharmony_ci const SkOpSegment* oppSegment = oppAngle->segment(); 516cb93a386Sopenharmony_ci (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i); 517cb93a386Sopenharmony_ci double closestDistSq = SK_ScalarInfinity; 518cb93a386Sopenharmony_ci for (int index = 0; index < i.used(); ++index) { 519cb93a386Sopenharmony_ci if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) { 520cb93a386Sopenharmony_ci continue; 521cb93a386Sopenharmony_ci } 522cb93a386Sopenharmony_ci double testDistSq = testPt.distanceSquared(i.pt(index)); 523cb93a386Sopenharmony_ci if (closestDistSq > testDistSq) { 524cb93a386Sopenharmony_ci closestDistSq = testDistSq; 525cb93a386Sopenharmony_ci } 526cb93a386Sopenharmony_ci } 527cb93a386Sopenharmony_ci return closestDistSq; 528cb93a386Sopenharmony_ci} 529cb93a386Sopenharmony_ci#endif 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_ci/* 532cb93a386Sopenharmony_ci The M and S variable name parts stand for the operators. 533cb93a386Sopenharmony_ci Mi stands for Minuend (see wiki subtraction, analogous to difference) 534cb93a386Sopenharmony_ci Su stands for Subtrahend 535cb93a386Sopenharmony_ci The Opp variable name part designates that the value is for the Opposite operator. 536cb93a386Sopenharmony_ci Opposite values result from combining coincident spans. 537cb93a386Sopenharmony_ci */ 538cb93a386Sopenharmony_ciSkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart, 539cb93a386Sopenharmony_ci SkOpSpanBase** nextEnd, bool* unsortable, bool* simple, 540cb93a386Sopenharmony_ci SkPathOp op, int xorMiMask, int xorSuMask) { 541cb93a386Sopenharmony_ci SkOpSpanBase* start = *nextStart; 542cb93a386Sopenharmony_ci SkOpSpanBase* end = *nextEnd; 543cb93a386Sopenharmony_ci SkASSERT(start != end); 544cb93a386Sopenharmony_ci int step = start->step(end); 545cb93a386Sopenharmony_ci SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart 546cb93a386Sopenharmony_ci if ((*simple = other)) { 547cb93a386Sopenharmony_ci // mark the smaller of startIndex, endIndex done, and all adjacent 548cb93a386Sopenharmony_ci // spans with the same T value (but not 'other' spans) 549cb93a386Sopenharmony_ci#if DEBUG_WINDING 550cb93a386Sopenharmony_ci SkDebugf("%s simple\n", __FUNCTION__); 551cb93a386Sopenharmony_ci#endif 552cb93a386Sopenharmony_ci SkOpSpan* startSpan = start->starter(end); 553cb93a386Sopenharmony_ci if (startSpan->done()) { 554cb93a386Sopenharmony_ci return nullptr; 555cb93a386Sopenharmony_ci } 556cb93a386Sopenharmony_ci markDone(startSpan); 557cb93a386Sopenharmony_ci *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 558cb93a386Sopenharmony_ci return other; 559cb93a386Sopenharmony_ci } 560cb93a386Sopenharmony_ci SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 561cb93a386Sopenharmony_ci SkASSERT(endNear == end); // is this ever not end? 562cb93a386Sopenharmony_ci SkASSERT(endNear); 563cb93a386Sopenharmony_ci SkASSERT(start != endNear); 564cb93a386Sopenharmony_ci SkASSERT((start->t() < endNear->t()) ^ (step < 0)); 565cb93a386Sopenharmony_ci // more than one viable candidate -- measure angles to find best 566cb93a386Sopenharmony_ci int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp); 567cb93a386Sopenharmony_ci bool sortable = calcWinding != SK_NaN32; 568cb93a386Sopenharmony_ci if (!sortable) { 569cb93a386Sopenharmony_ci *unsortable = true; 570cb93a386Sopenharmony_ci markDone(start->starter(end)); 571cb93a386Sopenharmony_ci return nullptr; 572cb93a386Sopenharmony_ci } 573cb93a386Sopenharmony_ci SkOpAngle* angle = this->spanToAngle(end, start); 574cb93a386Sopenharmony_ci if (angle->unorderable()) { 575cb93a386Sopenharmony_ci *unsortable = true; 576cb93a386Sopenharmony_ci markDone(start->starter(end)); 577cb93a386Sopenharmony_ci return nullptr; 578cb93a386Sopenharmony_ci } 579cb93a386Sopenharmony_ci#if DEBUG_SORT 580cb93a386Sopenharmony_ci SkDebugf("%s\n", __FUNCTION__); 581cb93a386Sopenharmony_ci angle->debugLoop(); 582cb93a386Sopenharmony_ci#endif 583cb93a386Sopenharmony_ci int sumMiWinding = updateWinding(end, start); 584cb93a386Sopenharmony_ci if (sumMiWinding == SK_MinS32) { 585cb93a386Sopenharmony_ci *unsortable = true; 586cb93a386Sopenharmony_ci markDone(start->starter(end)); 587cb93a386Sopenharmony_ci return nullptr; 588cb93a386Sopenharmony_ci } 589cb93a386Sopenharmony_ci int sumSuWinding = updateOppWinding(end, start); 590cb93a386Sopenharmony_ci if (operand()) { 591cb93a386Sopenharmony_ci using std::swap; 592cb93a386Sopenharmony_ci swap(sumMiWinding, sumSuWinding); 593cb93a386Sopenharmony_ci } 594cb93a386Sopenharmony_ci SkOpAngle* nextAngle = angle->next(); 595cb93a386Sopenharmony_ci const SkOpAngle* foundAngle = nullptr; 596cb93a386Sopenharmony_ci bool foundDone = false; 597cb93a386Sopenharmony_ci // iterate through the angle, and compute everyone's winding 598cb93a386Sopenharmony_ci SkOpSegment* nextSegment; 599cb93a386Sopenharmony_ci int activeCount = 0; 600cb93a386Sopenharmony_ci do { 601cb93a386Sopenharmony_ci nextSegment = nextAngle->segment(); 602cb93a386Sopenharmony_ci bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(), 603cb93a386Sopenharmony_ci nextAngle->end(), op, &sumMiWinding, &sumSuWinding); 604cb93a386Sopenharmony_ci if (activeAngle) { 605cb93a386Sopenharmony_ci ++activeCount; 606cb93a386Sopenharmony_ci if (!foundAngle || (foundDone && activeCount & 1)) { 607cb93a386Sopenharmony_ci foundAngle = nextAngle; 608cb93a386Sopenharmony_ci foundDone = nextSegment->done(nextAngle); 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci } 611cb93a386Sopenharmony_ci if (nextSegment->done()) { 612cb93a386Sopenharmony_ci continue; 613cb93a386Sopenharmony_ci } 614cb93a386Sopenharmony_ci if (!activeAngle) { 615cb93a386Sopenharmony_ci (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr); 616cb93a386Sopenharmony_ci } 617cb93a386Sopenharmony_ci SkOpSpanBase* last = nextAngle->lastMarked(); 618cb93a386Sopenharmony_ci if (last) { 619cb93a386Sopenharmony_ci SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 620cb93a386Sopenharmony_ci *chase->append() = last; 621cb93a386Sopenharmony_ci#if DEBUG_WINDING 622cb93a386Sopenharmony_ci SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__, 623cb93a386Sopenharmony_ci last->segment()->debugID(), last->debugID()); 624cb93a386Sopenharmony_ci if (!last->final()) { 625cb93a386Sopenharmony_ci SkDebugf(" windSum=%d", last->upCast()->windSum()); 626cb93a386Sopenharmony_ci } 627cb93a386Sopenharmony_ci SkDebugf("\n"); 628cb93a386Sopenharmony_ci#endif 629cb93a386Sopenharmony_ci } 630cb93a386Sopenharmony_ci } while ((nextAngle = nextAngle->next()) != angle); 631cb93a386Sopenharmony_ci start->segment()->markDone(start->starter(end)); 632cb93a386Sopenharmony_ci if (!foundAngle) { 633cb93a386Sopenharmony_ci return nullptr; 634cb93a386Sopenharmony_ci } 635cb93a386Sopenharmony_ci *nextStart = foundAngle->start(); 636cb93a386Sopenharmony_ci *nextEnd = foundAngle->end(); 637cb93a386Sopenharmony_ci nextSegment = foundAngle->segment(); 638cb93a386Sopenharmony_ci#if DEBUG_WINDING 639cb93a386Sopenharmony_ci SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 640cb93a386Sopenharmony_ci __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 641cb93a386Sopenharmony_ci #endif 642cb93a386Sopenharmony_ci return nextSegment; 643cb93a386Sopenharmony_ci} 644cb93a386Sopenharmony_ci 645cb93a386Sopenharmony_ciSkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase, 646cb93a386Sopenharmony_ci SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) { 647cb93a386Sopenharmony_ci SkOpSpanBase* start = *nextStart; 648cb93a386Sopenharmony_ci SkOpSpanBase* end = *nextEnd; 649cb93a386Sopenharmony_ci SkASSERT(start != end); 650cb93a386Sopenharmony_ci int step = start->step(end); 651cb93a386Sopenharmony_ci SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart 652cb93a386Sopenharmony_ci if (other) { 653cb93a386Sopenharmony_ci // mark the smaller of startIndex, endIndex done, and all adjacent 654cb93a386Sopenharmony_ci // spans with the same T value (but not 'other' spans) 655cb93a386Sopenharmony_ci#if DEBUG_WINDING 656cb93a386Sopenharmony_ci SkDebugf("%s simple\n", __FUNCTION__); 657cb93a386Sopenharmony_ci#endif 658cb93a386Sopenharmony_ci SkOpSpan* startSpan = start->starter(end); 659cb93a386Sopenharmony_ci if (startSpan->done()) { 660cb93a386Sopenharmony_ci return nullptr; 661cb93a386Sopenharmony_ci } 662cb93a386Sopenharmony_ci markDone(startSpan); 663cb93a386Sopenharmony_ci *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 664cb93a386Sopenharmony_ci return other; 665cb93a386Sopenharmony_ci } 666cb93a386Sopenharmony_ci SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 667cb93a386Sopenharmony_ci SkASSERT(endNear == end); // is this ever not end? 668cb93a386Sopenharmony_ci SkASSERT(endNear); 669cb93a386Sopenharmony_ci SkASSERT(start != endNear); 670cb93a386Sopenharmony_ci SkASSERT((start->t() < endNear->t()) ^ (step < 0)); 671cb93a386Sopenharmony_ci // more than one viable candidate -- measure angles to find best 672cb93a386Sopenharmony_ci int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding); 673cb93a386Sopenharmony_ci bool sortable = calcWinding != SK_NaN32; 674cb93a386Sopenharmony_ci if (!sortable) { 675cb93a386Sopenharmony_ci *unsortable = true; 676cb93a386Sopenharmony_ci markDone(start->starter(end)); 677cb93a386Sopenharmony_ci return nullptr; 678cb93a386Sopenharmony_ci } 679cb93a386Sopenharmony_ci SkOpAngle* angle = this->spanToAngle(end, start); 680cb93a386Sopenharmony_ci if (angle->unorderable()) { 681cb93a386Sopenharmony_ci *unsortable = true; 682cb93a386Sopenharmony_ci markDone(start->starter(end)); 683cb93a386Sopenharmony_ci return nullptr; 684cb93a386Sopenharmony_ci } 685cb93a386Sopenharmony_ci#if DEBUG_SORT 686cb93a386Sopenharmony_ci SkDebugf("%s\n", __FUNCTION__); 687cb93a386Sopenharmony_ci angle->debugLoop(); 688cb93a386Sopenharmony_ci#endif 689cb93a386Sopenharmony_ci int sumWinding = updateWinding(end, start); 690cb93a386Sopenharmony_ci SkOpAngle* nextAngle = angle->next(); 691cb93a386Sopenharmony_ci const SkOpAngle* foundAngle = nullptr; 692cb93a386Sopenharmony_ci bool foundDone = false; 693cb93a386Sopenharmony_ci // iterate through the angle, and compute everyone's winding 694cb93a386Sopenharmony_ci SkOpSegment* nextSegment; 695cb93a386Sopenharmony_ci int activeCount = 0; 696cb93a386Sopenharmony_ci do { 697cb93a386Sopenharmony_ci nextSegment = nextAngle->segment(); 698cb93a386Sopenharmony_ci bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(), 699cb93a386Sopenharmony_ci &sumWinding); 700cb93a386Sopenharmony_ci if (activeAngle) { 701cb93a386Sopenharmony_ci ++activeCount; 702cb93a386Sopenharmony_ci if (!foundAngle || (foundDone && activeCount & 1)) { 703cb93a386Sopenharmony_ci foundAngle = nextAngle; 704cb93a386Sopenharmony_ci foundDone = nextSegment->done(nextAngle); 705cb93a386Sopenharmony_ci } 706cb93a386Sopenharmony_ci } 707cb93a386Sopenharmony_ci if (nextSegment->done()) { 708cb93a386Sopenharmony_ci continue; 709cb93a386Sopenharmony_ci } 710cb93a386Sopenharmony_ci if (!activeAngle) { 711cb93a386Sopenharmony_ci (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr); 712cb93a386Sopenharmony_ci } 713cb93a386Sopenharmony_ci SkOpSpanBase* last = nextAngle->lastMarked(); 714cb93a386Sopenharmony_ci if (last) { 715cb93a386Sopenharmony_ci SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 716cb93a386Sopenharmony_ci *chase->append() = last; 717cb93a386Sopenharmony_ci#if DEBUG_WINDING 718cb93a386Sopenharmony_ci SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__, 719cb93a386Sopenharmony_ci last->segment()->debugID(), last->debugID()); 720cb93a386Sopenharmony_ci if (!last->final()) { 721cb93a386Sopenharmony_ci SkDebugf(" windSum=%d", last->upCast()->windSum()); 722cb93a386Sopenharmony_ci } 723cb93a386Sopenharmony_ci SkDebugf("\n"); 724cb93a386Sopenharmony_ci#endif 725cb93a386Sopenharmony_ci } 726cb93a386Sopenharmony_ci } while ((nextAngle = nextAngle->next()) != angle); 727cb93a386Sopenharmony_ci start->segment()->markDone(start->starter(end)); 728cb93a386Sopenharmony_ci if (!foundAngle) { 729cb93a386Sopenharmony_ci return nullptr; 730cb93a386Sopenharmony_ci } 731cb93a386Sopenharmony_ci *nextStart = foundAngle->start(); 732cb93a386Sopenharmony_ci *nextEnd = foundAngle->end(); 733cb93a386Sopenharmony_ci nextSegment = foundAngle->segment(); 734cb93a386Sopenharmony_ci#if DEBUG_WINDING 735cb93a386Sopenharmony_ci SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 736cb93a386Sopenharmony_ci __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 737cb93a386Sopenharmony_ci #endif 738cb93a386Sopenharmony_ci return nextSegment; 739cb93a386Sopenharmony_ci} 740cb93a386Sopenharmony_ci 741cb93a386Sopenharmony_ciSkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, 742cb93a386Sopenharmony_ci bool* unsortable) { 743cb93a386Sopenharmony_ci SkOpSpanBase* start = *nextStart; 744cb93a386Sopenharmony_ci SkOpSpanBase* end = *nextEnd; 745cb93a386Sopenharmony_ci SkASSERT(start != end); 746cb93a386Sopenharmony_ci int step = start->step(end); 747cb93a386Sopenharmony_ci SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart 748cb93a386Sopenharmony_ci if (other) { 749cb93a386Sopenharmony_ci // mark the smaller of startIndex, endIndex done, and all adjacent 750cb93a386Sopenharmony_ci // spans with the same T value (but not 'other' spans) 751cb93a386Sopenharmony_ci#if DEBUG_WINDING 752cb93a386Sopenharmony_ci SkDebugf("%s simple\n", __FUNCTION__); 753cb93a386Sopenharmony_ci#endif 754cb93a386Sopenharmony_ci SkOpSpan* startSpan = start->starter(end); 755cb93a386Sopenharmony_ci if (startSpan->done()) { 756cb93a386Sopenharmony_ci return nullptr; 757cb93a386Sopenharmony_ci } 758cb93a386Sopenharmony_ci markDone(startSpan); 759cb93a386Sopenharmony_ci *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev(); 760cb93a386Sopenharmony_ci return other; 761cb93a386Sopenharmony_ci } 762cb93a386Sopenharmony_ci SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \ 763cb93a386Sopenharmony_ci : (*nextStart)->prev()); 764cb93a386Sopenharmony_ci SkASSERT(endNear == end); // is this ever not end? 765cb93a386Sopenharmony_ci SkASSERT(endNear); 766cb93a386Sopenharmony_ci SkASSERT(start != endNear); 767cb93a386Sopenharmony_ci SkASSERT((start->t() < endNear->t()) ^ (step < 0)); 768cb93a386Sopenharmony_ci SkOpAngle* angle = this->spanToAngle(end, start); 769cb93a386Sopenharmony_ci if (!angle || angle->unorderable()) { 770cb93a386Sopenharmony_ci *unsortable = true; 771cb93a386Sopenharmony_ci markDone(start->starter(end)); 772cb93a386Sopenharmony_ci return nullptr; 773cb93a386Sopenharmony_ci } 774cb93a386Sopenharmony_ci#if DEBUG_SORT 775cb93a386Sopenharmony_ci SkDebugf("%s\n", __FUNCTION__); 776cb93a386Sopenharmony_ci angle->debugLoop(); 777cb93a386Sopenharmony_ci#endif 778cb93a386Sopenharmony_ci SkOpAngle* nextAngle = angle->next(); 779cb93a386Sopenharmony_ci const SkOpAngle* foundAngle = nullptr; 780cb93a386Sopenharmony_ci bool foundDone = false; 781cb93a386Sopenharmony_ci // iterate through the angle, and compute everyone's winding 782cb93a386Sopenharmony_ci SkOpSegment* nextSegment; 783cb93a386Sopenharmony_ci int activeCount = 0; 784cb93a386Sopenharmony_ci do { 785cb93a386Sopenharmony_ci if (!nextAngle) { 786cb93a386Sopenharmony_ci return nullptr; 787cb93a386Sopenharmony_ci } 788cb93a386Sopenharmony_ci nextSegment = nextAngle->segment(); 789cb93a386Sopenharmony_ci ++activeCount; 790cb93a386Sopenharmony_ci if (!foundAngle || (foundDone && activeCount & 1)) { 791cb93a386Sopenharmony_ci foundAngle = nextAngle; 792cb93a386Sopenharmony_ci if (!(foundDone = nextSegment->done(nextAngle))) { 793cb93a386Sopenharmony_ci break; 794cb93a386Sopenharmony_ci } 795cb93a386Sopenharmony_ci } 796cb93a386Sopenharmony_ci nextAngle = nextAngle->next(); 797cb93a386Sopenharmony_ci } while (nextAngle != angle); 798cb93a386Sopenharmony_ci start->segment()->markDone(start->starter(end)); 799cb93a386Sopenharmony_ci if (!foundAngle) { 800cb93a386Sopenharmony_ci return nullptr; 801cb93a386Sopenharmony_ci } 802cb93a386Sopenharmony_ci *nextStart = foundAngle->start(); 803cb93a386Sopenharmony_ci *nextEnd = foundAngle->end(); 804cb93a386Sopenharmony_ci nextSegment = foundAngle->segment(); 805cb93a386Sopenharmony_ci#if DEBUG_WINDING 806cb93a386Sopenharmony_ci SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 807cb93a386Sopenharmony_ci __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 808cb93a386Sopenharmony_ci #endif 809cb93a386Sopenharmony_ci return nextSegment; 810cb93a386Sopenharmony_ci} 811cb93a386Sopenharmony_ci 812cb93a386Sopenharmony_ciSkOpGlobalState* SkOpSegment::globalState() const { 813cb93a386Sopenharmony_ci return contour()->globalState(); 814cb93a386Sopenharmony_ci} 815cb93a386Sopenharmony_ci 816cb93a386Sopenharmony_civoid SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) { 817cb93a386Sopenharmony_ci fContour = contour; 818cb93a386Sopenharmony_ci fNext = nullptr; 819cb93a386Sopenharmony_ci fPts = pts; 820cb93a386Sopenharmony_ci fWeight = weight; 821cb93a386Sopenharmony_ci fVerb = verb; 822cb93a386Sopenharmony_ci fCount = 0; 823cb93a386Sopenharmony_ci fDoneCount = 0; 824cb93a386Sopenharmony_ci fVisited = false; 825cb93a386Sopenharmony_ci SkOpSpan* zeroSpan = &fHead; 826cb93a386Sopenharmony_ci zeroSpan->init(this, nullptr, 0, fPts[0]); 827cb93a386Sopenharmony_ci SkOpSpanBase* oneSpan = &fTail; 828cb93a386Sopenharmony_ci zeroSpan->setNext(oneSpan); 829cb93a386Sopenharmony_ci oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); 830cb93a386Sopenharmony_ci SkDEBUGCODE(fID = globalState()->nextSegmentID()); 831cb93a386Sopenharmony_ci} 832cb93a386Sopenharmony_ci 833cb93a386Sopenharmony_cibool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { 834cb93a386Sopenharmony_ci SkDPoint cPt = this->dPtAtT(t); 835cb93a386Sopenharmony_ci SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t); 836cb93a386Sopenharmony_ci SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; 837cb93a386Sopenharmony_ci SkIntersections i; 838cb93a386Sopenharmony_ci (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i); 839cb93a386Sopenharmony_ci int used = i.used(); 840cb93a386Sopenharmony_ci for (int index = 0; index < used; ++index) { 841cb93a386Sopenharmony_ci if (cPt.roughlyEqual(i.pt(index))) { 842cb93a386Sopenharmony_ci return true; 843cb93a386Sopenharmony_ci } 844cb93a386Sopenharmony_ci } 845cb93a386Sopenharmony_ci return false; 846cb93a386Sopenharmony_ci} 847cb93a386Sopenharmony_ci 848cb93a386Sopenharmony_cibool SkOpSegment::isXor() const { 849cb93a386Sopenharmony_ci return fContour->isXor(); 850cb93a386Sopenharmony_ci} 851cb93a386Sopenharmony_ci 852cb93a386Sopenharmony_civoid SkOpSegment::markAllDone() { 853cb93a386Sopenharmony_ci SkOpSpan* span = this->head(); 854cb93a386Sopenharmony_ci do { 855cb93a386Sopenharmony_ci this->markDone(span); 856cb93a386Sopenharmony_ci } while ((span = span->next()->upCastable())); 857cb93a386Sopenharmony_ci} 858cb93a386Sopenharmony_ci 859cb93a386Sopenharmony_ci bool SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end, SkOpSpanBase** found) { 860cb93a386Sopenharmony_ci int step = start->step(end); 861cb93a386Sopenharmony_ci SkOpSpan* minSpan = start->starter(end); 862cb93a386Sopenharmony_ci markDone(minSpan); 863cb93a386Sopenharmony_ci SkOpSpanBase* last = nullptr; 864cb93a386Sopenharmony_ci SkOpSegment* other = this; 865cb93a386Sopenharmony_ci SkOpSpan* priorDone = nullptr; 866cb93a386Sopenharmony_ci SkOpSpan* lastDone = nullptr; 867cb93a386Sopenharmony_ci int safetyNet = 100000; 868cb93a386Sopenharmony_ci while ((other = other->nextChase(&start, &step, &minSpan, &last))) { 869cb93a386Sopenharmony_ci if (!--safetyNet) { 870cb93a386Sopenharmony_ci return false; 871cb93a386Sopenharmony_ci } 872cb93a386Sopenharmony_ci if (other->done()) { 873cb93a386Sopenharmony_ci SkASSERT(!last); 874cb93a386Sopenharmony_ci break; 875cb93a386Sopenharmony_ci } 876cb93a386Sopenharmony_ci if (lastDone == minSpan || priorDone == minSpan) { 877cb93a386Sopenharmony_ci if (found) { 878cb93a386Sopenharmony_ci *found = nullptr; 879cb93a386Sopenharmony_ci } 880cb93a386Sopenharmony_ci return true; 881cb93a386Sopenharmony_ci } 882cb93a386Sopenharmony_ci other->markDone(minSpan); 883cb93a386Sopenharmony_ci priorDone = lastDone; 884cb93a386Sopenharmony_ci lastDone = minSpan; 885cb93a386Sopenharmony_ci } 886cb93a386Sopenharmony_ci if (found) { 887cb93a386Sopenharmony_ci *found = last; 888cb93a386Sopenharmony_ci } 889cb93a386Sopenharmony_ci return true; 890cb93a386Sopenharmony_ci} 891cb93a386Sopenharmony_ci 892cb93a386Sopenharmony_cibool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding, 893cb93a386Sopenharmony_ci SkOpSpanBase** lastPtr) { 894cb93a386Sopenharmony_ci SkOpSpan* spanStart = start->starter(end); 895cb93a386Sopenharmony_ci int step = start->step(end); 896cb93a386Sopenharmony_ci bool success = markWinding(spanStart, winding); 897cb93a386Sopenharmony_ci SkOpSpanBase* last = nullptr; 898cb93a386Sopenharmony_ci SkOpSegment* other = this; 899cb93a386Sopenharmony_ci int safetyNet = 100000; 900cb93a386Sopenharmony_ci while ((other = other->nextChase(&start, &step, &spanStart, &last))) { 901cb93a386Sopenharmony_ci if (!--safetyNet) { 902cb93a386Sopenharmony_ci return false; 903cb93a386Sopenharmony_ci } 904cb93a386Sopenharmony_ci if (spanStart->windSum() != SK_MinS32) { 905cb93a386Sopenharmony_ci// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive? 906cb93a386Sopenharmony_ci SkASSERT(!last); 907cb93a386Sopenharmony_ci break; 908cb93a386Sopenharmony_ci } 909cb93a386Sopenharmony_ci (void) other->markWinding(spanStart, winding); 910cb93a386Sopenharmony_ci } 911cb93a386Sopenharmony_ci if (lastPtr) { 912cb93a386Sopenharmony_ci *lastPtr = last; 913cb93a386Sopenharmony_ci } 914cb93a386Sopenharmony_ci return success; 915cb93a386Sopenharmony_ci} 916cb93a386Sopenharmony_ci 917cb93a386Sopenharmony_cibool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, 918cb93a386Sopenharmony_ci int winding, int oppWinding, SkOpSpanBase** lastPtr) { 919cb93a386Sopenharmony_ci SkOpSpan* spanStart = start->starter(end); 920cb93a386Sopenharmony_ci int step = start->step(end); 921cb93a386Sopenharmony_ci bool success = markWinding(spanStart, winding, oppWinding); 922cb93a386Sopenharmony_ci SkOpSpanBase* last = nullptr; 923cb93a386Sopenharmony_ci SkOpSegment* other = this; 924cb93a386Sopenharmony_ci int safetyNet = 100000; 925cb93a386Sopenharmony_ci while ((other = other->nextChase(&start, &step, &spanStart, &last))) { 926cb93a386Sopenharmony_ci if (!--safetyNet) { 927cb93a386Sopenharmony_ci return false; 928cb93a386Sopenharmony_ci } 929cb93a386Sopenharmony_ci if (spanStart->windSum() != SK_MinS32) { 930cb93a386Sopenharmony_ci if (this->operand() == other->operand()) { 931cb93a386Sopenharmony_ci if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) { 932cb93a386Sopenharmony_ci this->globalState()->setWindingFailed(); 933cb93a386Sopenharmony_ci return true; // ... but let it succeed anyway 934cb93a386Sopenharmony_ci } 935cb93a386Sopenharmony_ci } else { 936cb93a386Sopenharmony_ci FAIL_IF(spanStart->windSum() != oppWinding); 937cb93a386Sopenharmony_ci FAIL_IF(spanStart->oppSum() != winding); 938cb93a386Sopenharmony_ci } 939cb93a386Sopenharmony_ci SkASSERT(!last); 940cb93a386Sopenharmony_ci break; 941cb93a386Sopenharmony_ci } 942cb93a386Sopenharmony_ci if (this->operand() == other->operand()) { 943cb93a386Sopenharmony_ci (void) other->markWinding(spanStart, winding, oppWinding); 944cb93a386Sopenharmony_ci } else { 945cb93a386Sopenharmony_ci (void) other->markWinding(spanStart, oppWinding, winding); 946cb93a386Sopenharmony_ci } 947cb93a386Sopenharmony_ci } 948cb93a386Sopenharmony_ci if (lastPtr) { 949cb93a386Sopenharmony_ci *lastPtr = last; 950cb93a386Sopenharmony_ci } 951cb93a386Sopenharmony_ci return success; 952cb93a386Sopenharmony_ci} 953cb93a386Sopenharmony_ci 954cb93a386Sopenharmony_cibool SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle, 955cb93a386Sopenharmony_ci SkOpSpanBase** result) { 956cb93a386Sopenharmony_ci SkASSERT(angle->segment() == this); 957cb93a386Sopenharmony_ci if (UseInnerWinding(maxWinding, sumWinding)) { 958cb93a386Sopenharmony_ci maxWinding = sumWinding; 959cb93a386Sopenharmony_ci } 960cb93a386Sopenharmony_ci if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, result)) { 961cb93a386Sopenharmony_ci return false; 962cb93a386Sopenharmony_ci } 963cb93a386Sopenharmony_ci#if DEBUG_WINDING 964cb93a386Sopenharmony_ci SkOpSpanBase* last = *result; 965cb93a386Sopenharmony_ci if (last) { 966cb93a386Sopenharmony_ci SkDebugf("%s last seg=%d span=%d", __FUNCTION__, 967cb93a386Sopenharmony_ci last->segment()->debugID(), last->debugID()); 968cb93a386Sopenharmony_ci if (!last->final()) { 969cb93a386Sopenharmony_ci SkDebugf(" windSum="); 970cb93a386Sopenharmony_ci SkPathOpsDebug::WindingPrintf(last->upCast()->windSum()); 971cb93a386Sopenharmony_ci } 972cb93a386Sopenharmony_ci SkDebugf("\n"); 973cb93a386Sopenharmony_ci } 974cb93a386Sopenharmony_ci#endif 975cb93a386Sopenharmony_ci return true; 976cb93a386Sopenharmony_ci} 977cb93a386Sopenharmony_ci 978cb93a386Sopenharmony_cibool SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding, 979cb93a386Sopenharmony_ci int oppSumWinding, const SkOpAngle* angle, SkOpSpanBase** result) { 980cb93a386Sopenharmony_ci SkASSERT(angle->segment() == this); 981cb93a386Sopenharmony_ci if (UseInnerWinding(maxWinding, sumWinding)) { 982cb93a386Sopenharmony_ci maxWinding = sumWinding; 983cb93a386Sopenharmony_ci } 984cb93a386Sopenharmony_ci if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) { 985cb93a386Sopenharmony_ci oppMaxWinding = oppSumWinding; 986cb93a386Sopenharmony_ci } 987cb93a386Sopenharmony_ci // caller doesn't require that this marks anything 988cb93a386Sopenharmony_ci if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, result)) { 989cb93a386Sopenharmony_ci return false; 990cb93a386Sopenharmony_ci } 991cb93a386Sopenharmony_ci#if DEBUG_WINDING 992cb93a386Sopenharmony_ci if (result) { 993cb93a386Sopenharmony_ci SkOpSpanBase* last = *result; 994cb93a386Sopenharmony_ci if (last) { 995cb93a386Sopenharmony_ci SkDebugf("%s last segment=%d span=%d", __FUNCTION__, 996cb93a386Sopenharmony_ci last->segment()->debugID(), last->debugID()); 997cb93a386Sopenharmony_ci if (!last->final()) { 998cb93a386Sopenharmony_ci SkDebugf(" windSum="); 999cb93a386Sopenharmony_ci SkPathOpsDebug::WindingPrintf(last->upCast()->windSum()); 1000cb93a386Sopenharmony_ci } 1001cb93a386Sopenharmony_ci SkDebugf(" \n"); 1002cb93a386Sopenharmony_ci } 1003cb93a386Sopenharmony_ci } 1004cb93a386Sopenharmony_ci#endif 1005cb93a386Sopenharmony_ci return true; 1006cb93a386Sopenharmony_ci} 1007cb93a386Sopenharmony_ci 1008cb93a386Sopenharmony_civoid SkOpSegment::markDone(SkOpSpan* span) { 1009cb93a386Sopenharmony_ci SkASSERT(this == span->segment()); 1010cb93a386Sopenharmony_ci if (span->done()) { 1011cb93a386Sopenharmony_ci return; 1012cb93a386Sopenharmony_ci } 1013cb93a386Sopenharmony_ci#if DEBUG_MARK_DONE 1014cb93a386Sopenharmony_ci debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum()); 1015cb93a386Sopenharmony_ci#endif 1016cb93a386Sopenharmony_ci span->setDone(true); 1017cb93a386Sopenharmony_ci ++fDoneCount; 1018cb93a386Sopenharmony_ci debugValidate(); 1019cb93a386Sopenharmony_ci} 1020cb93a386Sopenharmony_ci 1021cb93a386Sopenharmony_cibool SkOpSegment::markWinding(SkOpSpan* span, int winding) { 1022cb93a386Sopenharmony_ci SkASSERT(this == span->segment()); 1023cb93a386Sopenharmony_ci SkASSERT(winding); 1024cb93a386Sopenharmony_ci if (span->done()) { 1025cb93a386Sopenharmony_ci return false; 1026cb93a386Sopenharmony_ci } 1027cb93a386Sopenharmony_ci#if DEBUG_MARK_DONE 1028cb93a386Sopenharmony_ci debugShowNewWinding(__FUNCTION__, span, winding); 1029cb93a386Sopenharmony_ci#endif 1030cb93a386Sopenharmony_ci span->setWindSum(winding); 1031cb93a386Sopenharmony_ci debugValidate(); 1032cb93a386Sopenharmony_ci return true; 1033cb93a386Sopenharmony_ci} 1034cb93a386Sopenharmony_ci 1035cb93a386Sopenharmony_cibool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) { 1036cb93a386Sopenharmony_ci SkASSERT(this == span->segment()); 1037cb93a386Sopenharmony_ci SkASSERT(winding || oppWinding); 1038cb93a386Sopenharmony_ci if (span->done()) { 1039cb93a386Sopenharmony_ci return false; 1040cb93a386Sopenharmony_ci } 1041cb93a386Sopenharmony_ci#if DEBUG_MARK_DONE 1042cb93a386Sopenharmony_ci debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); 1043cb93a386Sopenharmony_ci#endif 1044cb93a386Sopenharmony_ci span->setWindSum(winding); 1045cb93a386Sopenharmony_ci span->setOppSum(oppWinding); 1046cb93a386Sopenharmony_ci debugValidate(); 1047cb93a386Sopenharmony_ci return true; 1048cb93a386Sopenharmony_ci} 1049cb93a386Sopenharmony_ci 1050cb93a386Sopenharmony_cibool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT, 1051cb93a386Sopenharmony_ci const SkPoint& testPt) const { 1052cb93a386Sopenharmony_ci SkASSERT(this == base->segment()); 1053cb93a386Sopenharmony_ci if (this == testParent) { 1054cb93a386Sopenharmony_ci if (precisely_equal(base->fT, testT)) { 1055cb93a386Sopenharmony_ci return true; 1056cb93a386Sopenharmony_ci } 1057cb93a386Sopenharmony_ci } 1058cb93a386Sopenharmony_ci if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { 1059cb93a386Sopenharmony_ci return false; 1060cb93a386Sopenharmony_ci } 1061cb93a386Sopenharmony_ci return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); 1062cb93a386Sopenharmony_ci} 1063cb93a386Sopenharmony_ci 1064cb93a386Sopenharmony_cistatic SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { 1065cb93a386Sopenharmony_ci if (last) { 1066cb93a386Sopenharmony_ci *last = endSpan; 1067cb93a386Sopenharmony_ci } 1068cb93a386Sopenharmony_ci return nullptr; 1069cb93a386Sopenharmony_ci} 1070cb93a386Sopenharmony_ci 1071cb93a386Sopenharmony_ciSkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr, 1072cb93a386Sopenharmony_ci SkOpSpanBase** last) const { 1073cb93a386Sopenharmony_ci SkOpSpanBase* origStart = *startPtr; 1074cb93a386Sopenharmony_ci int step = *stepPtr; 1075cb93a386Sopenharmony_ci SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev(); 1076cb93a386Sopenharmony_ci SkASSERT(endSpan); 1077cb93a386Sopenharmony_ci SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle(); 1078cb93a386Sopenharmony_ci SkOpSpanBase* foundSpan; 1079cb93a386Sopenharmony_ci SkOpSpanBase* otherEnd; 1080cb93a386Sopenharmony_ci SkOpSegment* other; 1081cb93a386Sopenharmony_ci if (angle == nullptr) { 1082cb93a386Sopenharmony_ci if (endSpan->t() != 0 && endSpan->t() != 1) { 1083cb93a386Sopenharmony_ci return nullptr; 1084cb93a386Sopenharmony_ci } 1085cb93a386Sopenharmony_ci SkOpPtT* otherPtT = endSpan->ptT()->next(); 1086cb93a386Sopenharmony_ci other = otherPtT->segment(); 1087cb93a386Sopenharmony_ci foundSpan = otherPtT->span(); 1088cb93a386Sopenharmony_ci otherEnd = step > 0 1089cb93a386Sopenharmony_ci ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr 1090cb93a386Sopenharmony_ci : foundSpan->prev(); 1091cb93a386Sopenharmony_ci } else { 1092cb93a386Sopenharmony_ci int loopCount = angle->loopCount(); 1093cb93a386Sopenharmony_ci if (loopCount > 2) { 1094cb93a386Sopenharmony_ci return set_last(last, endSpan); 1095cb93a386Sopenharmony_ci } 1096cb93a386Sopenharmony_ci const SkOpAngle* next = angle->next(); 1097cb93a386Sopenharmony_ci if (nullptr == next) { 1098cb93a386Sopenharmony_ci return nullptr; 1099cb93a386Sopenharmony_ci } 1100cb93a386Sopenharmony_ci#if DEBUG_WINDING 1101cb93a386Sopenharmony_ci if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor() 1102cb93a386Sopenharmony_ci && !next->segment()->contour()->isXor()) { 1103cb93a386Sopenharmony_ci SkDebugf("%s mismatched signs\n", __FUNCTION__); 1104cb93a386Sopenharmony_ci } 1105cb93a386Sopenharmony_ci#endif 1106cb93a386Sopenharmony_ci other = next->segment(); 1107cb93a386Sopenharmony_ci foundSpan = endSpan = next->start(); 1108cb93a386Sopenharmony_ci otherEnd = next->end(); 1109cb93a386Sopenharmony_ci } 1110cb93a386Sopenharmony_ci if (!otherEnd) { 1111cb93a386Sopenharmony_ci return nullptr; 1112cb93a386Sopenharmony_ci } 1113cb93a386Sopenharmony_ci int foundStep = foundSpan->step(otherEnd); 1114cb93a386Sopenharmony_ci if (*stepPtr != foundStep) { 1115cb93a386Sopenharmony_ci return set_last(last, endSpan); 1116cb93a386Sopenharmony_ci } 1117cb93a386Sopenharmony_ci SkASSERT(*startPtr); 1118cb93a386Sopenharmony_ci// SkASSERT(otherEnd >= 0); 1119cb93a386Sopenharmony_ci SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast(); 1120cb93a386Sopenharmony_ci SkOpSpan* foundMin = foundSpan->starter(otherEnd); 1121cb93a386Sopenharmony_ci if (foundMin->windValue() != origMin->windValue() 1122cb93a386Sopenharmony_ci || foundMin->oppValue() != origMin->oppValue()) { 1123cb93a386Sopenharmony_ci return set_last(last, endSpan); 1124cb93a386Sopenharmony_ci } 1125cb93a386Sopenharmony_ci *startPtr = foundSpan; 1126cb93a386Sopenharmony_ci *stepPtr = foundStep; 1127cb93a386Sopenharmony_ci if (minPtr) { 1128cb93a386Sopenharmony_ci *minPtr = foundMin; 1129cb93a386Sopenharmony_ci } 1130cb93a386Sopenharmony_ci return other; 1131cb93a386Sopenharmony_ci} 1132cb93a386Sopenharmony_ci 1133cb93a386Sopenharmony_ci// Please keep this in sync with DebugClearVisited() 1134cb93a386Sopenharmony_civoid SkOpSegment::ClearVisited(SkOpSpanBase* span) { 1135cb93a386Sopenharmony_ci // reset visited flag back to false 1136cb93a386Sopenharmony_ci do { 1137cb93a386Sopenharmony_ci SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; 1138cb93a386Sopenharmony_ci while ((ptT = ptT->next()) != stopPtT) { 1139cb93a386Sopenharmony_ci SkOpSegment* opp = ptT->segment(); 1140cb93a386Sopenharmony_ci opp->resetVisited(); 1141cb93a386Sopenharmony_ci } 1142cb93a386Sopenharmony_ci } while (!span->final() && (span = span->upCast()->next())); 1143cb93a386Sopenharmony_ci} 1144cb93a386Sopenharmony_ci 1145cb93a386Sopenharmony_ci// Please keep this in sync with debugMissingCoincidence() 1146cb93a386Sopenharmony_ci// look for pairs of undetected coincident curves 1147cb93a386Sopenharmony_ci// assumes that segments going in have visited flag clear 1148cb93a386Sopenharmony_ci// Even though pairs of curves correct detect coincident runs, a run may be missed 1149cb93a386Sopenharmony_ci// if the coincidence is a product of multiple intersections. For instance, given 1150cb93a386Sopenharmony_ci// curves A, B, and C: 1151cb93a386Sopenharmony_ci// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near 1152cb93a386Sopenharmony_ci// the end of C that the intersection is replaced with the end of C. 1153cb93a386Sopenharmony_ci// Even though A-B correctly do not detect an intersection at point 2, 1154cb93a386Sopenharmony_ci// the resulting run from point 1 to point 2 is coincident on A and B. 1155cb93a386Sopenharmony_cibool SkOpSegment::missingCoincidence() { 1156cb93a386Sopenharmony_ci if (this->done()) { 1157cb93a386Sopenharmony_ci return false; 1158cb93a386Sopenharmony_ci } 1159cb93a386Sopenharmony_ci SkOpSpan* prior = nullptr; 1160cb93a386Sopenharmony_ci SkOpSpanBase* spanBase = &fHead; 1161cb93a386Sopenharmony_ci bool result = false; 1162cb93a386Sopenharmony_ci int safetyNet = 100000; 1163cb93a386Sopenharmony_ci do { 1164cb93a386Sopenharmony_ci SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; 1165cb93a386Sopenharmony_ci SkOPASSERT(ptT->span() == spanBase); 1166cb93a386Sopenharmony_ci while ((ptT = ptT->next()) != spanStopPtT) { 1167cb93a386Sopenharmony_ci if (!--safetyNet) { 1168cb93a386Sopenharmony_ci return false; 1169cb93a386Sopenharmony_ci } 1170cb93a386Sopenharmony_ci if (ptT->deleted()) { 1171cb93a386Sopenharmony_ci continue; 1172cb93a386Sopenharmony_ci } 1173cb93a386Sopenharmony_ci SkOpSegment* opp = ptT->span()->segment(); 1174cb93a386Sopenharmony_ci if (opp->done()) { 1175cb93a386Sopenharmony_ci continue; 1176cb93a386Sopenharmony_ci } 1177cb93a386Sopenharmony_ci // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence 1178cb93a386Sopenharmony_ci if (!opp->visited()) { 1179cb93a386Sopenharmony_ci continue; 1180cb93a386Sopenharmony_ci } 1181cb93a386Sopenharmony_ci if (spanBase == &fHead) { 1182cb93a386Sopenharmony_ci continue; 1183cb93a386Sopenharmony_ci } 1184cb93a386Sopenharmony_ci if (ptT->segment() == this) { 1185cb93a386Sopenharmony_ci continue; 1186cb93a386Sopenharmony_ci } 1187cb93a386Sopenharmony_ci SkOpSpan* span = spanBase->upCastable(); 1188cb93a386Sopenharmony_ci // FIXME?: this assumes that if the opposite segment is coincident then no more 1189cb93a386Sopenharmony_ci // coincidence needs to be detected. This may not be true. 1190cb93a386Sopenharmony_ci if (span && span->containsCoincidence(opp)) { 1191cb93a386Sopenharmony_ci continue; 1192cb93a386Sopenharmony_ci } 1193cb93a386Sopenharmony_ci if (spanBase->containsCoinEnd(opp)) { 1194cb93a386Sopenharmony_ci continue; 1195cb93a386Sopenharmony_ci } 1196cb93a386Sopenharmony_ci SkOpPtT* priorPtT = nullptr, * priorStopPtT; 1197cb93a386Sopenharmony_ci // find prior span containing opp segment 1198cb93a386Sopenharmony_ci SkOpSegment* priorOpp = nullptr; 1199cb93a386Sopenharmony_ci SkOpSpan* priorTest = spanBase->prev(); 1200cb93a386Sopenharmony_ci while (!priorOpp && priorTest) { 1201cb93a386Sopenharmony_ci priorStopPtT = priorPtT = priorTest->ptT(); 1202cb93a386Sopenharmony_ci while ((priorPtT = priorPtT->next()) != priorStopPtT) { 1203cb93a386Sopenharmony_ci if (priorPtT->deleted()) { 1204cb93a386Sopenharmony_ci continue; 1205cb93a386Sopenharmony_ci } 1206cb93a386Sopenharmony_ci SkOpSegment* segment = priorPtT->span()->segment(); 1207cb93a386Sopenharmony_ci if (segment == opp) { 1208cb93a386Sopenharmony_ci prior = priorTest; 1209cb93a386Sopenharmony_ci priorOpp = opp; 1210cb93a386Sopenharmony_ci break; 1211cb93a386Sopenharmony_ci } 1212cb93a386Sopenharmony_ci } 1213cb93a386Sopenharmony_ci priorTest = priorTest->prev(); 1214cb93a386Sopenharmony_ci } 1215cb93a386Sopenharmony_ci if (!priorOpp) { 1216cb93a386Sopenharmony_ci continue; 1217cb93a386Sopenharmony_ci } 1218cb93a386Sopenharmony_ci if (priorPtT == ptT) { 1219cb93a386Sopenharmony_ci continue; 1220cb93a386Sopenharmony_ci } 1221cb93a386Sopenharmony_ci SkOpPtT* oppStart = prior->ptT(); 1222cb93a386Sopenharmony_ci SkOpPtT* oppEnd = spanBase->ptT(); 1223cb93a386Sopenharmony_ci bool swapped = priorPtT->fT > ptT->fT; 1224cb93a386Sopenharmony_ci if (swapped) { 1225cb93a386Sopenharmony_ci using std::swap; 1226cb93a386Sopenharmony_ci swap(priorPtT, ptT); 1227cb93a386Sopenharmony_ci swap(oppStart, oppEnd); 1228cb93a386Sopenharmony_ci } 1229cb93a386Sopenharmony_ci SkOpCoincidence* coincidences = this->globalState()->coincidence(); 1230cb93a386Sopenharmony_ci SkOpPtT* rootPriorPtT = priorPtT->span()->ptT(); 1231cb93a386Sopenharmony_ci SkOpPtT* rootPtT = ptT->span()->ptT(); 1232cb93a386Sopenharmony_ci SkOpPtT* rootOppStart = oppStart->span()->ptT(); 1233cb93a386Sopenharmony_ci SkOpPtT* rootOppEnd = oppEnd->span()->ptT(); 1234cb93a386Sopenharmony_ci if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) { 1235cb93a386Sopenharmony_ci goto swapBack; 1236cb93a386Sopenharmony_ci } 1237cb93a386Sopenharmony_ci if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) { 1238cb93a386Sopenharmony_ci // mark coincidence 1239cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE 1240cb93a386Sopenharmony_ci SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__, 1241cb93a386Sopenharmony_ci rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(), 1242cb93a386Sopenharmony_ci rootOppEnd->debugID()); 1243cb93a386Sopenharmony_ci#endif 1244cb93a386Sopenharmony_ci if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) { 1245cb93a386Sopenharmony_ci coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd); 1246cb93a386Sopenharmony_ci } 1247cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 1248cb93a386Sopenharmony_ci SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)); 1249cb93a386Sopenharmony_ci#endif 1250cb93a386Sopenharmony_ci result = true; 1251cb93a386Sopenharmony_ci } 1252cb93a386Sopenharmony_ci swapBack: 1253cb93a386Sopenharmony_ci if (swapped) { 1254cb93a386Sopenharmony_ci using std::swap; 1255cb93a386Sopenharmony_ci swap(priorPtT, ptT); 1256cb93a386Sopenharmony_ci } 1257cb93a386Sopenharmony_ci } 1258cb93a386Sopenharmony_ci } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next())); 1259cb93a386Sopenharmony_ci ClearVisited(&fHead); 1260cb93a386Sopenharmony_ci return result; 1261cb93a386Sopenharmony_ci} 1262cb93a386Sopenharmony_ci 1263cb93a386Sopenharmony_ci// please keep this in sync with debugMoveMultiples() 1264cb93a386Sopenharmony_ci// if a span has more than one intersection, merge the other segments' span as needed 1265cb93a386Sopenharmony_cibool SkOpSegment::moveMultiples() { 1266cb93a386Sopenharmony_ci debugValidate(); 1267cb93a386Sopenharmony_ci SkOpSpanBase* test = &fHead; 1268cb93a386Sopenharmony_ci do { 1269cb93a386Sopenharmony_ci int addCount = test->spanAddsCount(); 1270cb93a386Sopenharmony_ci// FAIL_IF(addCount < 1); 1271cb93a386Sopenharmony_ci if (addCount <= 1) { 1272cb93a386Sopenharmony_ci continue; 1273cb93a386Sopenharmony_ci } 1274cb93a386Sopenharmony_ci SkOpPtT* startPtT = test->ptT(); 1275cb93a386Sopenharmony_ci SkOpPtT* testPtT = startPtT; 1276cb93a386Sopenharmony_ci int safetyHatch = 1000000; 1277cb93a386Sopenharmony_ci do { // iterate through all spans associated with start 1278cb93a386Sopenharmony_ci if (!--safetyHatch) { 1279cb93a386Sopenharmony_ci return false; 1280cb93a386Sopenharmony_ci } 1281cb93a386Sopenharmony_ci SkOpSpanBase* oppSpan = testPtT->span(); 1282cb93a386Sopenharmony_ci if (oppSpan->spanAddsCount() == addCount) { 1283cb93a386Sopenharmony_ci continue; 1284cb93a386Sopenharmony_ci } 1285cb93a386Sopenharmony_ci if (oppSpan->deleted()) { 1286cb93a386Sopenharmony_ci continue; 1287cb93a386Sopenharmony_ci } 1288cb93a386Sopenharmony_ci SkOpSegment* oppSegment = oppSpan->segment(); 1289cb93a386Sopenharmony_ci if (oppSegment == this) { 1290cb93a386Sopenharmony_ci continue; 1291cb93a386Sopenharmony_ci } 1292cb93a386Sopenharmony_ci // find range of spans to consider merging 1293cb93a386Sopenharmony_ci SkOpSpanBase* oppPrev = oppSpan; 1294cb93a386Sopenharmony_ci SkOpSpanBase* oppFirst = oppSpan; 1295cb93a386Sopenharmony_ci while ((oppPrev = oppPrev->prev())) { 1296cb93a386Sopenharmony_ci if (!roughly_equal(oppPrev->t(), oppSpan->t())) { 1297cb93a386Sopenharmony_ci break; 1298cb93a386Sopenharmony_ci } 1299cb93a386Sopenharmony_ci if (oppPrev->spanAddsCount() == addCount) { 1300cb93a386Sopenharmony_ci continue; 1301cb93a386Sopenharmony_ci } 1302cb93a386Sopenharmony_ci if (oppPrev->deleted()) { 1303cb93a386Sopenharmony_ci continue; 1304cb93a386Sopenharmony_ci } 1305cb93a386Sopenharmony_ci oppFirst = oppPrev; 1306cb93a386Sopenharmony_ci } 1307cb93a386Sopenharmony_ci SkOpSpanBase* oppNext = oppSpan; 1308cb93a386Sopenharmony_ci SkOpSpanBase* oppLast = oppSpan; 1309cb93a386Sopenharmony_ci while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) { 1310cb93a386Sopenharmony_ci if (!roughly_equal(oppNext->t(), oppSpan->t())) { 1311cb93a386Sopenharmony_ci break; 1312cb93a386Sopenharmony_ci } 1313cb93a386Sopenharmony_ci if (oppNext->spanAddsCount() == addCount) { 1314cb93a386Sopenharmony_ci continue; 1315cb93a386Sopenharmony_ci } 1316cb93a386Sopenharmony_ci if (oppNext->deleted()) { 1317cb93a386Sopenharmony_ci continue; 1318cb93a386Sopenharmony_ci } 1319cb93a386Sopenharmony_ci oppLast = oppNext; 1320cb93a386Sopenharmony_ci } 1321cb93a386Sopenharmony_ci if (oppFirst == oppLast) { 1322cb93a386Sopenharmony_ci continue; 1323cb93a386Sopenharmony_ci } 1324cb93a386Sopenharmony_ci SkOpSpanBase* oppTest = oppFirst; 1325cb93a386Sopenharmony_ci do { 1326cb93a386Sopenharmony_ci if (oppTest == oppSpan) { 1327cb93a386Sopenharmony_ci continue; 1328cb93a386Sopenharmony_ci } 1329cb93a386Sopenharmony_ci // check to see if the candidate meets specific criteria: 1330cb93a386Sopenharmony_ci // it contains spans of segments in test's loop but not including 'this' 1331cb93a386Sopenharmony_ci SkOpPtT* oppStartPtT = oppTest->ptT(); 1332cb93a386Sopenharmony_ci SkOpPtT* oppPtT = oppStartPtT; 1333cb93a386Sopenharmony_ci while ((oppPtT = oppPtT->next()) != oppStartPtT) { 1334cb93a386Sopenharmony_ci SkOpSegment* oppPtTSegment = oppPtT->segment(); 1335cb93a386Sopenharmony_ci if (oppPtTSegment == this) { 1336cb93a386Sopenharmony_ci goto tryNextSpan; 1337cb93a386Sopenharmony_ci } 1338cb93a386Sopenharmony_ci SkOpPtT* matchPtT = startPtT; 1339cb93a386Sopenharmony_ci do { 1340cb93a386Sopenharmony_ci if (matchPtT->segment() == oppPtTSegment) { 1341cb93a386Sopenharmony_ci goto foundMatch; 1342cb93a386Sopenharmony_ci } 1343cb93a386Sopenharmony_ci } while ((matchPtT = matchPtT->next()) != startPtT); 1344cb93a386Sopenharmony_ci goto tryNextSpan; 1345cb93a386Sopenharmony_ci foundMatch: // merge oppTest and oppSpan 1346cb93a386Sopenharmony_ci oppSegment->debugValidate(); 1347cb93a386Sopenharmony_ci oppTest->mergeMatches(oppSpan); 1348cb93a386Sopenharmony_ci oppTest->addOpp(oppSpan); 1349cb93a386Sopenharmony_ci oppSegment->debugValidate(); 1350cb93a386Sopenharmony_ci goto checkNextSpan; 1351cb93a386Sopenharmony_ci } 1352cb93a386Sopenharmony_ci tryNextSpan: 1353cb93a386Sopenharmony_ci ; 1354cb93a386Sopenharmony_ci } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next())); 1355cb93a386Sopenharmony_ci } while ((testPtT = testPtT->next()) != startPtT); 1356cb93a386Sopenharmony_cicheckNextSpan: 1357cb93a386Sopenharmony_ci ; 1358cb93a386Sopenharmony_ci } while ((test = test->final() ? nullptr : test->upCast()->next())); 1359cb93a386Sopenharmony_ci debugValidate(); 1360cb93a386Sopenharmony_ci return true; 1361cb93a386Sopenharmony_ci} 1362cb93a386Sopenharmony_ci 1363cb93a386Sopenharmony_ci// adjacent spans may have points close by 1364cb93a386Sopenharmony_cibool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan, 1365cb93a386Sopenharmony_ci bool* found) const { 1366cb93a386Sopenharmony_ci const SkOpPtT* refHead = refSpan->ptT(); 1367cb93a386Sopenharmony_ci const SkOpPtT* checkHead = checkSpan->ptT(); 1368cb93a386Sopenharmony_ci// if the first pt pair from adjacent spans are far apart, assume that all are far enough apart 1369cb93a386Sopenharmony_ci if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) { 1370cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 1371cb93a386Sopenharmony_ci // verify that no combination of points are close 1372cb93a386Sopenharmony_ci const SkOpPtT* dBugRef = refHead; 1373cb93a386Sopenharmony_ci do { 1374cb93a386Sopenharmony_ci const SkOpPtT* dBugCheck = checkHead; 1375cb93a386Sopenharmony_ci do { 1376cb93a386Sopenharmony_ci SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt)); 1377cb93a386Sopenharmony_ci dBugCheck = dBugCheck->next(); 1378cb93a386Sopenharmony_ci } while (dBugCheck != checkHead); 1379cb93a386Sopenharmony_ci dBugRef = dBugRef->next(); 1380cb93a386Sopenharmony_ci } while (dBugRef != refHead); 1381cb93a386Sopenharmony_ci#endif 1382cb93a386Sopenharmony_ci *found = false; 1383cb93a386Sopenharmony_ci return true; 1384cb93a386Sopenharmony_ci } 1385cb93a386Sopenharmony_ci // check only unique points 1386cb93a386Sopenharmony_ci SkScalar distSqBest = SK_ScalarMax; 1387cb93a386Sopenharmony_ci const SkOpPtT* refBest = nullptr; 1388cb93a386Sopenharmony_ci const SkOpPtT* checkBest = nullptr; 1389cb93a386Sopenharmony_ci const SkOpPtT* ref = refHead; 1390cb93a386Sopenharmony_ci do { 1391cb93a386Sopenharmony_ci if (ref->deleted()) { 1392cb93a386Sopenharmony_ci continue; 1393cb93a386Sopenharmony_ci } 1394cb93a386Sopenharmony_ci while (ref->ptAlreadySeen(refHead)) { 1395cb93a386Sopenharmony_ci ref = ref->next(); 1396cb93a386Sopenharmony_ci if (ref == refHead) { 1397cb93a386Sopenharmony_ci goto doneCheckingDistance; 1398cb93a386Sopenharmony_ci } 1399cb93a386Sopenharmony_ci } 1400cb93a386Sopenharmony_ci const SkOpPtT* check = checkHead; 1401cb93a386Sopenharmony_ci const SkOpSegment* refSeg = ref->segment(); 1402cb93a386Sopenharmony_ci int escapeHatch = 100000; // defend against infinite loops 1403cb93a386Sopenharmony_ci do { 1404cb93a386Sopenharmony_ci if (check->deleted()) { 1405cb93a386Sopenharmony_ci continue; 1406cb93a386Sopenharmony_ci } 1407cb93a386Sopenharmony_ci while (check->ptAlreadySeen(checkHead)) { 1408cb93a386Sopenharmony_ci check = check->next(); 1409cb93a386Sopenharmony_ci if (check == checkHead) { 1410cb93a386Sopenharmony_ci goto nextRef; 1411cb93a386Sopenharmony_ci } 1412cb93a386Sopenharmony_ci } 1413cb93a386Sopenharmony_ci SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt); 1414cb93a386Sopenharmony_ci if (distSqBest > distSq && (refSeg != check->segment() 1415cb93a386Sopenharmony_ci || !refSeg->ptsDisjoint(*ref, *check))) { 1416cb93a386Sopenharmony_ci distSqBest = distSq; 1417cb93a386Sopenharmony_ci refBest = ref; 1418cb93a386Sopenharmony_ci checkBest = check; 1419cb93a386Sopenharmony_ci } 1420cb93a386Sopenharmony_ci if (--escapeHatch <= 0) { 1421cb93a386Sopenharmony_ci return false; 1422cb93a386Sopenharmony_ci } 1423cb93a386Sopenharmony_ci } while ((check = check->next()) != checkHead); 1424cb93a386Sopenharmony_ci nextRef: 1425cb93a386Sopenharmony_ci ; 1426cb93a386Sopenharmony_ci } while ((ref = ref->next()) != refHead); 1427cb93a386Sopenharmony_cidoneCheckingDistance: 1428cb93a386Sopenharmony_ci *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT, 1429cb93a386Sopenharmony_ci checkBest->fPt); 1430cb93a386Sopenharmony_ci return true; 1431cb93a386Sopenharmony_ci} 1432cb93a386Sopenharmony_ci 1433cb93a386Sopenharmony_ci// Please keep this function in sync with debugMoveNearby() 1434cb93a386Sopenharmony_ci// Move nearby t values and pts so they all hang off the same span. Alignment happens later. 1435cb93a386Sopenharmony_cibool SkOpSegment::moveNearby() { 1436cb93a386Sopenharmony_ci debugValidate(); 1437cb93a386Sopenharmony_ci // release undeleted spans pointing to this seg that are linked to the primary span 1438cb93a386Sopenharmony_ci SkOpSpanBase* spanBase = &fHead; 1439cb93a386Sopenharmony_ci int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500 1440cb93a386Sopenharmony_ci do { 1441cb93a386Sopenharmony_ci SkOpPtT* ptT = spanBase->ptT(); 1442cb93a386Sopenharmony_ci const SkOpPtT* headPtT = ptT; 1443cb93a386Sopenharmony_ci while ((ptT = ptT->next()) != headPtT) { 1444cb93a386Sopenharmony_ci if (!--escapeHatch) { 1445cb93a386Sopenharmony_ci return false; 1446cb93a386Sopenharmony_ci } 1447cb93a386Sopenharmony_ci SkOpSpanBase* test = ptT->span(); 1448cb93a386Sopenharmony_ci if (ptT->segment() == this && !ptT->deleted() && test != spanBase 1449cb93a386Sopenharmony_ci && test->ptT() == ptT) { 1450cb93a386Sopenharmony_ci if (test->final()) { 1451cb93a386Sopenharmony_ci if (spanBase == &fHead) { 1452cb93a386Sopenharmony_ci this->clearAll(); 1453cb93a386Sopenharmony_ci return true; 1454cb93a386Sopenharmony_ci } 1455cb93a386Sopenharmony_ci spanBase->upCast()->release(ptT); 1456cb93a386Sopenharmony_ci } else if (test->prev()) { 1457cb93a386Sopenharmony_ci test->upCast()->release(headPtT); 1458cb93a386Sopenharmony_ci } 1459cb93a386Sopenharmony_ci break; 1460cb93a386Sopenharmony_ci } 1461cb93a386Sopenharmony_ci } 1462cb93a386Sopenharmony_ci spanBase = spanBase->upCast()->next(); 1463cb93a386Sopenharmony_ci } while (!spanBase->final()); 1464cb93a386Sopenharmony_ci // This loop looks for adjacent spans which are near by 1465cb93a386Sopenharmony_ci spanBase = &fHead; 1466cb93a386Sopenharmony_ci do { // iterate through all spans associated with start 1467cb93a386Sopenharmony_ci SkOpSpanBase* test = spanBase->upCast()->next(); 1468cb93a386Sopenharmony_ci bool found; 1469cb93a386Sopenharmony_ci if (!this->spansNearby(spanBase, test, &found)) { 1470cb93a386Sopenharmony_ci return false; 1471cb93a386Sopenharmony_ci } 1472cb93a386Sopenharmony_ci if (found) { 1473cb93a386Sopenharmony_ci if (test->final()) { 1474cb93a386Sopenharmony_ci if (spanBase->prev()) { 1475cb93a386Sopenharmony_ci test->merge(spanBase->upCast()); 1476cb93a386Sopenharmony_ci } else { 1477cb93a386Sopenharmony_ci this->clearAll(); 1478cb93a386Sopenharmony_ci return true; 1479cb93a386Sopenharmony_ci } 1480cb93a386Sopenharmony_ci } else { 1481cb93a386Sopenharmony_ci spanBase->merge(test->upCast()); 1482cb93a386Sopenharmony_ci } 1483cb93a386Sopenharmony_ci } 1484cb93a386Sopenharmony_ci spanBase = test; 1485cb93a386Sopenharmony_ci } while (!spanBase->final()); 1486cb93a386Sopenharmony_ci debugValidate(); 1487cb93a386Sopenharmony_ci return true; 1488cb93a386Sopenharmony_ci} 1489cb93a386Sopenharmony_ci 1490cb93a386Sopenharmony_cibool SkOpSegment::operand() const { 1491cb93a386Sopenharmony_ci return fContour->operand(); 1492cb93a386Sopenharmony_ci} 1493cb93a386Sopenharmony_ci 1494cb93a386Sopenharmony_cibool SkOpSegment::oppXor() const { 1495cb93a386Sopenharmony_ci return fContour->oppXor(); 1496cb93a386Sopenharmony_ci} 1497cb93a386Sopenharmony_ci 1498cb93a386Sopenharmony_cibool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const { 1499cb93a386Sopenharmony_ci if (fVerb == SkPath::kLine_Verb) { 1500cb93a386Sopenharmony_ci return false; 1501cb93a386Sopenharmony_ci } 1502cb93a386Sopenharmony_ci // quads (and cubics) can loop back to nearly a line so that an opposite curve 1503cb93a386Sopenharmony_ci // hits in two places with very different t values. 1504cb93a386Sopenharmony_ci // OPTIMIZATION: curves could be preflighted so that, for example, something like 1505cb93a386Sopenharmony_ci // 'controls contained by ends' could avoid this check for common curves 1506cb93a386Sopenharmony_ci // 'ends are extremes in x or y' is cheaper to compute and real-world common 1507cb93a386Sopenharmony_ci // on the other hand, the below check is relatively inexpensive 1508cb93a386Sopenharmony_ci double midT = (t1 + t2) / 2; 1509cb93a386Sopenharmony_ci SkPoint midPt = this->ptAtT(midT); 1510cb93a386Sopenharmony_ci double seDistSq = std::max(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2); 1511cb93a386Sopenharmony_ci return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq || 1512cb93a386Sopenharmony_ci SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq; 1513cb93a386Sopenharmony_ci} 1514cb93a386Sopenharmony_ci 1515cb93a386Sopenharmony_civoid SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding, 1516cb93a386Sopenharmony_ci int* maxWinding, int* sumWinding) { 1517cb93a386Sopenharmony_ci int deltaSum = SpanSign(start, end); 1518cb93a386Sopenharmony_ci *maxWinding = *sumMiWinding; 1519cb93a386Sopenharmony_ci *sumWinding = *sumMiWinding -= deltaSum; 1520cb93a386Sopenharmony_ci SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); 1521cb93a386Sopenharmony_ci} 1522cb93a386Sopenharmony_ci 1523cb93a386Sopenharmony_civoid SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding, 1524cb93a386Sopenharmony_ci int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding, 1525cb93a386Sopenharmony_ci int* oppSumWinding) { 1526cb93a386Sopenharmony_ci int deltaSum = SpanSign(start, end); 1527cb93a386Sopenharmony_ci int oppDeltaSum = OppSign(start, end); 1528cb93a386Sopenharmony_ci if (operand()) { 1529cb93a386Sopenharmony_ci *maxWinding = *sumSuWinding; 1530cb93a386Sopenharmony_ci *sumWinding = *sumSuWinding -= deltaSum; 1531cb93a386Sopenharmony_ci *oppMaxWinding = *sumMiWinding; 1532cb93a386Sopenharmony_ci *oppSumWinding = *sumMiWinding -= oppDeltaSum; 1533cb93a386Sopenharmony_ci } else { 1534cb93a386Sopenharmony_ci *maxWinding = *sumMiWinding; 1535cb93a386Sopenharmony_ci *sumWinding = *sumMiWinding -= deltaSum; 1536cb93a386Sopenharmony_ci *oppMaxWinding = *sumSuWinding; 1537cb93a386Sopenharmony_ci *oppSumWinding = *sumSuWinding -= oppDeltaSum; 1538cb93a386Sopenharmony_ci } 1539cb93a386Sopenharmony_ci SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); 1540cb93a386Sopenharmony_ci SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM); 1541cb93a386Sopenharmony_ci} 1542cb93a386Sopenharmony_ci 1543cb93a386Sopenharmony_cibool SkOpSegment::sortAngles() { 1544cb93a386Sopenharmony_ci SkOpSpanBase* span = &this->fHead; 1545cb93a386Sopenharmony_ci do { 1546cb93a386Sopenharmony_ci SkOpAngle* fromAngle = span->fromAngle(); 1547cb93a386Sopenharmony_ci SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle(); 1548cb93a386Sopenharmony_ci if (!fromAngle && !toAngle) { 1549cb93a386Sopenharmony_ci continue; 1550cb93a386Sopenharmony_ci } 1551cb93a386Sopenharmony_ci#if DEBUG_ANGLE 1552cb93a386Sopenharmony_ci bool wroteAfterHeader = false; 1553cb93a386Sopenharmony_ci#endif 1554cb93a386Sopenharmony_ci SkOpAngle* baseAngle = fromAngle; 1555cb93a386Sopenharmony_ci if (fromAngle && toAngle) { 1556cb93a386Sopenharmony_ci#if DEBUG_ANGLE 1557cb93a386Sopenharmony_ci SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(), 1558cb93a386Sopenharmony_ci span->debugID()); 1559cb93a386Sopenharmony_ci wroteAfterHeader = true; 1560cb93a386Sopenharmony_ci#endif 1561cb93a386Sopenharmony_ci FAIL_IF(!fromAngle->insert(toAngle)); 1562cb93a386Sopenharmony_ci } else if (!fromAngle) { 1563cb93a386Sopenharmony_ci baseAngle = toAngle; 1564cb93a386Sopenharmony_ci } 1565cb93a386Sopenharmony_ci SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; 1566cb93a386Sopenharmony_ci int safetyNet = 1000000; 1567cb93a386Sopenharmony_ci do { 1568cb93a386Sopenharmony_ci if (!--safetyNet) { 1569cb93a386Sopenharmony_ci return false; 1570cb93a386Sopenharmony_ci } 1571cb93a386Sopenharmony_ci SkOpSpanBase* oSpan = ptT->span(); 1572cb93a386Sopenharmony_ci if (oSpan == span) { 1573cb93a386Sopenharmony_ci continue; 1574cb93a386Sopenharmony_ci } 1575cb93a386Sopenharmony_ci SkOpAngle* oAngle = oSpan->fromAngle(); 1576cb93a386Sopenharmony_ci if (oAngle) { 1577cb93a386Sopenharmony_ci#if DEBUG_ANGLE 1578cb93a386Sopenharmony_ci if (!wroteAfterHeader) { 1579cb93a386Sopenharmony_ci SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), 1580cb93a386Sopenharmony_ci span->t(), span->debugID()); 1581cb93a386Sopenharmony_ci wroteAfterHeader = true; 1582cb93a386Sopenharmony_ci } 1583cb93a386Sopenharmony_ci#endif 1584cb93a386Sopenharmony_ci if (!oAngle->loopContains(baseAngle)) { 1585cb93a386Sopenharmony_ci baseAngle->insert(oAngle); 1586cb93a386Sopenharmony_ci } 1587cb93a386Sopenharmony_ci } 1588cb93a386Sopenharmony_ci if (!oSpan->final()) { 1589cb93a386Sopenharmony_ci oAngle = oSpan->upCast()->toAngle(); 1590cb93a386Sopenharmony_ci if (oAngle) { 1591cb93a386Sopenharmony_ci#if DEBUG_ANGLE 1592cb93a386Sopenharmony_ci if (!wroteAfterHeader) { 1593cb93a386Sopenharmony_ci SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), 1594cb93a386Sopenharmony_ci span->t(), span->debugID()); 1595cb93a386Sopenharmony_ci wroteAfterHeader = true; 1596cb93a386Sopenharmony_ci } 1597cb93a386Sopenharmony_ci#endif 1598cb93a386Sopenharmony_ci if (!oAngle->loopContains(baseAngle)) { 1599cb93a386Sopenharmony_ci baseAngle->insert(oAngle); 1600cb93a386Sopenharmony_ci } 1601cb93a386Sopenharmony_ci } 1602cb93a386Sopenharmony_ci } 1603cb93a386Sopenharmony_ci } while ((ptT = ptT->next()) != stopPtT); 1604cb93a386Sopenharmony_ci if (baseAngle->loopCount() == 1) { 1605cb93a386Sopenharmony_ci span->setFromAngle(nullptr); 1606cb93a386Sopenharmony_ci if (toAngle) { 1607cb93a386Sopenharmony_ci span->upCast()->setToAngle(nullptr); 1608cb93a386Sopenharmony_ci } 1609cb93a386Sopenharmony_ci baseAngle = nullptr; 1610cb93a386Sopenharmony_ci } 1611cb93a386Sopenharmony_ci#if DEBUG_SORT 1612cb93a386Sopenharmony_ci SkASSERT(!baseAngle || baseAngle->loopCount() > 1); 1613cb93a386Sopenharmony_ci#endif 1614cb93a386Sopenharmony_ci } while (!span->final() && (span = span->upCast()->next())); 1615cb93a386Sopenharmony_ci return true; 1616cb93a386Sopenharmony_ci} 1617cb93a386Sopenharmony_ci 1618cb93a386Sopenharmony_cibool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, 1619cb93a386Sopenharmony_ci SkDCurve* edge) const { 1620cb93a386Sopenharmony_ci SkASSERT(start != end); 1621cb93a386Sopenharmony_ci const SkOpPtT& startPtT = *start->ptT(); 1622cb93a386Sopenharmony_ci const SkOpPtT& endPtT = *end->ptT(); 1623cb93a386Sopenharmony_ci SkDEBUGCODE(edge->fVerb = fVerb); 1624cb93a386Sopenharmony_ci edge->fCubic[0].set(startPtT.fPt); 1625cb93a386Sopenharmony_ci int points = SkPathOpsVerbToPoints(fVerb); 1626cb93a386Sopenharmony_ci edge->fCubic[points].set(endPtT.fPt); 1627cb93a386Sopenharmony_ci if (fVerb == SkPath::kLine_Verb) { 1628cb93a386Sopenharmony_ci return false; 1629cb93a386Sopenharmony_ci } 1630cb93a386Sopenharmony_ci double startT = startPtT.fT; 1631cb93a386Sopenharmony_ci double endT = endPtT.fT; 1632cb93a386Sopenharmony_ci if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { 1633cb93a386Sopenharmony_ci // don't compute midpoints if we already have them 1634cb93a386Sopenharmony_ci if (fVerb == SkPath::kQuad_Verb) { 1635cb93a386Sopenharmony_ci edge->fLine[1].set(fPts[1]); 1636cb93a386Sopenharmony_ci return false; 1637cb93a386Sopenharmony_ci } 1638cb93a386Sopenharmony_ci if (fVerb == SkPath::kConic_Verb) { 1639cb93a386Sopenharmony_ci edge->fConic[1].set(fPts[1]); 1640cb93a386Sopenharmony_ci edge->fConic.fWeight = fWeight; 1641cb93a386Sopenharmony_ci return false; 1642cb93a386Sopenharmony_ci } 1643cb93a386Sopenharmony_ci SkASSERT(fVerb == SkPath::kCubic_Verb); 1644cb93a386Sopenharmony_ci if (startT == 0) { 1645cb93a386Sopenharmony_ci edge->fCubic[1].set(fPts[1]); 1646cb93a386Sopenharmony_ci edge->fCubic[2].set(fPts[2]); 1647cb93a386Sopenharmony_ci return false; 1648cb93a386Sopenharmony_ci } 1649cb93a386Sopenharmony_ci edge->fCubic[1].set(fPts[2]); 1650cb93a386Sopenharmony_ci edge->fCubic[2].set(fPts[1]); 1651cb93a386Sopenharmony_ci return false; 1652cb93a386Sopenharmony_ci } 1653cb93a386Sopenharmony_ci if (fVerb == SkPath::kQuad_Verb) { 1654cb93a386Sopenharmony_ci edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT); 1655cb93a386Sopenharmony_ci } else if (fVerb == SkPath::kConic_Verb) { 1656cb93a386Sopenharmony_ci edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2], 1657cb93a386Sopenharmony_ci startT, endT, &edge->fConic.fWeight); 1658cb93a386Sopenharmony_ci } else { 1659cb93a386Sopenharmony_ci SkASSERT(fVerb == SkPath::kCubic_Verb); 1660cb93a386Sopenharmony_ci SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]); 1661cb93a386Sopenharmony_ci } 1662cb93a386Sopenharmony_ci return true; 1663cb93a386Sopenharmony_ci} 1664cb93a386Sopenharmony_ci 1665cb93a386Sopenharmony_cibool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT, 1666cb93a386Sopenharmony_ci const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const { 1667cb93a386Sopenharmony_ci // average t, find mid pt 1668cb93a386Sopenharmony_ci double midT = (prior->t() + spanBase->t()) / 2; 1669cb93a386Sopenharmony_ci SkPoint midPt = this->ptAtT(midT); 1670cb93a386Sopenharmony_ci bool coincident = true; 1671cb93a386Sopenharmony_ci // if the mid pt is not near either end pt, project perpendicular through opp seg 1672cb93a386Sopenharmony_ci if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) 1673cb93a386Sopenharmony_ci && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { 1674cb93a386Sopenharmony_ci if (priorPtT->span() == ptT->span()) { 1675cb93a386Sopenharmony_ci return false; 1676cb93a386Sopenharmony_ci } 1677cb93a386Sopenharmony_ci coincident = false; 1678cb93a386Sopenharmony_ci SkIntersections i; 1679cb93a386Sopenharmony_ci SkDCurve curvePart; 1680cb93a386Sopenharmony_ci this->subDivide(prior, spanBase, &curvePart); 1681cb93a386Sopenharmony_ci SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f); 1682cb93a386Sopenharmony_ci SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f); 1683cb93a386Sopenharmony_ci SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}}; 1684cb93a386Sopenharmony_ci SkDCurve oppPart; 1685cb93a386Sopenharmony_ci opp->subDivide(priorPtT->span(), ptT->span(), &oppPart); 1686cb93a386Sopenharmony_ci (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i); 1687cb93a386Sopenharmony_ci // measure distance and see if it's small enough to denote coincidence 1688cb93a386Sopenharmony_ci for (int index = 0; index < i.used(); ++index) { 1689cb93a386Sopenharmony_ci if (!between(0, i[0][index], 1)) { 1690cb93a386Sopenharmony_ci continue; 1691cb93a386Sopenharmony_ci } 1692cb93a386Sopenharmony_ci SkDPoint oppPt = i.pt(index); 1693cb93a386Sopenharmony_ci if (oppPt.approximatelyDEqual(midPt)) { 1694cb93a386Sopenharmony_ci // the coincidence can occur at almost any angle 1695cb93a386Sopenharmony_ci coincident = true; 1696cb93a386Sopenharmony_ci } 1697cb93a386Sopenharmony_ci } 1698cb93a386Sopenharmony_ci } 1699cb93a386Sopenharmony_ci return coincident; 1700cb93a386Sopenharmony_ci} 1701cb93a386Sopenharmony_ci 1702cb93a386Sopenharmony_ciSkOpSpan* SkOpSegment::undoneSpan() { 1703cb93a386Sopenharmony_ci SkOpSpan* span = &fHead; 1704cb93a386Sopenharmony_ci SkOpSpanBase* next; 1705cb93a386Sopenharmony_ci do { 1706cb93a386Sopenharmony_ci next = span->next(); 1707cb93a386Sopenharmony_ci if (!span->done()) { 1708cb93a386Sopenharmony_ci return span; 1709cb93a386Sopenharmony_ci } 1710cb93a386Sopenharmony_ci } while (!next->final() && (span = next->upCast())); 1711cb93a386Sopenharmony_ci return nullptr; 1712cb93a386Sopenharmony_ci} 1713cb93a386Sopenharmony_ci 1714cb93a386Sopenharmony_ciint SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const { 1715cb93a386Sopenharmony_ci const SkOpSpan* lesser = start->starter(end); 1716cb93a386Sopenharmony_ci int oppWinding = lesser->oppSum(); 1717cb93a386Sopenharmony_ci int oppSpanWinding = SkOpSegment::OppSign(start, end); 1718cb93a386Sopenharmony_ci if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding) 1719cb93a386Sopenharmony_ci && oppWinding != SK_MaxS32) { 1720cb93a386Sopenharmony_ci oppWinding -= oppSpanWinding; 1721cb93a386Sopenharmony_ci } 1722cb93a386Sopenharmony_ci return oppWinding; 1723cb93a386Sopenharmony_ci} 1724cb93a386Sopenharmony_ci 1725cb93a386Sopenharmony_ciint SkOpSegment::updateOppWinding(const SkOpAngle* angle) const { 1726cb93a386Sopenharmony_ci const SkOpSpanBase* startSpan = angle->start(); 1727cb93a386Sopenharmony_ci const SkOpSpanBase* endSpan = angle->end(); 1728cb93a386Sopenharmony_ci return updateOppWinding(endSpan, startSpan); 1729cb93a386Sopenharmony_ci} 1730cb93a386Sopenharmony_ci 1731cb93a386Sopenharmony_ciint SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { 1732cb93a386Sopenharmony_ci const SkOpSpanBase* startSpan = angle->start(); 1733cb93a386Sopenharmony_ci const SkOpSpanBase* endSpan = angle->end(); 1734cb93a386Sopenharmony_ci return updateOppWinding(startSpan, endSpan); 1735cb93a386Sopenharmony_ci} 1736cb93a386Sopenharmony_ci 1737cb93a386Sopenharmony_ciint SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) { 1738cb93a386Sopenharmony_ci SkOpSpan* lesser = start->starter(end); 1739cb93a386Sopenharmony_ci int winding = lesser->windSum(); 1740cb93a386Sopenharmony_ci if (winding == SK_MinS32) { 1741cb93a386Sopenharmony_ci winding = lesser->computeWindSum(); 1742cb93a386Sopenharmony_ci } 1743cb93a386Sopenharmony_ci if (winding == SK_MinS32) { 1744cb93a386Sopenharmony_ci return winding; 1745cb93a386Sopenharmony_ci } 1746cb93a386Sopenharmony_ci int spanWinding = SkOpSegment::SpanSign(start, end); 1747cb93a386Sopenharmony_ci if (winding && UseInnerWinding(winding - spanWinding, winding) 1748cb93a386Sopenharmony_ci && winding != SK_MaxS32) { 1749cb93a386Sopenharmony_ci winding -= spanWinding; 1750cb93a386Sopenharmony_ci } 1751cb93a386Sopenharmony_ci return winding; 1752cb93a386Sopenharmony_ci} 1753cb93a386Sopenharmony_ci 1754cb93a386Sopenharmony_ciint SkOpSegment::updateWinding(SkOpAngle* angle) { 1755cb93a386Sopenharmony_ci SkOpSpanBase* startSpan = angle->start(); 1756cb93a386Sopenharmony_ci SkOpSpanBase* endSpan = angle->end(); 1757cb93a386Sopenharmony_ci return updateWinding(endSpan, startSpan); 1758cb93a386Sopenharmony_ci} 1759cb93a386Sopenharmony_ci 1760cb93a386Sopenharmony_ciint SkOpSegment::updateWindingReverse(const SkOpAngle* angle) { 1761cb93a386Sopenharmony_ci SkOpSpanBase* startSpan = angle->start(); 1762cb93a386Sopenharmony_ci SkOpSpanBase* endSpan = angle->end(); 1763cb93a386Sopenharmony_ci return updateWinding(startSpan, endSpan); 1764cb93a386Sopenharmony_ci} 1765cb93a386Sopenharmony_ci 1766cb93a386Sopenharmony_ci// OPTIMIZATION: does the following also work, and is it any faster? 1767cb93a386Sopenharmony_ci// return outerWinding * innerWinding > 0 1768cb93a386Sopenharmony_ci// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0))) 1769cb93a386Sopenharmony_cibool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { 1770cb93a386Sopenharmony_ci SkASSERT(outerWinding != SK_MaxS32); 1771cb93a386Sopenharmony_ci SkASSERT(innerWinding != SK_MaxS32); 1772cb93a386Sopenharmony_ci int absOut = SkTAbs(outerWinding); 1773cb93a386Sopenharmony_ci int absIn = SkTAbs(innerWinding); 1774cb93a386Sopenharmony_ci bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 1775cb93a386Sopenharmony_ci return result; 1776cb93a386Sopenharmony_ci} 1777cb93a386Sopenharmony_ci 1778cb93a386Sopenharmony_ciint SkOpSegment::windSum(const SkOpAngle* angle) const { 1779cb93a386Sopenharmony_ci const SkOpSpan* minSpan = angle->start()->starter(angle->end()); 1780cb93a386Sopenharmony_ci return minSpan->windSum(); 1781cb93a386Sopenharmony_ci} 1782