| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * Copyright 2012 Google Inc. | 2  * Copyright 2012 Google Inc. | 
| 3  * | 3  * | 
| 4  * Use of this source code is governed by a BSD-style license that can be | 4  * Use of this source code is governed by a BSD-style license that can be | 
| 5  * found in the LICENSE file. | 5  * found in the LICENSE file. | 
| 6  */ | 6  */ | 
| 7 #include "SkOpCoincidence.h" | 7 #include "SkOpCoincidence.h" | 
| 8 #include "SkOpContour.h" | 8 #include "SkOpContour.h" | 
| 9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" | 
| 10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" | 
| 11 | 11 | 
|  | 12 #define FAIL_IF(cond) do { if (cond) return false; } while (false) | 
|  | 13 | 
| 12 /* | 14 /* | 
| 13 After computing raw intersections, post process all segments to: | 15 After computing raw intersections, post process all segments to: | 
| 14 - find small collections of points that can be collapsed to a single point | 16 - find small collections of points that can be collapsed to a single point | 
| 15 - find missing intersections to resolve differences caused by different algorith
      ms | 17 - find missing intersections to resolve differences caused by different algorith
      ms | 
| 16 | 18 | 
| 17 Consider segments containing tiny or small intervals. Consider coincident segmen
      ts | 19 Consider segments containing tiny or small intervals. Consider coincident segmen
      ts | 
| 18 because coincidence finds intersections through distance measurement that non-co
      incident | 20 because coincidence finds intersections through distance measurement that non-co
      incident | 
| 19 intersection tests cannot. | 21 intersection tests cannot. | 
| 20  */ | 22  */ | 
| 21 | 23 | 
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 152 | 154 | 
| 153 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
      Winding) { | 155 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
      Winding) { | 
| 154     int maxWinding; | 156     int maxWinding; | 
| 155     setUpWinding(start, end, &maxWinding, sumWinding); | 157     setUpWinding(start, end, &maxWinding, sumWinding); | 
| 156     bool from = maxWinding != 0; | 158     bool from = maxWinding != 0; | 
| 157     bool to = *sumWinding  != 0; | 159     bool to = *sumWinding  != 0; | 
| 158     bool result = gUnaryActiveEdge[from][to]; | 160     bool result = gUnaryActiveEdge[from][to]; | 
| 159     return result; | 161     return result; | 
| 160 } | 162 } | 
| 161 | 163 | 
| 162 void SkOpSegment::addAlignIntersection(SkOpPtT& endPtT, SkPoint& oldPt, |  | 
| 163         SkOpContourHead* contourList, SkChunkAlloc* allocator) { |  | 
| 164     const SkPoint& newPt = endPtT.fPt; |  | 
| 165     if (newPt == oldPt) { |  | 
| 166         return; |  | 
| 167     } |  | 
| 168     SkPoint line[2] = { newPt, oldPt }; |  | 
| 169     SkPathOpsBounds lineBounds; |  | 
| 170     lineBounds.setBounds(line, 2); |  | 
| 171     SkDLine aLine; |  | 
| 172     aLine.set(line); |  | 
| 173     SkOpContour* current = contourList; |  | 
| 174     do { |  | 
| 175         if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) { |  | 
| 176             continue; |  | 
| 177         } |  | 
| 178         SkOpSegment* segment = current->first(); |  | 
| 179         do { |  | 
| 180             if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) { |  | 
| 181                 continue; |  | 
| 182             } |  | 
| 183             if (newPt == segment->fPts[0]) { |  | 
| 184                 continue; |  | 
| 185             } |  | 
| 186             if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { |  | 
| 187                 continue; |  | 
| 188             } |  | 
| 189             if (oldPt == segment->fPts[0]) { |  | 
| 190                 continue; |  | 
| 191             } |  | 
| 192             if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { |  | 
| 193                 continue; |  | 
| 194             } |  | 
| 195             if (endPtT.contains(segment)) { |  | 
| 196                 continue; |  | 
| 197             } |  | 
| 198             SkIntersections i; |  | 
| 199             switch (segment->fVerb) { |  | 
| 200                 case SkPath::kLine_Verb: { |  | 
| 201                     SkDLine bLine; |  | 
| 202                     bLine.set(segment->fPts); |  | 
| 203                     i.intersect(bLine, aLine); |  | 
| 204                     } break; |  | 
| 205                 case SkPath::kQuad_Verb: { |  | 
| 206                     SkDQuad bQuad; |  | 
| 207                     bQuad.set(segment->fPts); |  | 
| 208                     i.intersect(bQuad, aLine); |  | 
| 209                     } break; |  | 
| 210                 case SkPath::kConic_Verb: { |  | 
| 211                     SkDConic bConic; |  | 
| 212                     bConic.set(segment->fPts, segment->fWeight); |  | 
| 213                     i.intersect(bConic, aLine); |  | 
| 214                     } break; |  | 
| 215                 case SkPath::kCubic_Verb: { |  | 
| 216                     SkDCubic bCubic; |  | 
| 217                     bCubic.set(segment->fPts); |  | 
| 218                     i.intersect(bCubic, aLine); |  | 
| 219                     } break; |  | 
| 220                 default: |  | 
| 221                     SkASSERT(0); |  | 
| 222             } |  | 
| 223             if (i.used()) { |  | 
| 224                 SkASSERT(i.used() == 1); |  | 
| 225                 SkASSERT(!zero_or_one(i[0][0])); |  | 
| 226                 SkOpSpanBase* checkSpan = fHead.next(); |  | 
| 227                 while (!checkSpan->final()) { |  | 
| 228                     if (checkSpan->contains(segment)) { |  | 
| 229                         goto nextSegment; |  | 
| 230                     } |  | 
| 231                     checkSpan = checkSpan->upCast()->next(); |  | 
| 232                 } |  | 
| 233                 SkOpPtT* ptT = segment->addT(i[0][0], SkOpSegment::kAllowAlias, 
      allocator); |  | 
| 234                 ptT->fPt = newPt; |  | 
| 235                 endPtT.addOpp(ptT); |  | 
| 236             } |  | 
| 237     nextSegment: |  | 
| 238             ; |  | 
| 239         } while ((segment = segment->next())); |  | 
| 240     } while ((current = current->next())); |  | 
| 241 } |  | 
| 242 |  | 
| 243 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, | 164 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, | 
| 244         SkPathWriter* path) const { | 165         SkPathWriter* path) const { | 
| 245     if (start->starter(end)->alreadyAdded()) { | 166     if (start->starter(end)->alreadyAdded()) { | 
|  | 167         SkDEBUGF(("same curve added twice aborted pathops\n")); | 
| 246         return false; | 168         return false; | 
| 247     } | 169     } | 
| 248     SkOpCurve edge; | 170     SkOpCurve edge; | 
| 249     const SkPoint* ePtr; | 171     const SkPoint* ePtr; | 
| 250     SkScalar eWeight; | 172     SkScalar eWeight; | 
| 251     if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)
      ) { | 173     if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)
      ) { | 
| 252         ePtr = fPts; | 174         ePtr = fPts; | 
| 253         eWeight = fWeight; | 175         eWeight = fWeight; | 
| 254     } else { | 176     } else { | 
| 255     // OPTIMIZE? if not active, skip remainder and return xyAtT(end) | 177     // OPTIMIZE? if not active, skip remainder and return xyAtT(end) | 
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 291             case SkPath::kCubic_Verb: | 213             case SkPath::kCubic_Verb: | 
| 292                 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); | 214                 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); | 
| 293                 break; | 215                 break; | 
| 294             default: | 216             default: | 
| 295                 SkASSERT(0); | 217                 SkASSERT(0); | 
| 296         } | 218         } | 
| 297     } | 219     } | 
| 298     return true; | 220     return true; | 
| 299 } | 221 } | 
| 300 | 222 | 
| 301 SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* alloc
      ator) { | 223 const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const { | 
| 302     SkOpSpanBase* existing = nullptr; | 224     const SkOpSpanBase* test = &fHead; | 
| 303     SkOpSpanBase* test = &fHead; | 225     const SkOpPtT* testPtT; | 
| 304     double testT; | 226     SkPoint pt = this->ptAtT(t); | 
| 305     do { | 227     do { | 
| 306         if ((testT = test->ptT()->fT) >= t) { | 228         testPtT = test->ptT(); | 
| 307             if (testT == t) { | 229         if (testPtT->fT == t) { | 
| 308                 existing = test; |  | 
| 309             } |  | 
| 310             break; | 230             break; | 
| 311         } | 231         } | 
|  | 232         if (!this->match(testPtT, this, t, pt, opp ? kAllowAliasMatch : kNoAlias
      Match)) { | 
|  | 233             if (t < testPtT->fT) { | 
|  | 234                 return nullptr; | 
|  | 235             } | 
|  | 236             continue; | 
|  | 237         } | 
|  | 238         if (!opp) { | 
|  | 239             return testPtT; | 
|  | 240         } | 
|  | 241         const SkOpPtT* loop = testPtT->next(); | 
|  | 242         while (loop != testPtT) { | 
|  | 243             if (loop->segment() == this && loop->fT == t && loop->fPt == pt) { | 
|  | 244                 goto foundMatch; | 
|  | 245             } | 
|  | 246             loop = loop->next(); | 
|  | 247         } | 
|  | 248         return nullptr; | 
| 312     } while ((test = test->upCast()->next())); | 249     } while ((test = test->upCast()->next())); | 
| 313     SkOpPtT* result; | 250 foundMatch: | 
| 314     if (existing && existing->contains(opp)) { | 251     return opp && !test->contains(opp) ? nullptr : testPtT; | 
| 315         result = existing->ptT(); |  | 
| 316     } else { |  | 
| 317         result = this->addT(t, SkOpSegment::kNoAlias, allocator); |  | 
| 318     } |  | 
| 319     SkASSERT(result); |  | 
| 320     return result; |  | 
| 321 } | 252 } | 
| 322 | 253 | 
| 323 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca
      tor) { | 254 // break the span so that the coincident part does not change the angle of the r
      emainder | 
|  | 255 bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* start
      Over) { | 
|  | 256     if (this->contains(newT)) { | 
|  | 257         return true; | 
|  | 258     } | 
|  | 259     SkOpPtT* newPtT = this->addT(newT, kAllowAliasMatch, startOver); | 
|  | 260     if (!newPtT) { | 
|  | 261         return false; | 
|  | 262     } | 
|  | 263     newPtT->fPt = this->ptAtT(newT); | 
|  | 264     // const cast away to change linked list; pt/t values stays unchanged | 
|  | 265     SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test); | 
|  | 266     if (writableTest->ptT()->addOpp(newPtT)) { | 
|  | 267         writableTest->checkForCollapsedCoincidence(); | 
|  | 268     } | 
|  | 269     return true; | 
|  | 270 } | 
|  | 271 | 
|  | 272 // Please keep this in sync with debugAddT() | 
|  | 273 SkOpPtT* SkOpSegment::addT(double t, AliasMatch allowAlias, bool* allocated) { | 
| 324     debugValidate(); | 274     debugValidate(); | 
| 325     SkPoint pt = this->ptAtT(t); | 275     SkPoint pt = this->ptAtT(t); | 
| 326     SkOpSpanBase* span = &fHead; | 276     SkOpSpanBase* span = &fHead; | 
| 327     do { | 277     do { | 
| 328         SkOpPtT* result = span->ptT(); | 278         SkOpPtT* result = span->ptT(); | 
| 329         SkOpPtT* loop; | 279         SkOpPtT* loop; | 
| 330         bool duplicatePt; | 280         bool duplicatePt; | 
| 331         if (t == result->fT) { | 281         if (t == result->fT) { | 
| 332             goto bumpSpan; | 282             goto bumpSpan; | 
| 333         } | 283         } | 
| 334         if (this->match(result, this, t, pt)) { | 284         if (this->match(result, this, t, pt, allowAlias)) { | 
| 335             // see if any existing alias matches segment, pt, and t | 285             // see if any existing alias matches segment, pt, and t | 
| 336            loop = result->next(); | 286             loop = result->next(); | 
| 337             duplicatePt = false; | 287             duplicatePt = false; | 
| 338             while (loop != result) { | 288             while (loop != result) { | 
| 339                 bool ptMatch = loop->fPt == pt; | 289                 bool ptMatch = loop->fPt == pt; | 
| 340                 if (loop->segment() == this && loop->fT == t && ptMatch) { | 290                 if (loop->segment() == this && loop->fT == t && ptMatch) { | 
| 341                     goto bumpSpan; | 291                     goto bumpSpan; | 
| 342                 } | 292                 } | 
| 343                 duplicatePt |= ptMatch; | 293                 duplicatePt |= ptMatch; | 
| 344                 loop = loop->next(); | 294                 loop = loop->next(); | 
| 345             } | 295             } | 
| 346             if (kNoAlias == allowAlias) { | 296             if (kNoAliasMatch == allowAlias) { | 
| 347     bumpSpan: | 297     bumpSpan: | 
| 348                 span->bumpSpanAdds(); | 298                 span->bumpSpanAdds(); | 
| 349                 return result; | 299                 return result; | 
| 350             } | 300             } | 
| 351             SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator); | 301             SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(this->globalState
      ()->allocator()); | 
| 352             alias->init(result->span(), t, pt, duplicatePt); | 302             alias->init(result->span(), t, pt, duplicatePt); | 
| 353             result->insert(alias); | 303             result->insert(alias); | 
| 354             result->span()->unaligned(); | 304             result->span()->unaligned(); | 
| 355             this->debugValidate(); | 305             this->debugValidate(); | 
| 356 #if DEBUG_ADD_T | 306 #if DEBUG_ADD_T | 
| 357             SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n",  __FUNCTION__, t, | 307             SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n",  __FUNCTION__, t, | 
| 358                     alias->segment()->debugID(), alias->span()->debugID()); | 308                     alias->segment()->debugID(), alias->span()->debugID()); | 
| 359 #endif | 309 #endif | 
| 360             span->bumpSpanAdds(); | 310             span->bumpSpanAdds(); | 
|  | 311             if (allocated) { | 
|  | 312                 *allocated = true; | 
|  | 313             } | 
| 361             return alias; | 314             return alias; | 
| 362         } | 315         } | 
| 363         if (t < result->fT) { | 316         if (t < result->fT) { | 
| 364             SkOpSpan* prev = result->span()->prev(); | 317             SkOpSpan* prev = result->span()->prev(); | 
| 365             if (!prev) { | 318             if (!prev) { | 
| 366                 return nullptr; | 319                 return nullptr; | 
| 367             } | 320             } | 
| 368             SkOpSpan* span = insert(prev, allocator); | 321             SkOpSpan* span = insert(prev); | 
| 369             span->init(this, prev, t, pt); | 322             span->init(this, prev, t, pt); | 
| 370             this->debugValidate(); | 323             this->debugValidate(); | 
| 371 #if DEBUG_ADD_T | 324 #if DEBUG_ADD_T | 
| 372             SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, | 325             SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, | 
| 373                     span->segment()->debugID(), span->debugID()); | 326                     span->segment()->debugID(), span->debugID()); | 
| 374 #endif | 327 #endif | 
| 375             span->bumpSpanAdds(); | 328             span->bumpSpanAdds(); | 
|  | 329             if (allocated) { | 
|  | 330                 *allocated = true; | 
|  | 331             } | 
| 376             return span->ptT(); | 332             return span->ptT(); | 
| 377         } | 333         } | 
| 378         SkASSERT(span != &fTail); | 334         SkASSERT(span != &fTail); | 
| 379     } while ((span = span->upCast()->next())); | 335     } while ((span = span->upCast()->next())); | 
| 380     SkASSERT(0); | 336     SkASSERT(0); | 
| 381     return nullptr; | 337     return nullptr; | 
| 382 } | 338 } | 
| 383 | 339 | 
| 384 // choose a solitary t and pt value; remove aliases; align the opposite ends | 340 void SkOpSegment::calcAngles() { | 
| 385 void SkOpSegment::align() { |  | 
| 386     debugValidate(); |  | 
| 387     SkOpSpanBase* span = &fHead; |  | 
| 388     if (!span->aligned()) { |  | 
| 389         span->alignEnd(0, fPts[0]); |  | 
| 390     } |  | 
| 391     while ((span = span->upCast()->next())) { |  | 
| 392         if (span == &fTail) { |  | 
| 393             break; |  | 
| 394         } |  | 
| 395         span->align(); |  | 
| 396     } |  | 
| 397     if (!span->aligned()) { |  | 
| 398         span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); |  | 
| 399     } |  | 
| 400     if (this->collapsed()) { |  | 
| 401         SkOpSpan* span = &fHead; |  | 
| 402         do { |  | 
| 403             span->setWindValue(0); |  | 
| 404             span->setOppValue(0); |  | 
| 405             this->markDone(span); |  | 
| 406         } while ((span = span->next()->upCastable())); |  | 
| 407     } |  | 
| 408     debugValidate(); |  | 
| 409 } |  | 
| 410 |  | 
| 411 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) { |  | 
| 412     bool activePrior = !fHead.isCanceled(); | 341     bool activePrior = !fHead.isCanceled(); | 
| 413     if (activePrior && !fHead.simple()) { | 342     if (activePrior && !fHead.simple()) { | 
| 414         addStartSpan(allocator); | 343         addStartSpan(); | 
| 415     } | 344     } | 
| 416     SkOpSpan* prior = &fHead; | 345     SkOpSpan* prior = &fHead; | 
| 417     SkOpSpanBase* spanBase = fHead.next(); | 346     SkOpSpanBase* spanBase = fHead.next(); | 
| 418     while (spanBase != &fTail) { | 347     while (spanBase != &fTail) { | 
| 419         if (activePrior) { | 348         if (activePrior) { | 
| 420             SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato
      r); | 349             SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate( | 
|  | 350                     this->globalState()->allocator()); | 
| 421             priorAngle->set(spanBase, prior); | 351             priorAngle->set(spanBase, prior); | 
| 422             spanBase->setFromAngle(priorAngle); | 352             spanBase->setFromAngle(priorAngle); | 
| 423         } | 353         } | 
| 424         SkOpSpan* span = spanBase->upCast(); | 354         SkOpSpan* span = spanBase->upCast(); | 
| 425         bool active = !span->isCanceled(); | 355         bool active = !span->isCanceled(); | 
| 426         SkOpSpanBase* next = span->next(); | 356         SkOpSpanBase* next = span->next(); | 
| 427         if (active) { | 357         if (active) { | 
| 428             SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); | 358             SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate( | 
|  | 359                     this->globalState()->allocator()); | 
| 429             angle->set(span, next); | 360             angle->set(span, next); | 
| 430             span->setToAngle(angle); | 361             span->setToAngle(angle); | 
| 431         } | 362         } | 
| 432         activePrior = active; | 363         activePrior = active; | 
| 433         prior = span; | 364         prior = span; | 
| 434         spanBase = next; | 365         spanBase = next; | 
| 435     } | 366     } | 
| 436     if (activePrior && !fTail.simple()) { | 367     if (activePrior && !fTail.simple()) { | 
| 437         addEndSpan(allocator); | 368         addEndSpan(); | 
| 438     } | 369     } | 
| 439 } | 370 } | 
| 440 | 371 | 
|  | 372 // Please keep this in sync with debugClearAll() | 
|  | 373 void SkOpSegment::clearAll() { | 
|  | 374     SkOpSpan* span = &fHead; | 
|  | 375     do { | 
|  | 376         this->clearOne(span); | 
|  | 377     } while ((span = span->next()->upCastable())); | 
|  | 378     this->globalState()->coincidence()->release(this); | 
|  | 379 } | 
|  | 380 | 
|  | 381 // Please keep this in sync with debugClearOne() | 
|  | 382 void SkOpSegment::clearOne(SkOpSpan* span) { | 
|  | 383     span->setWindValue(0); | 
|  | 384     span->setOppValue(0); | 
|  | 385     this->markDone(span); | 
|  | 386 } | 
|  | 387 | 
|  | 388 // Quads and conics collapse if the end points are the same, because | 
|  | 389 // the curve doesn't enclose an area. | 
| 441 bool SkOpSegment::collapsed() const { | 390 bool SkOpSegment::collapsed() const { | 
| 442     return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt(); | 391     // FIXME: cubics can have also collapsed -- need to check if the | 
|  | 392     // control points are on a line with the end points | 
|  | 393     return fVerb < SkPath::kCubic_Verb && fHead.pt() == fTail.pt(); | 
| 443 } | 394 } | 
| 444 | 395 | 
| 445 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
      , | 396 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
      , | 
