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 8cb93a386Sopenharmony_ci#include "include/private/SkMacros.h" 9cb93a386Sopenharmony_ci#include "src/core/SkTSort.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkAddIntersections.h" 11cb93a386Sopenharmony_ci#include "src/pathops/SkOpCoincidence.h" 12cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h" 13cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCommon.h" 14cb93a386Sopenharmony_ci#include "src/pathops/SkPathWriter.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ciconst SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windingPtr, 17cb93a386Sopenharmony_ci bool* sortablePtr) { 18cb93a386Sopenharmony_ci // find first angle, initialize winding to computed fWindSum 19cb93a386Sopenharmony_ci SkOpSegment* segment = start->segment(); 20cb93a386Sopenharmony_ci const SkOpAngle* angle = segment->spanToAngle(start, end); 21cb93a386Sopenharmony_ci if (!angle) { 22cb93a386Sopenharmony_ci *windingPtr = SK_MinS32; 23cb93a386Sopenharmony_ci return nullptr; 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci bool computeWinding = false; 26cb93a386Sopenharmony_ci const SkOpAngle* firstAngle = angle; 27cb93a386Sopenharmony_ci bool loop = false; 28cb93a386Sopenharmony_ci bool unorderable = false; 29cb93a386Sopenharmony_ci int winding = SK_MinS32; 30cb93a386Sopenharmony_ci do { 31cb93a386Sopenharmony_ci angle = angle->next(); 32cb93a386Sopenharmony_ci if (!angle) { 33cb93a386Sopenharmony_ci return nullptr; 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci unorderable |= angle->unorderable(); 36cb93a386Sopenharmony_ci if ((computeWinding = unorderable || (angle == firstAngle && loop))) { 37cb93a386Sopenharmony_ci break; // if we get here, there's no winding, loop is unorderable 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci loop |= angle == firstAngle; 40cb93a386Sopenharmony_ci segment = angle->segment(); 41cb93a386Sopenharmony_ci winding = segment->windSum(angle); 42cb93a386Sopenharmony_ci } while (winding == SK_MinS32); 43cb93a386Sopenharmony_ci // if the angle loop contains an unorderable span, the angle order may be useless 44cb93a386Sopenharmony_ci // directly compute the winding in this case for each span 45cb93a386Sopenharmony_ci if (computeWinding) { 46cb93a386Sopenharmony_ci firstAngle = angle; 47cb93a386Sopenharmony_ci winding = SK_MinS32; 48cb93a386Sopenharmony_ci do { 49cb93a386Sopenharmony_ci SkOpSpanBase* startSpan = angle->start(); 50cb93a386Sopenharmony_ci SkOpSpanBase* endSpan = angle->end(); 51cb93a386Sopenharmony_ci SkOpSpan* lesser = startSpan->starter(endSpan); 52cb93a386Sopenharmony_ci int testWinding = lesser->windSum(); 53cb93a386Sopenharmony_ci if (testWinding == SK_MinS32) { 54cb93a386Sopenharmony_ci testWinding = lesser->computeWindSum(); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci if (testWinding != SK_MinS32) { 57cb93a386Sopenharmony_ci segment = angle->segment(); 58cb93a386Sopenharmony_ci winding = testWinding; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci angle = angle->next(); 61cb93a386Sopenharmony_ci } while (angle != firstAngle); 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci *sortablePtr = !unorderable; 64cb93a386Sopenharmony_ci *windingPtr = winding; 65cb93a386Sopenharmony_ci return angle; 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ciSkOpSpan* FindUndone(SkOpContourHead* contourHead) { 69cb93a386Sopenharmony_ci SkOpContour* contour = contourHead; 70cb93a386Sopenharmony_ci do { 71cb93a386Sopenharmony_ci if (contour->done()) { 72cb93a386Sopenharmony_ci continue; 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci SkOpSpan* result = contour->undoneSpan(); 75cb93a386Sopenharmony_ci if (result) { 76cb93a386Sopenharmony_ci return result; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci } while ((contour = contour->next())); 79cb93a386Sopenharmony_ci return nullptr; 80cb93a386Sopenharmony_ci} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ciSkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr, 83cb93a386Sopenharmony_ci SkOpSpanBase** endPtr) { 84cb93a386Sopenharmony_ci while (chase->count()) { 85cb93a386Sopenharmony_ci SkOpSpanBase* span; 86cb93a386Sopenharmony_ci chase->pop(&span); 87cb93a386Sopenharmony_ci SkOpSegment* segment = span->segment(); 88cb93a386Sopenharmony_ci *startPtr = span->ptT()->next()->span(); 89cb93a386Sopenharmony_ci bool done = true; 90cb93a386Sopenharmony_ci *endPtr = nullptr; 91cb93a386Sopenharmony_ci if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) { 92cb93a386Sopenharmony_ci *startPtr = last->start(); 93cb93a386Sopenharmony_ci *endPtr = last->end(); 94cb93a386Sopenharmony_ci #if TRY_ROTATE 95cb93a386Sopenharmony_ci *chase->insert(0) = span; 96cb93a386Sopenharmony_ci #else 97cb93a386Sopenharmony_ci *chase->append() = span; 98cb93a386Sopenharmony_ci #endif 99cb93a386Sopenharmony_ci return last->segment(); 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci if (done) { 102cb93a386Sopenharmony_ci continue; 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci // find first angle, initialize winding to computed wind sum 105cb93a386Sopenharmony_ci int winding; 106cb93a386Sopenharmony_ci bool sortable; 107cb93a386Sopenharmony_ci const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable); 108cb93a386Sopenharmony_ci if (!angle) { 109cb93a386Sopenharmony_ci return nullptr; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci if (winding == SK_MinS32) { 112cb93a386Sopenharmony_ci continue; 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci int sumWinding SK_INIT_TO_AVOID_WARNING; 115cb93a386Sopenharmony_ci if (sortable) { 116cb93a386Sopenharmony_ci segment = angle->segment(); 117cb93a386Sopenharmony_ci sumWinding = segment->updateWindingReverse(angle); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci SkOpSegment* first = nullptr; 120cb93a386Sopenharmony_ci const SkOpAngle* firstAngle = angle; 121cb93a386Sopenharmony_ci while ((angle = angle->next()) != firstAngle) { 122cb93a386Sopenharmony_ci segment = angle->segment(); 123cb93a386Sopenharmony_ci SkOpSpanBase* start = angle->start(); 124cb93a386Sopenharmony_ci SkOpSpanBase* end = angle->end(); 125cb93a386Sopenharmony_ci int maxWinding SK_INIT_TO_AVOID_WARNING; 126cb93a386Sopenharmony_ci if (sortable) { 127cb93a386Sopenharmony_ci segment->setUpWinding(start, end, &maxWinding, &sumWinding); 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci if (!segment->done(angle)) { 130cb93a386Sopenharmony_ci if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) { 131cb93a386Sopenharmony_ci first = segment; 132cb93a386Sopenharmony_ci *startPtr = start; 133cb93a386Sopenharmony_ci *endPtr = end; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci // OPTIMIZATION: should this also add to the chase? 136cb93a386Sopenharmony_ci if (sortable) { 137cb93a386Sopenharmony_ci // TODO: add error handling 138cb93a386Sopenharmony_ci SkAssertResult(segment->markAngle(maxWinding, sumWinding, angle, nullptr)); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci if (first) { 143cb93a386Sopenharmony_ci #if TRY_ROTATE 144cb93a386Sopenharmony_ci *chase->insert(0) = span; 145cb93a386Sopenharmony_ci #else 146cb93a386Sopenharmony_ci *chase->append() = span; 147cb93a386Sopenharmony_ci #endif 148cb93a386Sopenharmony_ci return first; 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci return nullptr; 152cb93a386Sopenharmony_ci} 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_cibool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) { 155cb93a386Sopenharmony_ci SkTDArray<SkOpContour* > list; 156cb93a386Sopenharmony_ci SkOpContour* contour = *contourList; 157cb93a386Sopenharmony_ci do { 158cb93a386Sopenharmony_ci if (contour->count()) { 159cb93a386Sopenharmony_ci contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd); 160cb93a386Sopenharmony_ci *list.append() = contour; 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci } while ((contour = contour->next())); 163cb93a386Sopenharmony_ci int count = list.count(); 164cb93a386Sopenharmony_ci if (!count) { 165cb93a386Sopenharmony_ci return false; 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci if (count > 1) { 168cb93a386Sopenharmony_ci SkTQSort<SkOpContour>(list.begin(), list.end()); 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci contour = list[0]; 171cb93a386Sopenharmony_ci SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour); 172cb93a386Sopenharmony_ci contour->globalState()->setContourHead(contourHead); 173cb93a386Sopenharmony_ci *contourList = contourHead; 174cb93a386Sopenharmony_ci for (int index = 1; index < count; ++index) { 175cb93a386Sopenharmony_ci SkOpContour* next = list[index]; 176cb93a386Sopenharmony_ci contour->setNext(next); 177cb93a386Sopenharmony_ci contour = next; 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci contour->setNext(nullptr); 180cb93a386Sopenharmony_ci return true; 181cb93a386Sopenharmony_ci} 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_cistatic void calc_angles(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) { 184cb93a386Sopenharmony_ci DEBUG_STATIC_SET_PHASE(contourList); 185cb93a386Sopenharmony_ci SkOpContour* contour = contourList; 186cb93a386Sopenharmony_ci do { 187cb93a386Sopenharmony_ci contour->calcAngles(); 188cb93a386Sopenharmony_ci } while ((contour = contour->next())); 189cb93a386Sopenharmony_ci} 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_cistatic bool missing_coincidence(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) { 192cb93a386Sopenharmony_ci DEBUG_STATIC_SET_PHASE(contourList); 193cb93a386Sopenharmony_ci SkOpContour* contour = contourList; 194cb93a386Sopenharmony_ci bool result = false; 195cb93a386Sopenharmony_ci do { 196cb93a386Sopenharmony_ci result |= contour->missingCoincidence(); 197cb93a386Sopenharmony_ci } while ((contour = contour->next())); 198cb93a386Sopenharmony_ci return result; 199cb93a386Sopenharmony_ci} 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_cistatic bool move_multiples(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) { 202cb93a386Sopenharmony_ci DEBUG_STATIC_SET_PHASE(contourList); 203cb93a386Sopenharmony_ci SkOpContour* contour = contourList; 204cb93a386Sopenharmony_ci do { 205cb93a386Sopenharmony_ci if (!contour->moveMultiples()) { 206cb93a386Sopenharmony_ci return false; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci } while ((contour = contour->next())); 209cb93a386Sopenharmony_ci return true; 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_cistatic bool move_nearby(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) { 213cb93a386Sopenharmony_ci DEBUG_STATIC_SET_PHASE(contourList); 214cb93a386Sopenharmony_ci SkOpContour* contour = contourList; 215cb93a386Sopenharmony_ci do { 216cb93a386Sopenharmony_ci if (!contour->moveNearby()) { 217cb93a386Sopenharmony_ci return false; 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci } while ((contour = contour->next())); 220cb93a386Sopenharmony_ci return true; 221cb93a386Sopenharmony_ci} 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_cistatic bool sort_angles(SkOpContourHead* contourList) { 224cb93a386Sopenharmony_ci SkOpContour* contour = contourList; 225cb93a386Sopenharmony_ci do { 226cb93a386Sopenharmony_ci if (!contour->sortAngles()) { 227cb93a386Sopenharmony_ci return false; 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci } while ((contour = contour->next())); 230cb93a386Sopenharmony_ci return true; 231cb93a386Sopenharmony_ci} 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_cibool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) { 234cb93a386Sopenharmony_ci SkOpGlobalState* globalState = contourList->globalState(); 235cb93a386Sopenharmony_ci // match up points within the coincident runs 236cb93a386Sopenharmony_ci if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kIntersecting))) { 237cb93a386Sopenharmony_ci return false; 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci // combine t values when multiple intersections occur on some segments but not others 240cb93a386Sopenharmony_ci if (!move_multiples(contourList DEBUG_PHASE_PARAMS(kWalking))) { 241cb93a386Sopenharmony_ci return false; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci // move t values and points together to eliminate small/tiny gaps 244cb93a386Sopenharmony_ci if (!move_nearby(contourList DEBUG_COIN_PARAMS())) { 245cb93a386Sopenharmony_ci return false; 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci // add coincidence formed by pairing on curve points and endpoints 248cb93a386Sopenharmony_ci coincidence->correctEnds(DEBUG_PHASE_ONLY_PARAMS(kIntersecting)); 249cb93a386Sopenharmony_ci if (!coincidence->addEndMovedSpans(DEBUG_COIN_ONLY_PARAMS())) { 250cb93a386Sopenharmony_ci return false; 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci const int SAFETY_COUNT = 3; 253cb93a386Sopenharmony_ci int safetyHatch = SAFETY_COUNT; 254cb93a386Sopenharmony_ci // look for coincidence present in A-B and A-C but missing in B-C 255cb93a386Sopenharmony_ci do { 256cb93a386Sopenharmony_ci bool added; 257cb93a386Sopenharmony_ci if (!coincidence->addMissing(&added DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) { 258cb93a386Sopenharmony_ci return false; 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci if (!added) { 261cb93a386Sopenharmony_ci break; 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci if (!--safetyHatch) { 264cb93a386Sopenharmony_ci SkASSERT(globalState->debugSkipAssert()); 265cb93a386Sopenharmony_ci return false; 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci move_nearby(contourList DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch - 1)); 268cb93a386Sopenharmony_ci } while (true); 269cb93a386Sopenharmony_ci // check to see if, loosely, coincident ranges may be expanded 270cb93a386Sopenharmony_ci if (coincidence->expand(DEBUG_COIN_ONLY_PARAMS())) { 271cb93a386Sopenharmony_ci bool added; 272cb93a386Sopenharmony_ci if (!coincidence->addMissing(&added DEBUG_COIN_PARAMS())) { 273cb93a386Sopenharmony_ci return false; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) { 276cb93a386Sopenharmony_ci return false; 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci if (!move_multiples(contourList DEBUG_COIN_PARAMS())) { 279cb93a386Sopenharmony_ci return false; 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci move_nearby(contourList DEBUG_COIN_PARAMS()); 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci // the expanded ranges may not align -- add the missing spans 284cb93a386Sopenharmony_ci if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kWalking))) { 285cb93a386Sopenharmony_ci return false; 286cb93a386Sopenharmony_ci } 287cb93a386Sopenharmony_ci // mark spans of coincident segments as coincident 288cb93a386Sopenharmony_ci coincidence->mark(DEBUG_COIN_ONLY_PARAMS()); 289cb93a386Sopenharmony_ci // look for coincidence lines and curves undetected by intersection 290cb93a386Sopenharmony_ci if (missing_coincidence(contourList DEBUG_COIN_PARAMS())) { 291cb93a386Sopenharmony_ci (void) coincidence->expand(DEBUG_PHASE_ONLY_PARAMS(kIntersecting)); 292cb93a386Sopenharmony_ci if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) { 293cb93a386Sopenharmony_ci return false; 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci if (!coincidence->mark(DEBUG_PHASE_ONLY_PARAMS(kWalking))) { 296cb93a386Sopenharmony_ci return false; 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci } else { 299cb93a386Sopenharmony_ci (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS()); 300cb93a386Sopenharmony_ci } 301cb93a386Sopenharmony_ci (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS()); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci SkOpCoincidence overlaps(globalState); 304cb93a386Sopenharmony_ci safetyHatch = SAFETY_COUNT; 305cb93a386Sopenharmony_ci do { 306cb93a386Sopenharmony_ci SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps; 307cb93a386Sopenharmony_ci // adjust the winding value to account for coincident edges 308cb93a386Sopenharmony_ci if (!pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch))) { 309cb93a386Sopenharmony_ci return false; 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci // For each coincident pair that overlaps another, when the receivers (the 1st of the pair) 312cb93a386Sopenharmony_ci // are different, construct a new pair to resolve their mutual span 313cb93a386Sopenharmony_ci if (!pairs->findOverlaps(&overlaps DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) { 314cb93a386Sopenharmony_ci return false; 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci if (!--safetyHatch) { 317cb93a386Sopenharmony_ci SkASSERT(globalState->debugSkipAssert()); 318cb93a386Sopenharmony_ci return false; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci } while (!overlaps.isEmpty()); 321cb93a386Sopenharmony_ci calc_angles(contourList DEBUG_COIN_PARAMS()); 322cb93a386Sopenharmony_ci if (!sort_angles(contourList)) { 323cb93a386Sopenharmony_ci return false; 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE 326cb93a386Sopenharmony_ci coincidence->debugShowCoincidence(); 327cb93a386Sopenharmony_ci#endif 328cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 329cb93a386Sopenharmony_ci coincidence->debugValidate(); 330cb93a386Sopenharmony_ci#endif 331cb93a386Sopenharmony_ci SkPathOpsDebug::ShowActiveSpans(contourList); 332cb93a386Sopenharmony_ci return true; 333cb93a386Sopenharmony_ci} 334