| 446         SkOpAngle::IncludeType includeType) { | 397         SkOpAngle::IncludeType includeType) { | 
| 447     SkOpSegment* baseSegment = baseAngle->segment(); | 398     SkOpSegment* baseSegment = baseAngle->segment(); | 
| 448     int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | 399     int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | 
| 449     int sumSuWinding; | 400     int sumSuWinding; | 
| 450     bool binary = includeType >= SkOpAngle::kBinarySingle; | 401     bool binary = includeType >= SkOpAngle::kBinarySingle; | 
| 451     if (binary) { | 402     if (binary) { | 
| 452         sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); | 403         sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); | 
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 564             } | 515             } | 
| 565             if (baseAngle) { | 516             if (baseAngle) { | 
| 566                 ComputeOneSumReverse(baseAngle, angle, includeType); | 517                 ComputeOneSumReverse(baseAngle, angle, includeType); | 
| 567                 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : n
      ullptr; | 518                 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : n
      ullptr; | 
| 568             } | 519             } | 
| 569         } while (prior != firstAngle); | 520         } while (prior != firstAngle); | 
| 570     } | 521     } | 
| 571     return start->starter(end)->windSum(); | 522     return start->starter(end)->windSum(); | 
| 572 } | 523 } | 
| 573 | 524 | 
|  | 525 bool SkOpSegment::contains(double newT) const { | 
|  | 526     const SkOpSpanBase* spanBase = &fHead; | 
|  | 527     do { | 
|  | 528         if (spanBase->ptT()->contains(this, newT)) { | 
|  | 529             return true; | 
|  | 530         } | 
|  | 531         if (spanBase == &fTail) { | 
|  | 532             break; | 
|  | 533         } | 
|  | 534         spanBase = spanBase->upCast()->next(); | 
|  | 535     } while (true); | 
|  | 536     return false; | 
|  | 537 } | 
|  | 538 | 
| 574 void SkOpSegment::release(const SkOpSpan* span) { | 539 void SkOpSegment::release(const SkOpSpan* span) { | 
| 575     if (span->done()) { | 540     if (span->done()) { | 
| 576         --fDoneCount; | 541         --fDoneCount; | 
| 577     } | 542     } | 
| 578     --fCount; | 543     --fCount; | 
| 579     SkASSERT(fCount >= fDoneCount); | 544     SkASSERT(this->globalState()->debugSkipAssert() || fCount >= fDoneCount); | 
| 580 } | 545 } | 
| 581 | 546 | 
| 582 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const { | 547 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const { | 
| 583     SkDPoint testPt = this->dPtAtT(t); | 548     SkDPoint testPt = this->dPtAtT(t); | 
| 584     SkDLine testPerp = {{ testPt, testPt }}; | 549     SkDLine testPerp = {{ testPt, testPt }}; | 
| 585     SkDVector slope = this->dSlopeAtT(t); | 550     SkDVector slope = this->dSlopeAtT(t); | 
| 586     testPerp[1].fX += slope.fY; | 551     testPerp[1].fX += slope.fY; | 
| 587     testPerp[1].fY -= slope.fX; | 552     testPerp[1].fY -= slope.fX; | 
| 588     SkIntersections i; | 553     SkIntersections i; | 
| 589     const SkOpSegment* oppSegment = oppAngle->segment(); | 554     const SkOpSegment* oppSegment = oppAngle->segment(); | 
| 590     (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weig
      ht(), testPerp, &i); | 555     (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weig
      ht(), testPerp, &i); | 
| 591     double closestDistSq = SK_ScalarInfinity; | 556     double closestDistSq = SK_ScalarInfinity; | 
| 592     for (int index = 0; index < i.used(); ++index) { | 557     for (int index = 0; index < i.used(); ++index) { | 
| 593         if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t()))
       { | 558         if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t()))
       { | 
| 594             continue; | 559             continue; | 
| 595         } | 560         } | 
| 596         double testDistSq = testPt.distanceSquared(i.pt(index)); | 561         double testDistSq = testPt.distanceSquared(i.pt(index)); | 
| 597         if (closestDistSq > testDistSq) { | 562         if (closestDistSq > testDistSq) { | 
| 598             closestDistSq = testDistSq; | 563             closestDistSq = testDistSq; | 
| 599         } | 564         } | 
| 600     } | 565     } | 
| 601     return closestDistSq; | 566     return closestDistSq; | 
| 602 } | 567 } | 
| 603 | 568 | 
| 604 void SkOpSegment::findCollapsed() { |  | 
| 605     if (fHead.contains(&fTail)) { |  | 
| 606         markAllDone(); |  | 
| 607         // move start and end to the same point |  | 
| 608         fHead.alignEnd(0, fHead.pt()); |  | 
| 609         fTail.setAligned(); |  | 
| 610     } |  | 
| 611 } |  | 
| 612 |  | 
| 613 /* | 569 /* | 
| 614  The M and S variable name parts stand for the operators. | 570  The M and S variable name parts stand for the operators. | 
| 615    Mi stands for Minuend (see wiki subtraction, analogous to difference) | 571    Mi stands for Minuend (see wiki subtraction, analogous to difference) | 
| 616    Su stands for Subtrahend | 572    Su stands for Subtrahend | 
| 617  The Opp variable name part designates that the value is for the Opposite operat
      or. | 573  The Opp variable name part designates that the value is for the Opposite operat
      or. | 
| 618  Opposite values result from combining coincident spans. | 574  Opposite values result from combining coincident spans. | 
| 619  */ | 575  */ | 
| 620 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa
      se** nextStart, | 576 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa
      se** nextStart, | 
| 621         SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in
      t xorSuMask) { | 577         SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in
      t xorSuMask) { | 
| 622     SkOpSpanBase* start = *nextStart; | 578     SkOpSpanBase* start = *nextStart; | 
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 880     *nextEnd = foundAngle->end(); | 836     *nextEnd = foundAngle->end(); | 
| 881     nextSegment = foundAngle->segment(); | 837     nextSegment = foundAngle->segment(); | 
| 882 #if DEBUG_WINDING | 838 #if DEBUG_WINDING | 
| 883     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 839     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 
| 884             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
      d); | 840             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
      d); | 
| 885  #endif | 841  #endif | 
| 886     return nextSegment; | 842     return nextSegment; | 
| 887 } | 843 } | 
| 888 | 844 | 
| 889 SkOpGlobalState* SkOpSegment::globalState() const { | 845 SkOpGlobalState* SkOpSegment::globalState() const { | 
| 890     return contour()->globalState(); | 846     return contour()->globalState(); | 
| 891 } | 847 } | 
| 892 | 848 | 
| 893 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
      ath::Verb verb) { | 849 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
      ath::Verb verb) { | 
| 894     fContour = contour; | 850     fContour = contour; | 
| 895     fNext = nullptr; | 851     fNext = nullptr; | 
| 896     fOriginal[0] = pts[0]; |  | 
| 897     fOriginal[1] = pts[SkPathOpsVerbToPoints(verb)]; |  | 
| 898     fPts = pts; | 852     fPts = pts; | 
| 899     fWeight = weight; | 853     fWeight = weight; | 
| 900     fVerb = verb; | 854     fVerb = verb; | 
| 901     fCount = 0; | 855     fCount = 0; | 
| 902     fDoneCount = 0; | 856     fDoneCount = 0; | 
| 903     fVisited = false; | 857     fVisited = false; | 
| 904     SkOpSpan* zeroSpan = &fHead; | 858     SkOpSpan* zeroSpan = &fHead; | 
| 905     zeroSpan->init(this, nullptr, 0, fPts[0]); | 859     zeroSpan->init(this, nullptr, 0, fPts[0]); | 
| 906     SkOpSpanBase* oneSpan = &fTail; | 860     SkOpSpanBase* oneSpan = &fTail; | 
| 907     zeroSpan->setNext(oneSpan); | 861     zeroSpan->setNext(oneSpan); | 
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1088 #if DEBUG_MARK_DONE | 1042 #if DEBUG_MARK_DONE | 
| 1089     debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); | 1043     debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); | 
| 1090 #endif | 1044 #endif | 
| 1091     span->setWindSum(winding); | 1045     span->setWindSum(winding); | 
| 1092     span->setOppSum(oppWinding); | 1046     span->setOppSum(oppWinding); | 
| 1093     debugValidate(); | 1047     debugValidate(); | 
| 1094     return true; | 1048     return true; | 
| 1095 } | 1049 } | 
| 1096 | 1050 | 
| 1097 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub
      le testT, | 1051 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub
      le testT, | 
| 1098         const SkPoint& testPt) const { | 1052         const SkPoint& testPt, AliasMatch aliasMatch) const { | 
| 1099     const SkOpSegment* baseParent = base->segment(); | 1053     SkASSERT(this == base->segment()); | 
| 1100     if (this == baseParent && this == testParent && precisely_equal(base->fT, te
      stT)) { | 1054     if (this == testParent) { | 
| 1101         return true; | 1055         if (precisely_equal(base->fT, testT)) { | 
|  | 1056             return true; | 
|  | 1057         } | 
| 1102     } | 1058     } | 
| 1103     if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { | 1059     if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { | 
| 1104         return false; | 1060         return false; | 
| 1105     } | 1061     } | 
| 1106     return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); | 1062     return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, 
      testPt); | 
| 1107 } | 1063 } | 
| 1108 | 1064 | 
| 1109 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { | 1065 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { | 
| 1110     if (last) { | 1066     if (last) { | 
| 1111         *last = endSpan; | 1067         *last = endSpan; | 
| 1112     } | 1068     } | 
| 1113     return nullptr; | 1069     return nullptr; | 
| 1114 } | 1070 } | 
| 1115 | 1071 | 
| 1116 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
      pan** minPtr, | 1072 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
      pan** minPtr, | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1171           return set_last(last, endSpan); | 1127           return set_last(last, endSpan); | 
| 1172     } | 1128     } | 
| 1173     *startPtr = foundSpan; | 1129     *startPtr = foundSpan; | 
| 1174     *stepPtr = foundStep; | 1130     *stepPtr = foundStep; | 
| 1175     if (minPtr) { | 1131     if (minPtr) { | 
| 1176         *minPtr = foundMin; | 1132         *minPtr = foundMin; | 
| 1177     } | 1133     } | 
| 1178     return other; | 1134     return other; | 
| 1179 } | 1135 } | 
| 1180 | 1136 | 
| 1181 static void clear_visited(SkOpSpanBase* span) { | 1137 // Please keep this in sync with DebugClearVisited() | 
|  | 1138 void SkOpSegment::ClearVisited(SkOpSpanBase* span) { | 
| 1182     // reset visited flag back to false | 1139     // reset visited flag back to false | 
| 1183     do { | 1140     do { | 
| 1184         SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; | 1141         SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; | 
| 1185         while ((ptT = ptT->next()) != stopPtT) { | 1142         while ((ptT = ptT->next()) != stopPtT) { | 
| 1186             SkOpSegment* opp = ptT->segment(); | 1143             SkOpSegment* opp = ptT->segment(); | 
| 1187             opp->resetVisited(); | 1144             opp->resetVisited(); | 
| 1188         } | 1145         } | 
| 1189     } while (!span->final() && (span = span->upCast()->next())); | 1146     } while (!span->final() && (span = span->upCast()->next())); | 
| 1190 } | 1147 } | 
| 1191 | 1148 | 
|  | 1149 // Please keep this in sync with debugMissingCoincidence() | 
| 1192 // look for pairs of undetected coincident curves | 1150 // look for pairs of undetected coincident curves | 
| 1193 // assumes that segments going in have visited flag clear | 1151 // assumes that segments going in have visited flag clear | 
| 1194 // curve/curve intersection should now do a pretty good job of finding coinciden
      t runs so | 1152 // Even though pairs of curves correct detect coincident runs, a run may be miss
      ed | 
| 1195 // this may be only be necessary for line/curve pairs -- so skip unless this is 
      a line and the | 1153 // if the coincidence is a product of multiple intersections. For instance, give
      n | 
| 1196 // the opp is not a line | 1154 // curves A, B, and C: | 
| 1197 bool SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
      * allocator) { | 1155 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near | 
| 1198     if (this->verb() != SkPath::kLine_Verb) { | 1156 // the end of C that the intersection is replaced with the end of C. | 
| 1199         return false; | 1157 // Even though A-B correctly do not detect an intersection at point 2, | 
| 1200     } | 1158 // the resulting run from point 1 to point 2 is coincident on A and B. | 
|  | 1159 bool SkOpSegment::missingCoincidence() { | 
| 1201     if (this->done()) { | 1160     if (this->done()) { | 
| 1202         return false; | 1161         return false; | 
| 1203     } | 1162     } | 
| 1204     SkOpSpan* prior = nullptr; | 1163     SkOpSpan* prior = nullptr; | 
| 1205     SkOpSpanBase* spanBase = &fHead; | 1164     SkOpSpanBase* spanBase = &fHead; | 
|  | 1165     bool result = false; | 
| 1206     do { | 1166     do { | 
| 1207         SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; | 1167         SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; | 
| 1208         SkASSERT(ptT->span() == spanBase); | 1168         SkASSERT(ptT->span() == spanBase); | 
| 1209         while ((ptT = ptT->next()) != spanStopPtT) { | 1169         while ((ptT = ptT->next()) != spanStopPtT) { | 
| 1210             if (ptT->deleted()) { | 1170             if (ptT->deleted()) { | 
| 1211                 continue; | 1171                 continue; | 
| 1212             } | 1172             } | 
| 1213             SkOpSegment* opp = ptT->span()->segment(); | 1173             SkOpSegment* opp = ptT->span()->segment(); | 
| 1214 //            if (opp->verb() == SkPath::kLine_Verb) { |  | 
| 1215 //                continue; |  | 
| 1216 //            } |  | 
| 1217             if (opp->done()) { | 1174             if (opp->done()) { | 
| 1218                 continue; | 1175                 continue; | 
| 1219             } | 1176             } | 
| 1220             // when opp is encounted the 1st time, continue; on 2nd encounter, l
      ook for coincidence | 1177             // when opp is encounted the 1st time, continue; on 2nd encounter, l
      ook for coincidence | 
| 1221             if (!opp->visited()) { | 1178             if (!opp->visited()) { | 
| 1222                 continue; | 1179                 continue; | 
| 1223             } | 1180             } | 
| 1224             if (spanBase == &fHead) { | 1181             if (spanBase == &fHead) { | 
| 1225                 continue; | 1182                 continue; | 
| 1226             } | 1183             } | 
|  | 1184             if (ptT->segment() == this) { | 
|  | 1185                 continue; | 
|  | 1186             } | 
| 1227             SkOpSpan* span = spanBase->upCastable(); | 1187             SkOpSpan* span = spanBase->upCastable(); | 
| 1228             // FIXME?: this assumes that if the opposite segment is coincident t
      hen no more | 1188             // FIXME?: this assumes that if the opposite segment is coincident t
      hen no more | 
| 1229             // coincidence needs to be detected. This may not be true. | 1189             // coincidence needs to be detected. This may not be true. | 
| 1230             if (span && span->containsCoincidence(opp)) { | 1190             if (span && span->containsCoincidence(opp)) { | 
| 1231                 continue; |  | 
| 1232             } |  | 
| 1233             if (spanBase->segment() == opp) { |  | 
| 1234                 continue; | 1191                 continue; | 
| 1235             } | 1192             } | 
| 1236             if (spanBase->containsCoinEnd(opp)) { | 1193             if (spanBase->containsCoinEnd(opp)) { | 
| 1237                 continue; | 1194                 continue; | 
| 1238             } | 1195             } | 
| 1239             SkOpPtT* priorPtT = nullptr, * priorStopPtT; | 1196             SkOpPtT* priorPtT = nullptr, * priorStopPtT; | 
| 1240             // find prior span containing opp segment | 1197             // find prior span containing opp segment | 
| 1241             SkOpSegment* priorOpp = nullptr; | 1198             SkOpSegment* priorOpp = nullptr; | 
| 1242             SkOpSpan* priorTest = spanBase->prev(); | 1199             SkOpSpan* priorTest = spanBase->prev(); | 
| 1243             while (!priorOpp && priorTest) { | 1200             while (!priorOpp && priorTest) { | 
| 1244                 priorStopPtT = priorPtT = priorTest->ptT(); | 1201                 priorStopPtT = priorPtT = priorTest->ptT(); | 
| 1245                 while ((priorPtT = priorPtT->next()) != priorStopPtT) { | 1202                 while ((priorPtT = priorPtT->next()) != priorStopPtT) { | 
| 1246                     if (priorPtT->deleted()) { | 1203                     if (priorPtT->deleted()) { | 
| 1247                         continue; | 1204                         continue; | 
| 1248                     } | 1205                     } | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 1261             if (priorPtT == ptT) { | 1218             if (priorPtT == ptT) { | 
| 1262                 continue; | 1219                 continue; | 
| 1263             } | 1220             } | 
| 1264             SkOpPtT* oppStart = prior->ptT(); | 1221             SkOpPtT* oppStart = prior->ptT(); | 
| 1265             SkOpPtT* oppEnd = spanBase->ptT(); | 1222             SkOpPtT* oppEnd = spanBase->ptT(); | 
| 1266             bool swapped = priorPtT->fT > ptT->fT; | 1223             bool swapped = priorPtT->fT > ptT->fT; | 
| 1267             if (swapped) { | 1224             if (swapped) { | 
| 1268                 SkTSwap(priorPtT, ptT); | 1225                 SkTSwap(priorPtT, ptT); | 
| 1269                 SkTSwap(oppStart, oppEnd); | 1226                 SkTSwap(oppStart, oppEnd); | 
| 1270             } | 1227             } | 
| 1271             bool flipped = oppStart->fT > oppEnd->fT; | 1228             SkOpCoincidence* coincidences = this->globalState()->coincidence(); | 
| 1272             bool coincident = false; | 1229             SkOpPtT* rootPriorPtT = priorPtT->span()->ptT(); | 
| 1273             if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)
      ) { | 1230             SkOpPtT* rootPtT = ptT->span()->ptT(); | 
|  | 1231             SkOpPtT* rootOppStart = oppStart->span()->ptT(); | 
|  | 1232             SkOpPtT* rootOppEnd = oppEnd->span()->ptT(); | 
|  | 1233             if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, root
      OppEnd)) { | 
| 1274                 goto swapBack; | 1234                 goto swapBack; | 
| 1275             } | 1235             } | 
| 1276             if (opp->verb() == SkPath::kLine_Verb) { | 1236             if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase,
       opp)) { | 
| 1277                 coincident = (SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppSta
      rt->fPt) || |  | 
| 1278                         SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppEnd->fPt)
      ) && |  | 
| 1279                         (SkDPoint::ApproximatelyEqual(ptT->fPt, oppStart->fPt) |
      | |  | 
| 1280                         SkDPoint::ApproximatelyEqual(ptT->fPt, oppEnd->fPt)); |  | 
| 1281             } |  | 
| 1282             if (!coincident) { |  | 
| 1283                 coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, 
      opp, 5000); |  | 
| 1284             } |  | 
| 1285             if (coincident) { |  | 
| 1286             // mark coincidence | 1237             // mark coincidence | 
| 1287                 if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd) | 1238 #if DEBUG_COINCIDENCE_VERBOSE | 
| 1288                         && !coincidences->extend(oppStart, oppEnd, priorPtT, ptT
      )) { | 1239                 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n",
       __FUNCTION__, | 
| 1289                     coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator
      ); | 1240                         rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStar
      t->debugID(), | 
|  | 1241                         rootOppEnd->debugID()); | 
|  | 1242 #endif | 
|  | 1243                 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, r
      ootOppEnd)) { | 
|  | 1244                     coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootO
      ppEnd); | 
| 1290                 } | 1245                 } | 
| 1291                 clear_visited(&fHead); | 1246 #if DEBUG_COINCIDENCE | 
| 1292                 return true; | 1247                 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppSt
      art, rootOppEnd)); | 
|  | 1248 #endif | 
|  | 1249                 result = true; | 
| 1293             } | 1250             } | 
| 1294     swapBack: | 1251     swapBack: | 
| 1295             if (swapped) { | 1252             if (swapped) { | 
| 1296                 SkTSwap(priorPtT, ptT); | 1253                 SkTSwap(priorPtT, ptT); | 
| 1297             } | 1254             } | 
| 1298         } | 1255         } | 
| 1299     } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next(
      ))); | 1256     } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next(
      ))); | 
| 1300     clear_visited(&fHead); | 1257     ClearVisited(&fHead); | 
| 1301     return false; | 1258     return result; | 
| 1302 } | 1259 } | 
| 1303 | 1260 | 
|  | 1261 // please keep this in sync with debugMoveMultiples() | 
| 1304 // if a span has more than one intersection, merge the other segments' span as n
      eeded | 1262 // if a span has more than one intersection, merge the other segments' span as n
      eeded | 
| 1305 bool SkOpSegment::moveMultiples() { | 1263 bool SkOpSegment::moveMultiples() { | 
| 1306     debugValidate(); | 1264     debugValidate(); | 
| 1307     SkOpSpanBase* test = &fHead; | 1265     SkOpSpanBase* test = &fHead; | 
| 1308     do { | 1266     do { | 
| 1309         int addCount = test->spanAddsCount(); | 1267         int addCount = test->spanAddsCount(); | 
| 1310         if (addCount < 1) { | 1268         FAIL_IF(addCount < 1); | 
| 1311             return false; |  | 
| 1312         } |  | 
| 1313         if (addCount == 1) { | 1269         if (addCount == 1) { | 
| 1314             continue; | 1270             continue; | 
| 1315         } | 1271         } | 
| 1316         SkOpPtT* startPtT = test->ptT(); | 1272         SkOpPtT* startPtT = test->ptT(); | 
| 1317         SkOpPtT* testPtT = startPtT; | 1273         SkOpPtT* testPtT = startPtT; | 
| 1318         do {  // iterate through all spans associated with start | 1274         do {  // iterate through all spans associated with start | 
| 1319             SkOpSpanBase* oppSpan = testPtT->span(); | 1275             SkOpSpanBase* oppSpan = testPtT->span(); | 
| 1320             if (oppSpan->spanAddsCount() == addCount) { | 1276             if (oppSpan->spanAddsCount() == addCount) { | 
| 1321                 continue; | 1277                 continue; | 
| 1322             } | 1278             } | 
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1385                     if (oppTest == &oppSegment->fTail || oppTest == &oppSegment-
      >fHead) { | 1341                     if (oppTest == &oppSegment->fTail || oppTest == &oppSegment-
      >fHead) { | 
| 1386                         SkASSERT(oppSpan != &oppSegment->fHead); // don't expect
       collapse | 1342                         SkASSERT(oppSpan != &oppSegment->fHead); // don't expect
       collapse | 
| 1387                         SkASSERT(oppSpan != &oppSegment->fTail); | 1343                         SkASSERT(oppSpan != &oppSegment->fTail); | 
| 1388                         oppTest->merge(oppSpan->upCast()); | 1344                         oppTest->merge(oppSpan->upCast()); | 
| 1389                     } else { | 1345                     } else { | 
| 1390                         oppSpan->merge(oppTest->upCast()); | 1346                         oppSpan->merge(oppTest->upCast()); | 
| 1391                     } | 1347                     } | 
| 1392                     oppSegment->debugValidate(); | 1348                     oppSegment->debugValidate(); | 
| 1393                     goto checkNextSpan; | 1349                     goto checkNextSpan; | 
| 1394                 } | 1350                 } | 
| 1395         tryNextSpan: | 1351         tryNextSpan: | 
| 1396                 ; | 1352                 ; | 
| 1397             } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next())
      ); | 1353             } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next())
      ); | 
| 1398         } while ((testPtT = testPtT->next()) != startPtT); | 1354         } while ((testPtT = testPtT->next()) != startPtT); | 
| 1399 checkNextSpan: | 1355 checkNextSpan: | 
| 1400         ; | 1356         ; | 
| 1401     } while ((test = test->final() ? nullptr : test->upCast()->next())); | 1357     } while ((test = test->final() ? nullptr : test->upCast()->next())); | 
| 1402     debugValidate(); | 1358     debugValidate(); | 
| 1403     return true; | 1359     return true; | 
| 1404 } | 1360 } | 
| 1405 | 1361 | 
|  | 1362 // adjacent spans may have points close by | 
|  | 1363 bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* c
      heckSpan) const { | 
|  | 1364     const SkOpPtT* refHead = refSpan->ptT(); | 
|  | 1365     const SkOpPtT* checkHead = checkSpan->ptT(); | 
|  | 1366 // if the first pt pair from adjacent spans are far apart, assume that all are f
      ar enough apart | 
|  | 1367     if (!SkDPoint::RoughlyEqual(refHead->fPt, checkHead->fPt)) { | 
|  | 1368 #if DEBUG_COINCIDENCE | 
|  | 1369         // verify that no combination of points are close | 
|  | 1370         const SkOpPtT* dBugRef = refHead; | 
|  | 1371         do { | 
|  | 1372             const SkOpPtT* dBugCheck = checkHead; | 
|  | 1373             do { | 
|  | 1374                 SkASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->
      fPt)); | 
|  | 1375                 dBugCheck = dBugCheck->next(); | 
|  | 1376             } while (dBugCheck != checkHead); | 
|  | 1377             dBugRef = dBugRef->next(); | 
|  | 1378         } while (dBugRef != refHead); | 
|  | 1379 #endif | 
|  | 1380         return false; | 
|  | 1381     } | 
|  | 1382     // check only unique points | 
|  | 1383     SkScalar distSqBest = SK_ScalarMax; | 
|  | 1384     const SkOpPtT* refBest = nullptr; | 
|  | 1385     const SkOpPtT* checkBest = nullptr; | 
|  | 1386     const SkOpPtT* ref = refHead; | 
|  | 1387     do { | 
|  | 1388         if (ref->deleted()) { | 
|  | 1389             continue; | 
|  | 1390         } | 
|  | 1391         while (ref->ptAlreadySeen(refHead)) { | 
|  | 1392             ref = ref->next(); | 
|  | 1393             if (ref == refHead) { | 
|  | 1394                 goto doneCheckingDistance; | 
|  | 1395             } | 
|  | 1396         } | 
|  | 1397         const SkOpPtT* check = checkHead; | 
|  | 1398         const SkOpSegment* refSeg = ref->segment(); | 
|  | 1399         do { | 
|  | 1400             if (check->deleted()) { | 
|  | 1401                 continue; | 
|  | 1402             } | 
|  | 1403             while (check->ptAlreadySeen(checkHead)) { | 
|  | 1404                 check = check->next(); | 
|  | 1405                 if (check == checkHead) { | 
|  | 1406                     goto nextRef; | 
|  | 1407                 } | 
|  | 1408             } | 
|  | 1409             SkScalar distSq = ref->fPt.distanceToSqd(check->fPt); | 
|  | 1410             if (distSqBest > distSq && (refSeg != check->segment() | 
|  | 1411                     || !refSeg->ptsDisjoint(*ref, *check))) { | 
|  | 1412                 distSqBest = distSq; | 
|  | 1413                 refBest = ref; | 
|  | 1414                 checkBest = check; | 
|  | 1415             } | 
|  | 1416         } while ((check = check->next()) != checkHead); | 
|  | 1417 nextRef: | 
|  | 1418         ; | 
|  | 1419    } while ((ref = ref->next()) != refHead); | 
|  | 1420 doneCheckingDistance: | 
|  | 1421     return checkBest && refBest->segment()->match(refBest, checkBest->segment(),
       checkBest->fT, | 
|  | 1422             checkBest->fPt, kAllowAliasMatch); | 
|  | 1423 } | 
|  | 1424 | 
|  | 1425 // Please keep this function in sync with debugMoveNearby() | 
| 1406 // Move nearby t values and pts so they all hang off the same span. Alignment ha
      ppens later. | 1426 // Move nearby t values and pts so they all hang off the same span. Alignment ha
      ppens later. | 
| 1407 void SkOpSegment::moveNearby() { | 1427 void SkOpSegment::moveNearby() { | 
| 1408     debugValidate(); | 1428     debugValidate(); | 
| 1409     SkOpSpanBase* spanS = &fHead; | 1429     // release undeleted spans pointing to this seg that are linked to the prima
      ry span | 
|  | 1430     SkOpSpanBase* spanBase = &fHead; | 
| 1410     do { | 1431     do { | 
| 1411         SkOpSpanBase* test = spanS->upCast()->next(); | 1432         SkOpPtT* ptT = spanBase->ptT(); | 
| 1412         SkOpSpanBase* next; | 1433         const SkOpPtT* headPtT = ptT; | 
| 1413         if (spanS->contains(test)) { | 1434         while ((ptT = ptT->next()) != headPtT) { | 
| 1414             if (!test->final()) { | 1435             SkOpSpanBase* test = ptT->span(); | 
| 1415                 test->upCast()->release(spanS->ptT()); | 1436             if (ptT->segment() == this && !ptT->deleted() && test != spanBase | 
| 1416                 continue; | 1437                     && test->ptT() == ptT) { | 
| 1417             } else if (spanS != &fHead) { | 1438                 if (test->final()) { | 
| 1418                 spanS->upCast()->release(test->ptT()); | 1439                     if (spanBase == &fHead) { | 
| 1419                 spanS = test; | 1440                         this->clearAll(); | 
| 1420                 continue; | 1441                         return; | 
|  | 1442                     } | 
|  | 1443                     spanBase->upCast()->release(ptT); | 
|  | 1444                 } else if (test->prev()) { | 
|  | 1445                     test->upCast()->release(headPtT); | 
|  | 1446                 } | 
|  | 1447                 break; | 
| 1421             } | 1448             } | 
| 1422         } | 1449         } | 
| 1423         do {  // iterate through all spans associated with start | 1450         spanBase = spanBase->upCast()->next(); | 
| 1424             SkOpPtT* startBase = spanS->ptT(); | 1451     } while (!spanBase->final()); | 
| 1425             next = test->final() ? nullptr : test->upCast()->next(); | 1452 | 
| 1426             do { | 1453     // This loop looks for adjacent spans which are near by | 
| 1427                 SkOpPtT* testBase = test->ptT(); | 1454     spanBase = &fHead; | 
| 1428                 do { | 1455     do {  // iterate through all spans associated with start | 
| 1429                     if (startBase == testBase) { | 1456         SkOpSpanBase* test = spanBase->upCast()->next(); | 
| 1430                         goto checkNextSpan; | 1457         if (this->spansNearby(spanBase, test)) { | 
| 1431                     } | 1458             if (test->final()) { | 
| 1432                     if (testBase->duplicate()) { | 1459                 if (spanBase->prev()) { | 
| 1433                         continue; | 1460                     test->merge(spanBase->upCast()); | 
| 1434                     } | 1461                 } else { | 
| 1435                     if (this->match(startBase, testBase->segment(), testBase->fT
      , testBase->fPt)) { | 1462                     this->clearAll(); | 
| 1436                         if (test == &this->fTail) { | 1463                     return; | 
| 1437                             if (spanS == &fHead) { | 1464                 } | 
| 1438                                 debugValidate(); | 1465             } else { | 
| 1439                                 return;  // if this span has collapsed, remove i
      t from parent | 1466                 spanBase->merge(test->upCast()); | 
| 1440                             } | 1467             } | 
| 1441                             this->fTail.merge(spanS->upCast()); | 1468         } | 
| 1442                             debugValidate(); | 1469         spanBase = test; | 
| 1443                             return; | 1470     } while (!spanBase->final()); | 
| 1444                         } |  | 
| 1445                         spanS->merge(test->upCast()); |  | 
| 1446                         goto checkNextSpan; |  | 
| 1447                     } |  | 
| 1448                 } while ((testBase = testBase->next()) != test->ptT()); |  | 
| 1449             } while ((startBase = startBase->next()) != spanS->ptT()); |  | 
| 1450     checkNextSpan: |  | 
| 1451             ; |  | 
| 1452         } while ((test = next)); |  | 
| 1453         spanS = spanS->upCast()->next(); |  | 
| 1454     } while (!spanS->final()); |  | 
| 1455     debugValidate(); | 1471     debugValidate(); | 
| 1456 } | 1472 } | 
| 1457 | 1473 | 
| 1458 bool SkOpSegment::operand() const { | 1474 bool SkOpSegment::operand() const { | 
| 1459     return fContour->operand(); | 1475     return fContour->operand(); | 
| 1460 } | 1476 } | 
| 1461 | 1477 | 
| 1462 bool SkOpSegment::oppXor() const { | 1478 bool SkOpSegment::oppXor() const { | 
| 1463     return fContour->oppXor(); | 1479     return fContour->oppXor(); | 
| 1464 } | 1480 } | 
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1672         edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg
      e->fQuad[2], | 1688         edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg
      e->fQuad[2], | 
| 1673             startT, endT, &edge->fConic.fWeight); | 1689             startT, endT, &edge->fConic.fWeight); | 
| 1674     } else { | 1690     } else { | 
| 1675         SkASSERT(fVerb == SkPath::kCubic_Verb); | 1691         SkASSERT(fVerb == SkPath::kCubic_Verb); | 
| 1676         SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT
      , &edge->fCubic[1]); | 1692         SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT
      , &edge->fCubic[1]); | 
| 1677     } | 1693     } | 
| 1678     return true; | 1694     return true; | 
| 1679 } | 1695 } | 
| 1680 | 1696 | 
| 1681 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT
      , | 1697 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT
      , | 
| 1682         const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegme
      nt* opp, | 1698         const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegme
      nt* opp) const { | 
| 1683         SkScalar flatnessLimit) const { |  | 
| 1684     // average t, find mid pt | 1699     // average t, find mid pt | 
| 1685     double midT = (prior->t() + spanBase->t()) / 2; | 1700     double midT = (prior->t() + spanBase->t()) / 2; | 
| 1686     SkPoint midPt = this->ptAtT(midT); | 1701     SkPoint midPt = this->ptAtT(midT); | 
| 1687     bool coincident = true; | 1702     bool coincident = true; | 
| 1688     // if the mid pt is not near either end pt, project perpendicular through op
      p seg | 1703     // if the mid pt is not near either end pt, project perpendicular through op
      p seg | 
| 1689     if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) | 1704     if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) | 
| 1690             && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { | 1705             && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { | 
|  | 1706         if (priorPtT->span() == ptT->span()) { | 
|  | 1707           return false; | 
|  | 1708         } | 
| 1691         coincident = false; | 1709         coincident = false; | 
| 1692         SkIntersections i; | 1710         SkIntersections i; | 
| 1693         SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), mid
      T); | 1711         SkDCurve curvePart; | 
| 1694         SkDLine ray = {{{midPt.fX, midPt.fY}, | 1712         this->subDivide(prior, spanBase, &curvePart); | 
| 1695                 {(double) midPt.fX + dxdy.fY, (double) midPt.fY - dxdy.fX}}}; | 1713         SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f); | 
| 1696         (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i); | 1714         SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f); | 
|  | 1715         SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt
      .fY - dxdy.fX}}}; | 
|  | 1716         SkDCurve oppPart; | 
|  | 1717         opp->subDivide(priorPtT->span(), ptT->span(), &oppPart); | 
|  | 1718         (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i); | 
| 1697         // measure distance and see if it's small enough to denote coincidence | 1719         // measure distance and see if it's small enough to denote coincidence | 
| 1698         for (int index = 0; index < i.used(); ++index) { | 1720         for (int index = 0; index < i.used(); ++index) { | 
|  | 1721             if (!between(0, i[0][index], 1)) { | 
|  | 1722                 continue; | 
|  | 1723             } | 
| 1699             SkDPoint oppPt = i.pt(index); | 1724             SkDPoint oppPt = i.pt(index); | 
| 1700             if (oppPt.approximatelyEqual(midPt)) { | 1725             if (oppPt.approximatelyEqual(midPt)) { | 
| 1701                 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(), | 1726                 // the coincidence can occur at almost any angle | 
| 1702                         opp->weight(), i[index][0]); | 1727                 coincident = true; | 
| 1703                 oppDxdy.normalize(); |  | 
| 1704                 dxdy.normalize(); |  | 
| 1705                 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILO
      N); |  | 
| 1706                 coincident |= flatness < flatnessLimit; |  | 
| 1707             } | 1728             } | 
| 1708         } | 1729         } | 
| 1709     } | 1730     } | 
| 1710     return coincident; | 1731     return coincident; | 
| 1711 } | 1732 } | 
| 1712 | 1733 | 
| 1713 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { | 1734 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { | 
| 1714     SkOpSpan* span = this->head(); | 1735     SkOpSpan* span = this->head(); | 
| 1715     do { | 1736     do { | 
| 1716         if (!span->done()) { | 1737         if (!span->done()) { | 
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1783     int absOut = SkTAbs(outerWinding); | 1804     int absOut = SkTAbs(outerWinding); | 
| 1784     int absIn = SkTAbs(innerWinding); | 1805     int absIn = SkTAbs(innerWinding); | 
| 1785     bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; | 1806     bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; | 
| 1786     return result; | 1807     return result; | 
| 1787 } | 1808 } | 
| 1788 | 1809 | 
| 1789 int SkOpSegment::windSum(const SkOpAngle* angle) const { | 1810 int SkOpSegment::windSum(const SkOpAngle* angle) const { | 
| 1790     const SkOpSpan* minSpan = angle->start()->starter(angle->end()); | 1811     const SkOpSpan* minSpan = angle->start()->starter(angle->end()); | 
| 1791     return minSpan->windSum(); | 1812     return minSpan->windSum(); | 
| 1792 } | 1813 } | 
| OLD | NEW | 
|---|