| 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 "SkAddIntersections.h" | 7 #include "SkAddIntersections.h" |
| 8 #include "SkOpCoincidence.h" |
| 8 #include "SkOpEdgeBuilder.h" | 9 #include "SkOpEdgeBuilder.h" |
| 9 #include "SkPathOpsCommon.h" | 10 #include "SkPathOpsCommon.h" |
| 10 #include "SkPathWriter.h" | 11 #include "SkPathWriter.h" |
| 11 #include "SkTSort.h" | 12 #include "SkTSort.h" |
| 12 | 13 |
| 13 static void alignMultiples(SkTArray<SkOpContour*, true>* contourList, | 14 static int contourRangeCheckY(const SkTDArray<SkOpContour* >& contourList, |
| 14 SkTDArray<SkOpSegment::AlignedSpan>* aligned) { | 15 SkOpSegment** currentPtr, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr
, |
| 15 int contourCount = (*contourList).count(); | 16 double* bestHit, SkScalar* bestDx, bool* tryAgain, double* midPtr, bool
opp) { |
| 16 for (int cTest = 0; cTest < contourCount; ++cTest) { | 17 SkOpSpanBase* start = *startPtr; |
| 17 SkOpContour* contour = (*contourList)[cTest]; | 18 SkOpSpanBase* end = *endPtr; |
| 18 if (contour->hasMultiples()) { | |
| 19 contour->alignMultiples(aligned); | |
| 20 } | |
| 21 } | |
| 22 } | |
| 23 | |
| 24 static void alignCoincidence(SkTArray<SkOpContour*, true>* contourList, | |
| 25 const SkTDArray<SkOpSegment::AlignedSpan>& aligned) { | |
| 26 int contourCount = (*contourList).count(); | |
| 27 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 28 SkOpContour* contour = (*contourList)[cTest]; | |
| 29 int count = aligned.count(); | |
| 30 for (int index = 0; index < count; ++index) { | |
| 31 contour->alignCoincidence(aligned[index]); | |
| 32 } | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, S
kOpSegment** currentPtr, | |
| 37 int* indexPtr, int* endIndexPtr, double* bestHit,
SkScalar* bestDx, | |
| 38 bool* tryAgain, double* midPtr, bool opp) { | |
| 39 const int index = *indexPtr; | |
| 40 const int endIndex = *endIndexPtr; | |
| 41 const double mid = *midPtr; | 19 const double mid = *midPtr; |
| 42 const SkOpSegment* current = *currentPtr; | 20 const SkOpSegment* current = *currentPtr; |
| 43 double tAtMid = current->tAtMid(index, endIndex, mid); | 21 double tAtMid = SkOpSegment::TAtMid(start, end, mid); |
| 44 SkPoint basePt = current->ptAtT(tAtMid); | 22 SkPoint basePt = current->ptAtT(tAtMid); |
| 45 int contourCount = contourList.count(); | 23 int contourCount = contourList.count(); |
| 46 SkScalar bestY = SK_ScalarMin; | 24 SkScalar bestY = SK_ScalarMin; |
| 47 SkOpSegment* bestSeg = NULL; | 25 SkOpSegment* bestSeg = NULL; |
| 48 int bestTIndex = 0; | 26 SkOpSpan* bestTSpan = NULL; |
| 49 bool bestOpp; | 27 bool bestOpp; |
| 50 bool hitSomething = false; | 28 bool hitSomething = false; |
| 51 for (int cTest = 0; cTest < contourCount; ++cTest) { | 29 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 52 SkOpContour* contour = contourList[cTest]; | 30 SkOpContour* contour = contourList[cTest]; |
| 53 bool testOpp = contour->operand() ^ current->operand() ^ opp; | 31 bool testOpp = contour->operand() ^ current->operand() ^ opp; |
| 54 if (basePt.fY < contour->bounds().fTop) { | 32 if (basePt.fY < contour->bounds().fTop) { |
| 55 continue; | 33 continue; |
| 56 } | 34 } |
| 57 if (bestY > contour->bounds().fBottom) { | 35 if (bestY > contour->bounds().fBottom) { |
| 58 continue; | 36 continue; |
| 59 } | 37 } |
| 60 int segmentCount = contour->segments().count(); | 38 SkOpSegment* testSeg = contour->first(); |
| 61 for (int test = 0; test < segmentCount; ++test) { | 39 SkASSERT(testSeg); |
| 62 SkOpSegment* testSeg = &contour->segments()[test]; | 40 do { |
| 63 SkScalar testY = bestY; | 41 SkScalar testY = bestY; |
| 64 double testHit; | 42 double testHit; |
| 65 int testTIndex = testSeg->crossedSpanY(basePt, &testY, &testHit, &hi
tSomething, tAtMid, | 43 bool vertical; |
| 66 testOpp, testSeg == current); | 44 SkOpSpan* testTSpan = testSeg->crossedSpanY(basePt, tAtMid, testOpp, |
| 67 if (testTIndex < 0) { | 45 testSeg == current, &testY, &testHit, &hitSomething, &vertic
al); |
| 68 if (testTIndex == SK_MinS32) { | 46 if (!testTSpan) { |
| 47 if (vertical) { |
| 69 hitSomething = true; | 48 hitSomething = true; |
| 70 bestSeg = NULL; | 49 bestSeg = NULL; |
| 71 goto abortContours; // vertical encountered, return and try
different point | 50 goto abortContours; // vertical encountered, return and try
different point |
| 72 } | 51 } |
| 73 continue; | 52 continue; |
| 74 } | 53 } |
| 75 if (testSeg == current && current->betweenTs(index, testHit, endInde
x)) { | 54 if (testSeg == current && SkOpSegment::BetweenTs(start, testHit, end
)) { |
| 76 double baseT = current->t(index); | 55 double baseT = start->t(); |
| 77 double endT = current->t(endIndex); | 56 double endT = end->t(); |
| 78 double newMid = (testHit - baseT) / (endT - baseT); | 57 double newMid = (testHit - baseT) / (endT - baseT); |
| 79 #if DEBUG_WINDING | 58 #if DEBUG_WINDING |
| 80 double midT = current->tAtMid(index, endIndex, mid); | 59 double midT = SkOpSegment::TAtMid(start, end, mid); |
| 81 SkPoint midXY = current->xyAtT(midT); | 60 SkPoint midXY = current->ptAtT(midT); |
| 82 double newMidT = current->tAtMid(index, endIndex, newMid); | 61 double newMidT = SkOpSegment::TAtMid(start, end, newMid); |
| 83 SkPoint newXY = current->xyAtT(newMidT); | 62 SkPoint newXY = current->ptAtT(newMidT); |
| 84 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g
(%1.9g,%1.9g)" | 63 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g
(%1.9g,%1.9g)" |
| 85 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNC
TION__, | 64 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNC
TION__, |
| 86 current->debugID(), mid, newMid, | 65 current->debugID(), mid, newMid, |
| 87 baseT, current->xAtT(index), current->yAtT(index), | 66 baseT, start->pt().fX, start->pt().fY, |
| 88 baseT + mid * (endT - baseT), midXY.fX, midXY.fY, | 67 baseT + mid * (endT - baseT), midXY.fX, midXY.fY, |
| 89 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY, | 68 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY, |
| 90 endT, current->xAtT(endIndex), current->yAtT(endIndex)); | 69 endT, end->pt().fX, end->pt().fY); |
| 91 #endif | 70 #endif |
| 92 *midPtr = newMid * 2; // calling loop with divide by 2 before c
ontinuing | 71 *midPtr = newMid * 2; // calling loop with divide by 2 before c
ontinuing |
| 93 return SK_MinS32; | 72 return SK_MinS32; |
| 94 } | 73 } |
| 95 bestSeg = testSeg; | 74 bestSeg = testSeg; |
| 96 *bestHit = testHit; | 75 *bestHit = testHit; |
| 97 bestOpp = testOpp; | 76 bestOpp = testOpp; |
| 98 bestTIndex = testTIndex; | 77 bestTSpan = testTSpan; |
| 99 bestY = testY; | 78 bestY = testY; |
| 100 } | 79 } while ((testSeg = testSeg->next())); |
| 101 } | 80 } |
| 102 abortContours: | 81 abortContours: |
| 103 int result; | 82 int result; |
| 104 if (!bestSeg) { | 83 if (!bestSeg) { |
| 105 result = hitSomething ? SK_MinS32 : 0; | 84 result = hitSomething ? SK_MinS32 : 0; |
| 106 } else { | 85 } else { |
| 107 if (bestSeg->windSum(bestTIndex) == SK_MinS32) { | 86 if (bestTSpan->windSum() == SK_MinS32) { |
| 108 *currentPtr = bestSeg; | 87 *currentPtr = bestSeg; |
| 109 *indexPtr = bestTIndex; | 88 *startPtr = bestTSpan; |
| 110 *endIndexPtr = bestSeg->nextSpan(bestTIndex, 1); | 89 *endPtr = bestTSpan->next(); |
| 111 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr
>= 0); | 90 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); |
| 112 *tryAgain = true; | 91 *tryAgain = true; |
| 113 return 0; | 92 return 0; |
| 114 } | 93 } |
| 115 result = bestSeg->windingAtT(*bestHit, bestTIndex, bestOpp, bestDx); | 94 result = bestSeg->windingAtT(*bestHit, bestTSpan, bestOpp, bestDx); |
| 116 SkASSERT(result == SK_MinS32 || *bestDx); | 95 SkASSERT(result == SK_MinS32 || *bestDx); |
| 117 } | 96 } |
| 118 double baseT = current->t(index); | 97 double baseT = (*startPtr)->t(); |
| 119 double endT = current->t(endIndex); | 98 double endT = (*endPtr)->t(); |
| 120 *bestHit = baseT + mid * (endT - baseT); | 99 *bestHit = baseT + mid * (endT - baseT); |
| 121 return result; | 100 return result; |
| 122 } | 101 } |
| 123 | 102 |
| 124 SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, i
nt* end) { | 103 SkOpSegment* FindUndone(SkTDArray<SkOpContour* >& contourList, SkOpSpanBase** st
artPtr, |
| 104 SkOpSpanBase** endPtr) { |
| 125 int contourCount = contourList.count(); | 105 int contourCount = contourList.count(); |
| 126 SkOpSegment* result; | 106 SkOpSegment* result; |
| 127 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 107 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
| 128 SkOpContour* contour = contourList[cIndex]; | 108 SkOpContour* contour = contourList[cIndex]; |
| 129 result = contour->undoneSegment(start, end); | 109 result = contour->undoneSegment(startPtr, endPtr); |
| 130 if (result) { | 110 if (result) { |
| 131 return result; | 111 return result; |
| 132 } | 112 } |
| 133 } | 113 } |
| 134 return NULL; | 114 return NULL; |
| 135 } | 115 } |
| 136 | 116 |
| 137 SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex)
{ | 117 SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr, |
| 118 SkOpSpanBase** endPtr) { |
| 138 while (chase->count()) { | 119 while (chase->count()) { |
| 139 SkOpSpan* span; | 120 SkOpSpanBase* span; |
| 140 chase->pop(&span); | 121 chase->pop(&span); |
| 141 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); | 122 SkOpSegment* segment = span->segment(); |
| 142 SkOpSegment* segment = backPtr.fOther; | 123 *startPtr = span->ptT()->next()->span(); |
| 143 *tIndex = backPtr.fOtherIndex; | |
| 144 bool sortable = true; | 124 bool sortable = true; |
| 145 bool done = true; | 125 bool done = true; |
| 146 *endIndex = -1; | 126 *endPtr = NULL; |
| 147 if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endInd
ex, &done, | 127 if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr,
&done, |
| 148 &sortable)) { | 128 &sortable)) { |
| 149 *tIndex = last->start(); | 129 if (last->unorderable()) { |
| 150 *endIndex = last->end(); | 130 continue; |
| 131 } |
| 132 *startPtr = last->start(); |
| 133 *endPtr = last->end(); |
| 151 #if TRY_ROTATE | 134 #if TRY_ROTATE |
| 152 *chase->insert(0) = span; | 135 *chase->insert(0) = span; |
| 153 #else | 136 #else |
| 154 *chase->append() = span; | 137 *chase->append() = span; |
| 155 #endif | 138 #endif |
| 156 return last->segment(); | 139 return last->segment(); |
| 157 } | 140 } |
| 158 if (done) { | 141 if (done) { |
| 159 continue; | 142 continue; |
| 160 } | 143 } |
| 161 if (!sortable) { | 144 if (!sortable) { |
| 162 continue; | 145 continue; |
| 163 } | 146 } |
| 164 // find first angle, initialize winding to computed wind sum | 147 // find first angle, initialize winding to computed wind sum |
| 165 const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex); | 148 const SkOpAngle* angle = segment->spanToAngle(*startPtr, *endPtr); |
| 166 const SkOpAngle* firstAngle; | 149 if (!angle) { |
| 167 SkDEBUGCODE(firstAngle = angle); | 150 continue; |
| 168 SkDEBUGCODE(bool loop = false); | 151 } |
| 169 int winding; | 152 const SkOpAngle* firstAngle = angle; |
| 153 bool loop = false; |
| 154 int winding = SK_MinS32; |
| 170 do { | 155 do { |
| 171 angle = angle->next(); | 156 angle = angle->next(); |
| 172 SkASSERT(angle != firstAngle || !loop); | 157 if (angle == firstAngle && loop) { |
| 173 SkDEBUGCODE(loop |= angle == firstAngle); | 158 break; // if we get here, there's no winding, loop is unorder
able |
| 159 } |
| 160 loop |= angle == firstAngle; |
| 174 segment = angle->segment(); | 161 segment = angle->segment(); |
| 175 winding = segment->windSum(angle); | 162 winding = segment->windSum(angle); |
| 176 } while (winding == SK_MinS32); | 163 } while (winding == SK_MinS32); |
| 177 int spanWinding = segment->spanSign(angle->start(), angle->end()); | 164 if (winding == SK_MinS32) { |
| 178 #if DEBUG_WINDING | 165 continue; |
| 179 SkDebugf("%s winding=%d spanWinding=%d\n", __FUNCTION__, winding, spanWi
nding); | |
| 180 #endif | |
| 181 // turn span winding into contour winding | |
| 182 if (spanWinding * winding < 0) { | |
| 183 winding += spanWinding; | |
| 184 } | 166 } |
| 185 // we care about first sign and whether wind sum indicates this | 167 int sumWinding = segment->updateWindingReverse(angle); |
| 186 // edge is inside or outside. Maybe need to pass span winding | 168 SkOpSegment* first = NULL; |
| 187 // or first winding or something into this function? | |
| 188 // advance to first undone angle, then return it and winding | |
| 189 // (to set whether edges are active or not) | |
| 190 firstAngle = angle; | 169 firstAngle = angle; |
| 191 winding -= firstAngle->segment()->spanSign(firstAngle); | |
| 192 while ((angle = angle->next()) != firstAngle) { | 170 while ((angle = angle->next()) != firstAngle) { |
| 193 segment = angle->segment(); | 171 segment = angle->segment(); |
| 194 int maxWinding = winding; | 172 SkOpSpanBase* start = angle->start(); |
| 195 winding -= segment->spanSign(angle); | 173 SkOpSpanBase* end = angle->end(); |
| 196 #if DEBUG_SORT | 174 int maxWinding; |
| 197 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__
, | 175 segment->setUpWinding(start, end, &maxWinding, &sumWinding); |
| 198 segment->debugID(), maxWinding, winding, angle->sign()); | 176 if (!segment->done(angle)) { |
| 199 #endif | 177 if (!first) { |
| 200 *tIndex = angle->start(); | 178 first = segment; |
| 201 *endIndex = angle->end(); | 179 *startPtr = start; |
| 202 int lesser = SkMin32(*tIndex, *endIndex); | 180 *endPtr = end; |
| 203 const SkOpSpan& nextSpan = segment->span(lesser); | |
| 204 if (!nextSpan.fDone) { | |
| 205 // FIXME: this be wrong? assign startWinding if edge is in | |
| 206 // same direction. If the direction is opposite, winding to | |
| 207 // assign is flipped sign or +/- 1? | |
| 208 if (SkOpSegment::UseInnerWinding(maxWinding, winding)) { | |
| 209 maxWinding = winding; | |
| 210 } | 181 } |
| 211 // allowed to do nothing | 182 // OPTIMIZATION: should this also add to the chase? |
| 212 (void) segment->markAndChaseWinding(angle, maxWinding, 0, NULL); | 183 (void) segment->markAngle(maxWinding, sumWinding, angle); |
| 213 break; | |
| 214 } | 184 } |
| 215 } | 185 } |
| 216 *chase->insert(0) = span; | 186 if (first) { |
| 217 return segment; | 187 #if TRY_ROTATE |
| 188 *chase->insert(0) = span; |
| 189 #else |
| 190 *chase->append() = span; |
| 191 #endif |
| 192 return first; |
| 193 } |
| 218 } | 194 } |
| 219 return NULL; | 195 return NULL; |
| 220 } | 196 } |
| 221 | 197 |
| 222 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | 198 #if DEBUG_ACTIVE_SPANS |
| 223 void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) { | 199 void DebugShowActiveSpans(SkTDArray<SkOpContour* >& contourList) { |
| 224 int index; | 200 int index; |
| 225 for (index = 0; index < contourList.count(); ++ index) { | 201 for (index = 0; index < contourList.count(); ++ index) { |
| 226 contourList[index]->debugShowActiveSpans(); | 202 contourList[index]->debugShowActiveSpans(); |
| 227 } | 203 } |
| 228 } | 204 } |
| 229 #endif | 205 #endif |
| 230 | 206 |
| 231 static SkOpSegment* findTopSegment(const SkTArray<SkOpContour*, true>& contourLi
st, int* index, | 207 static SkOpSegment* findTopSegment(const SkTDArray<SkOpContour* >& contourList, |
| 232 int* endIndex, SkPoint* topLeft, bool* unsortable, bool* done, bool firs
tPass) { | 208 bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkPoint* topLe
ft, |
| 209 bool* unsortable, bool* done, SkChunkAlloc* allocator) { |
| 233 SkOpSegment* result; | 210 SkOpSegment* result; |
| 234 const SkOpSegment* lastTopStart = NULL; | 211 const SkOpSegment* lastTopStart = NULL; |
| 235 int lastIndex = -1, lastEndIndex = -1; | 212 SkOpSpanBase* lastStart = NULL, * lastEnd = NULL; |
| 236 do { | 213 do { |
| 237 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; | 214 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; |
| 238 int contourCount = contourList.count(); | 215 int contourCount = contourList.count(); |
| 239 SkOpSegment* topStart = NULL; | 216 SkOpSegment* topStart = NULL; |
| 240 *done = true; | 217 *done = true; |
| 241 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 218 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
| 242 SkOpContour* contour = contourList[cIndex]; | 219 SkOpContour* contour = contourList[cIndex]; |
| 243 if (contour->done()) { | 220 if (contour->done()) { |
| 244 continue; | 221 continue; |
| 245 } | 222 } |
| 246 const SkPathOpsBounds& bounds = contour->bounds(); | 223 const SkPathOpsBounds& bounds = contour->bounds(); |
| 247 if (bounds.fBottom < topLeft->fY) { | 224 if (bounds.fBottom < topLeft->fY) { |
| 248 *done = false; | 225 *done = false; |
| 249 continue; | 226 continue; |
| 250 } | 227 } |
| 251 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) { | 228 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) { |
| 252 *done = false; | 229 *done = false; |
| 253 continue; | 230 continue; |
| 254 } | 231 } |
| 255 contour->topSortableSegment(*topLeft, &bestXY, &topStart); | 232 contour->topSortableSegment(*topLeft, &bestXY, &topStart); |
| 256 if (!contour->done()) { | 233 if (!contour->done()) { |
| 257 *done = false; | 234 *done = false; |
| 258 } | 235 } |
| 259 } | 236 } |
| 260 if (!topStart) { | 237 if (!topStart) { |
| 261 return NULL; | 238 return NULL; |
| 262 } | 239 } |
| 263 *topLeft = bestXY; | 240 *topLeft = bestXY; |
| 264 result = topStart->findTop(index, endIndex, unsortable, firstPass); | 241 result = topStart->findTop(firstPass, start, end, unsortable, allocator)
; |
| 265 if (!result) { | 242 if (!result) { |
| 266 if (lastTopStart == topStart && lastIndex == *index && lastEndIndex
== *endIndex) { | 243 if (lastTopStart == topStart && lastStart == *start && lastEnd == *e
nd) { |
| 267 *done = true; | 244 *done = true; |
| 268 return NULL; | 245 return NULL; |
| 269 } | 246 } |
| 270 lastTopStart = topStart; | 247 lastTopStart = topStart; |
| 271 lastIndex = *index; | 248 lastStart = *start; |
| 272 lastEndIndex = *endIndex; | 249 lastEnd = *end; |
| 273 } | 250 } |
| 274 } while (!result); | 251 } while (!result); |
| 275 return result; | 252 return result; |
| 276 } | 253 } |
| 277 | 254 |
| 278 static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList, | 255 static int rightAngleWinding(const SkTDArray<SkOpContour* >& contourList, |
| 279 SkOpSegment** currentPtr, int* indexPtr, int* endIndexPtr, double* tHit, | 256 SkOpSegment** currentPtr, SkOpSpanBase** start, SkOpSpanBase** end, doub
le* tHit, |
| 280 SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) { | 257 SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) { |
| 281 double test = 0.9; | 258 double test = 0.9; |
| 282 int contourWinding; | 259 int contourWinding; |
| 283 do { | 260 do { |
| 284 contourWinding = contourRangeCheckY(contourList, currentPtr, indexPtr, e
ndIndexPtr, | 261 contourWinding = contourRangeCheckY(contourList, currentPtr, start, end, |
| 285 tHit, hitDx, tryAgain, &test, opp); | 262 tHit, hitDx, tryAgain, &test, opp); |
| 286 if (contourWinding != SK_MinS32 || *tryAgain) { | 263 if (contourWinding != SK_MinS32 || *tryAgain) { |
| 287 return contourWinding; | 264 return contourWinding; |
| 288 } | 265 } |
| 289 if (*currentPtr && (*currentPtr)->isVertical()) { | 266 if (*currentPtr && (*currentPtr)->isVertical()) { |
| 290 *onlyVertical = true; | 267 *onlyVertical = true; |
| 291 return contourWinding; | 268 return contourWinding; |
| 292 } | 269 } |
| 293 test /= 2; | 270 test /= 2; |
| 294 } while (!approximately_negative(test)); | 271 } while (!approximately_negative(test)); |
| 295 SkASSERT(0); // FIXME: incomplete functionality | 272 SkASSERT(0); // FIXME: incomplete functionality |
| 296 return contourWinding; | 273 return contourWinding; |
| 297 } | 274 } |
| 298 | 275 |
| 299 static void skipVertical(const SkTArray<SkOpContour*, true>& contourList, | 276 static void skipVertical(const SkTDArray<SkOpContour* >& contourList, |
| 300 SkOpSegment** current, int* index, int* endIndex) { | 277 SkOpSegment** current, SkOpSpanBase** start, SkOpSpanBase** end) { |
| 301 if (!(*current)->isVertical(*index, *endIndex)) { | 278 if (!(*current)->isVertical(*start, *end)) { |
| 302 return; | 279 return; |
| 303 } | 280 } |
| 304 int contourCount = contourList.count(); | 281 int contourCount = contourList.count(); |
| 305 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 282 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
| 306 SkOpContour* contour = contourList[cIndex]; | 283 SkOpContour* contour = contourList[cIndex]; |
| 307 if (contour->done()) { | 284 if (contour->done()) { |
| 308 continue; | 285 continue; |
| 309 } | 286 } |
| 310 SkOpSegment* nonVertical = contour->nonVerticalSegment(index, endIndex); | 287 SkOpSegment* nonVertical = contour->nonVerticalSegment(start, end); |
| 311 if (nonVertical) { | 288 if (nonVertical) { |
| 312 *current = nonVertical; | 289 *current = nonVertical; |
| 313 return; | 290 return; |
| 314 } | 291 } |
| 315 } | 292 } |
| 316 return; | 293 return; |
| 317 } | 294 } |
| 318 | 295 |
| 319 struct SortableTop { // error if local in pre-C++11 | 296 struct SortableTop2 { // error if local in pre-C++11 |
| 320 SkOpSegment* fSegment; | 297 SkOpSpanBase* fStart; |
| 321 int fIndex; | 298 SkOpSpanBase* fEnd; |
| 322 int fEndIndex; | |
| 323 }; | 299 }; |
| 324 | 300 |
| 325 SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, | 301 SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour* >& contourList, bool f
irstPass, |
| 326 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexP
tr, | 302 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, SkOpSpanBas
e** startPtr, |
| 327 int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool*
onlyVertical, | 303 SkOpSpanBase** endPtr, SkPoint* topLeft, bool* unsortable, bool* done, b
ool* onlyVertical, |
| 328 bool firstPass) { | 304 SkChunkAlloc* allocator) { |
| 329 SkOpSegment* current = findTopSegment(contourList, indexPtr, endIndexPtr, to
pLeft, unsortable, | 305 SkOpSegment* current = findTopSegment(contourList, firstPass, startPtr, endP
tr, topLeft, |
| 330 done, firstPass); | 306 unsortable, done, allocator); |
| 331 if (!current) { | 307 if (!current) { |
| 332 return NULL; | 308 return NULL; |
| 333 } | 309 } |
| 334 const int startIndex = *indexPtr; | 310 SkOpSpanBase* start = *startPtr; |
| 335 const int endIndex = *endIndexPtr; | 311 SkOpSpanBase* end = *endPtr; |
| 312 SkASSERT(current == start->segment()); |
| 336 if (*firstContour) { | 313 if (*firstContour) { |
| 337 current->initWinding(startIndex, endIndex, angleIncludeType); | 314 current->initWinding(start, end, angleIncludeType); |
| 338 *firstContour = false; | 315 *firstContour = false; |
| 339 return current; | 316 return current; |
| 340 } | 317 } |
| 341 int minIndex = SkMin32(startIndex, endIndex); | 318 SkOpSpan* minSpan = start->starter(end); |
| 342 int sumWinding = current->windSum(minIndex); | 319 int sumWinding = minSpan->windSum(); |
| 343 if (sumWinding == SK_MinS32) { | 320 if (sumWinding == SK_MinS32) { |
| 344 int index = endIndex; | 321 SkOpSpanBase* iSpan = end; |
| 345 int oIndex = startIndex; | 322 SkOpSpanBase* oSpan = start; |
| 346 do { | 323 do { |
| 347 const SkOpSpan& span = current->span(index); | 324 bool checkFrom = oSpan->t() < iSpan->t(); |
| 348 if ((oIndex < index ? span.fFromAngle : span.fToAngle) == NULL) { | 325 if ((checkFrom ? iSpan->fromAngle() : iSpan->upCast()->toAngle()) ==
NULL) { |
| 349 current->addSimpleAngle(index); | 326 iSpan->addSimpleAngle(checkFrom, allocator); |
| 350 } | 327 } |
| 351 sumWinding = current->computeSum(oIndex, index, angleIncludeType); | 328 sumWinding = current->computeSum(oSpan, iSpan, angleIncludeType); |
| 352 SkTSwap(index, oIndex); | 329 SkTSwap(iSpan, oSpan); |
| 353 } while (sumWinding == SK_MinS32 && index == startIndex); | 330 } while (sumWinding == SK_MinS32 && iSpan == start); |
| 354 } | 331 } |
| 355 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { | 332 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { |
| 356 return current; | 333 return current; |
| 357 } | 334 } |
| 358 int contourWinding; | 335 int contourWinding; |
| 359 int oppContourWinding = 0; | 336 int oppContourWinding = 0; |
| 360 // the simple upward projection of the unresolved points hit unsortable angl
es | 337 // the simple upward projection of the unresolved points hit unsortable angl
es |
| 361 // shoot rays at right angles to the segment to find its winding, ignoring a
ngle cases | 338 // shoot rays at right angles to the segment to find its winding, ignoring a
ngle cases |
| 362 bool tryAgain; | 339 bool tryAgain; |
| 363 double tHit; | 340 double tHit; |
| 364 SkScalar hitDx = 0; | 341 SkScalar hitDx = 0; |
| 365 SkScalar hitOppDx = 0; | 342 SkScalar hitOppDx = 0; |
| 366 // keep track of subsequent returns to detect infinite loops | 343 // keep track of subsequent returns to detect infinite loops |
| 367 SkTDArray<SortableTop> sortableTops; | 344 SkTDArray<SortableTop2> sortableTops; |
| 368 do { | 345 do { |
| 369 // if current is vertical, find another candidate which is not | 346 // if current is vertical, find another candidate which is not |
| 370 // if only remaining candidates are vertical, then they can be marked do
ne | 347 // if only remaining candidates are vertical, then they can be marked do
ne |
| 371 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); | 348 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); |
| 372 skipVertical(contourList, ¤t, indexPtr, endIndexPtr); | 349 SkASSERT(current == (*startPtr)->segment()); |
| 350 skipVertical(contourList, ¤t, startPtr, endPtr); |
| 373 SkASSERT(current); // FIXME: if null, all remaining are vertical | 351 SkASSERT(current); // FIXME: if null, all remaining are vertical |
| 374 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); | 352 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); |
| 353 SkASSERT(current == (*startPtr)->segment()); |
| 375 tryAgain = false; | 354 tryAgain = false; |
| 376 contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endI
ndexPtr, &tHit, | 355 contourWinding = rightAngleWinding(contourList, ¤t, startPtr, endP
tr, &tHit, |
| 377 &hitDx, &tryAgain, onlyVertical, false); | 356 &hitDx, &tryAgain, onlyVertical, false); |
| 357 SkASSERT(current == (*startPtr)->segment()); |
| 378 if (tryAgain) { | 358 if (tryAgain) { |
| 379 bool giveUp = false; | 359 bool giveUp = false; |
| 380 int count = sortableTops.count(); | 360 int count = sortableTops.count(); |
| 381 for (int index = 0; index < count; ++index) { | 361 for (int index = 0; index < count; ++index) { |
| 382 const SortableTop& prev = sortableTops[index]; | 362 const SortableTop2& prev = sortableTops[index]; |
| 383 if (giveUp) { | 363 if (giveUp) { |
| 384 prev.fSegment->markDoneFinal(prev.fIndex); | 364 prev.fStart->segment()->markDone(prev.fStart->starter(prev.f
End)); |
| 385 } else if (prev.fSegment == current | 365 } else if (prev.fStart == *startPtr || prev.fEnd == *endPtr) { |
| 386 && (prev.fIndex == *indexPtr || prev.fEndIndex == *endIn
dexPtr)) { | |
| 387 // remaining edges are non-vertical and cannot have their wi
nding computed | 366 // remaining edges are non-vertical and cannot have their wi
nding computed |
| 388 // mark them as done and return, and hope that assembly can
fill the holes | 367 // mark them as done and return, and hope that assembly can
fill the holes |
| 389 giveUp = true; | 368 giveUp = true; |
| 390 index = -1; | 369 index = -1; |
| 391 } | 370 } |
| 392 } | 371 } |
| 393 if (giveUp) { | 372 if (giveUp) { |
| 394 *done = true; | 373 *done = true; |
| 395 return NULL; | 374 return NULL; |
| 396 } | 375 } |
| 397 } | 376 } |
| 398 SortableTop* sortableTop = sortableTops.append(); | 377 SortableTop2* sortableTop = sortableTops.append(); |
| 399 sortableTop->fSegment = current; | 378 sortableTop->fStart = *startPtr; |
| 400 sortableTop->fIndex = *indexPtr; | 379 sortableTop->fEnd = *endPtr; |
| 401 sortableTop->fEndIndex = *endIndexPtr; | |
| 402 #if DEBUG_SORT | 380 #if DEBUG_SORT |
| 403 SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=
%d vert=%d\n", | 381 SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=
%d vert=%d\n", |
| 404 __FUNCTION__, current->debugID(), *indexPtr, *endIndexPtr, tHit,
hitDx, tryAgain, | 382 __FUNCTION__, current->debugID(), (*startPtr)->debugID(), (*endP
tr)->debugID(), |
| 405 *onlyVertical); | 383 tHit, hitDx, tryAgain, *onlyVertical); |
| 406 #endif | 384 #endif |
| 407 if (*onlyVertical) { | 385 if (*onlyVertical) { |
| 408 return current; | 386 return current; |
| 409 } | 387 } |
| 410 if (tryAgain) { | 388 if (tryAgain) { |
| 411 continue; | 389 continue; |
| 412 } | 390 } |
| 413 if (angleIncludeType < SkOpAngle::kBinarySingle) { | 391 if (angleIncludeType < SkOpAngle::kBinarySingle) { |
| 414 break; | 392 break; |
| 415 } | 393 } |
| 416 oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, e
ndIndexPtr, &tHit, | 394 oppContourWinding = rightAngleWinding(contourList, ¤t, startPtr, e
ndPtr, &tHit, |
| 417 &hitOppDx, &tryAgain, NULL, true); | 395 &hitOppDx, &tryAgain, NULL, true); |
| 396 SkASSERT(current == (*startPtr)->segment()); |
| 418 } while (tryAgain); | 397 } while (tryAgain); |
| 419 bool success = current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWi
nding, hitDx, | 398 bool success = current->initWinding(*startPtr, *endPtr, tHit, contourWinding
, hitDx, |
| 420 oppContourWinding, hitOppDx); | 399 oppContourWinding, hitOppDx); |
| 421 if (current->done()) { | 400 if (current->done()) { |
| 422 return NULL; | 401 return NULL; |
| 423 } else if (!success) { // check if the span has a valid winding | 402 } else if (!success) { // check if the span has a valid winding |
| 424 int min = SkTMin(*indexPtr, *endIndexPtr); | 403 SkOpSpan* minSpan = (*startPtr)->t() < (*endPtr)->t() ? (*startPtr)->upC
ast() |
| 425 const SkOpSpan& span = current->span(min); | 404 : (*endPtr)->upCast(); |
| 426 if (span.fWindSum == SK_MinS32) { | 405 if (minSpan->windSum() == SK_MinS32) { |
| 427 return NULL; | 406 return NULL; |
| 428 } | 407 } |
| 429 } | 408 } |
| 430 return current; | 409 return current; |
| 431 } | 410 } |
| 432 | 411 |
| 433 static bool calcAngles(SkTArray<SkOpContour*, true>* contourList) { | 412 void MakeContourList(SkOpContour* contour, SkTDArray<SkOpContour* >& list, |
| 434 int contourCount = (*contourList).count(); | 413 bool evenOdd, bool oppEvenOdd) { |
| 435 for (int cTest = 0; cTest < contourCount; ++cTest) { | 414 do { |
| 436 SkOpContour* contour = (*contourList)[cTest]; | 415 if (contour->count()) { |
| 437 if (!contour->calcAngles()) { | 416 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd); |
| 438 return false; | 417 *list.append() = contour; |
| 439 } | 418 } |
| 440 } | 419 } while ((contour = contour->next())); |
| 441 return true; | 420 if (list.count() < 2) { |
| 442 } | |
| 443 | |
| 444 static void checkDuplicates(SkTArray<SkOpContour*, true>* contourList) { | |
| 445 int contourCount = (*contourList).count(); | |
| 446 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 447 SkOpContour* contour = (*contourList)[cTest]; | |
| 448 contour->checkDuplicates(); | |
| 449 } | |
| 450 } | |
| 451 | |
| 452 static bool checkEnds(SkTArray<SkOpContour*, true>* contourList) { | |
| 453 // it's hard to determine if the end of a cubic or conic nearly intersects a
nother curve. | |
| 454 // instead, look to see if the connecting curve intersected at that same end
. | |
| 455 int contourCount = (*contourList).count(); | |
| 456 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 457 SkOpContour* contour = (*contourList)[cTest]; | |
| 458 if (!contour->checkEnds()) { | |
| 459 return false; | |
| 460 } | |
| 461 } | |
| 462 return true; | |
| 463 } | |
| 464 | |
| 465 static bool checkMultiples(SkTArray<SkOpContour*, true>* contourList) { | |
| 466 bool hasMultiples = false; | |
| 467 int contourCount = (*contourList).count(); | |
| 468 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 469 SkOpContour* contour = (*contourList)[cTest]; | |
| 470 contour->checkMultiples(); | |
| 471 hasMultiples |= contour->hasMultiples(); | |
| 472 } | |
| 473 return hasMultiples; | |
| 474 } | |
| 475 | |
| 476 // A small interval of a pair of curves may collapse to lines for each, triggeri
ng coincidence | |
| 477 static void checkSmall(SkTArray<SkOpContour*, true>* contourList) { | |
| 478 int contourCount = (*contourList).count(); | |
| 479 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 480 SkOpContour* contour = (*contourList)[cTest]; | |
| 481 contour->checkSmall(); | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 // A tiny interval may indicate an undiscovered coincidence. Find and fix. | |
| 486 static void checkTiny(SkTArray<SkOpContour*, true>* contourList) { | |
| 487 int contourCount = (*contourList).count(); | |
| 488 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 489 SkOpContour* contour = (*contourList)[cTest]; | |
| 490 contour->checkTiny(); | |
| 491 } | |
| 492 } | |
| 493 | |
| 494 static void fixOtherTIndex(SkTArray<SkOpContour*, true>* contourList) { | |
| 495 int contourCount = (*contourList).count(); | |
| 496 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 497 SkOpContour* contour = (*contourList)[cTest]; | |
| 498 contour->fixOtherTIndex(); | |
| 499 } | |
| 500 } | |
| 501 | |
| 502 static void joinCoincidence(SkTArray<SkOpContour*, true>* contourList) { | |
| 503 int contourCount = (*contourList).count(); | |
| 504 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 505 SkOpContour* contour = (*contourList)[cTest]; | |
| 506 contour->joinCoincidence(); | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 static void sortAngles(SkTArray<SkOpContour*, true>* contourList) { | |
| 511 int contourCount = (*contourList).count(); | |
| 512 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 513 SkOpContour* contour = (*contourList)[cTest]; | |
| 514 contour->sortAngles(); | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 static void sortSegments(SkTArray<SkOpContour*, true>* contourList) { | |
| 519 int contourCount = (*contourList).count(); | |
| 520 for (int cTest = 0; cTest < contourCount; ++cTest) { | |
| 521 SkOpContour* contour = (*contourList)[cTest]; | |
| 522 contour->sortSegments(); | |
| 523 } | |
| 524 } | |
| 525 | |
| 526 void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, tru
e>& list, | |
| 527 bool evenOdd, bool oppEvenOdd) { | |
| 528 int count = contours.count(); | |
| 529 if (count == 0) { | |
| 530 return; | 421 return; |
| 531 } | 422 } |
| 532 for (int index = 0; index < count; ++index) { | |
| 533 SkOpContour& contour = contours[index]; | |
| 534 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd); | |
| 535 list.push_back(&contour); | |
| 536 } | |
| 537 SkTQSort<SkOpContour>(list.begin(), list.end() - 1); | 423 SkTQSort<SkOpContour>(list.begin(), list.end() - 1); |
| 538 } | 424 } |
| 539 | 425 |
| 540 class DistanceLessThan { | 426 class DistanceLessThan { |
| 541 public: | 427 public: |
| 542 DistanceLessThan(double* distances) : fDistances(distances) { } | 428 DistanceLessThan(double* distances) : fDistances(distances) { } |
| 543 double* fDistances; | 429 double* fDistances; |
| 544 bool operator()(const int one, const int two) { | 430 bool operator()(const int one, const int two) { |
| 545 return fDistances[one] < fDistances[two]; | 431 return fDistances[one] < fDistances[two]; |
| 546 } | 432 } |
| 547 }; | 433 }; |
| 548 | 434 |
| 549 /* | 435 /* |
| 550 check start and end of each contour | 436 check start and end of each contour |
| 551 if not the same, record them | 437 if not the same, record them |
| 552 match them up | 438 match them up |
| 553 connect closest | 439 connect closest |
| 554 reassemble contour pieces into new path | 440 reassemble contour pieces into new path |
| 555 */ | 441 */ |
| 556 void Assemble(const SkPathWriter& path, SkPathWriter* simple) { | 442 void Assemble(const SkPathWriter& path, SkPathWriter* simple) { |
| 443 SkOpContour contour; |
| 444 SkOpGlobalState globalState(NULL PATH_OPS_DEBUG_PARAMS(&contour)); |
| 557 #if DEBUG_PATH_CONSTRUCTION | 445 #if DEBUG_PATH_CONSTRUCTION |
| 558 SkDebugf("%s\n", __FUNCTION__); | 446 SkDebugf("%s\n", __FUNCTION__); |
| 559 #endif | 447 #endif |
| 560 SkTArray<SkOpContour> contours; | 448 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune |
| 561 SkOpEdgeBuilder builder(path, contours); | 449 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); |
| 562 builder.finish(); | 450 builder.finish(&allocator); |
| 563 int count = contours.count(); | 451 SkTDArray<const SkOpContour* > runs; // indices of partial contours |
| 564 int outer; | 452 const SkOpContour* eContour = builder.head(); |
| 565 SkTArray<int, true> runs(count); // indices of partial contours | 453 do { |
| 566 for (outer = 0; outer < count; ++outer) { | 454 if (!eContour->count()) { |
| 567 const SkOpContour& eContour = contours[outer]; | 455 continue; |
| 568 const SkPoint& eStart = eContour.start(); | 456 } |
| 569 const SkPoint& eEnd = eContour.end(); | 457 const SkPoint& eStart = eContour->start(); |
| 458 const SkPoint& eEnd = eContour->end(); |
| 570 #if DEBUG_ASSEMBLE | 459 #if DEBUG_ASSEMBLE |
| 571 SkDebugf("%s contour", __FUNCTION__); | 460 SkDebugf("%s contour", __FUNCTION__); |
| 572 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { | 461 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { |
| 573 SkDebugf("[%d]", runs.count()); | 462 SkDebugf("[%d]", runs.count()); |
| 574 } else { | 463 } else { |
| 575 SkDebugf(" "); | 464 SkDebugf(" "); |
| 576 } | 465 } |
| 577 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", | 466 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", |
| 578 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); | 467 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); |
| 579 #endif | 468 #endif |
| 580 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { | 469 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { |
| 581 eContour.toPath(simple); | 470 eContour->toPath(simple); |
| 582 continue; | 471 continue; |
| 583 } | 472 } |
| 584 runs.push_back(outer); | 473 *runs.append() = eContour; |
| 585 } | 474 } while ((eContour = eContour->next())); |
| 586 count = runs.count(); | 475 int count = runs.count(); |
| 587 if (count == 0) { | 476 if (count == 0) { |
| 588 return; | 477 return; |
| 589 } | 478 } |
| 590 SkTArray<int, true> sLink, eLink; | 479 SkTDArray<int> sLink, eLink; |
| 591 sLink.push_back_n(count); | 480 sLink.append(count); |
| 592 eLink.push_back_n(count); | 481 eLink.append(count); |
| 593 int rIndex, iIndex; | 482 int rIndex, iIndex; |
| 594 for (rIndex = 0; rIndex < count; ++rIndex) { | 483 for (rIndex = 0; rIndex < count; ++rIndex) { |
| 595 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; | 484 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; |
| 596 } | 485 } |
| 597 const int ends = count * 2; // all starts and ends | 486 const int ends = count * 2; // all starts and ends |
| 598 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) /
2 | 487 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) /
2 |
| 599 SkTArray<double, true> distances; | 488 SkTDArray<double> distances; |
| 600 distances.push_back_n(entries); | 489 distances.append(entries); |
| 601 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { | 490 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { |
| 602 outer = runs[rIndex >> 1]; | 491 const SkOpContour* oContour = runs[rIndex >> 1]; |
| 603 const SkOpContour& oContour = contours[outer]; | 492 const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start(); |
| 604 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start(); | |
| 605 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) | 493 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) |
| 606 * ends - rIndex - 1; | 494 * ends - rIndex - 1; |
| 607 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { | 495 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { |
| 608 int inner = runs[iIndex >> 1]; | 496 const SkOpContour* iContour = runs[iIndex >> 1]; |
| 609 const SkOpContour& iContour = contours[inner]; | 497 const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start(
); |
| 610 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start(); | |
| 611 double dx = iPt.fX - oPt.fX; | 498 double dx = iPt.fX - oPt.fX; |
| 612 double dy = iPt.fY - oPt.fY; | 499 double dy = iPt.fY - oPt.fY; |
| 613 double dist = dx * dx + dy * dy; | 500 double dist = dx * dx + dy * dy; |
| 614 distances[row + iIndex] = dist; // oStart distance from iStart | 501 distances[row + iIndex] = dist; // oStart distance from iStart |
| 615 } | 502 } |
| 616 } | 503 } |
| 617 SkTArray<int, true> sortedDist; | 504 SkTDArray<int> sortedDist; |
| 618 sortedDist.push_back_n(entries); | 505 sortedDist.append(entries); |
| 619 for (rIndex = 0; rIndex < entries; ++rIndex) { | 506 for (rIndex = 0; rIndex < entries; ++rIndex) { |
| 620 sortedDist[rIndex] = rIndex; | 507 sortedDist[rIndex] = rIndex; |
| 621 } | 508 } |
| 622 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(dis
tances.begin())); | 509 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(dis
tances.begin())); |
| 623 int remaining = count; // number of start/end pairs | 510 int remaining = count; // number of start/end pairs |
| 624 for (rIndex = 0; rIndex < entries; ++rIndex) { | 511 for (rIndex = 0; rIndex < entries; ++rIndex) { |
| 625 int pair = sortedDist[rIndex]; | 512 int pair = sortedDist[rIndex]; |
| 626 int row = pair / ends; | 513 int row = pair / ends; |
| 627 int col = pair - row * ends; | 514 int col = pair - row * ends; |
| 628 int thingOne = row < col ? row : ends - row - 2; | 515 int thingOne = row < col ? row : ends - row - 2; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 eIndex = eLink[sIndex]; | 558 eIndex = eLink[sIndex]; |
| 672 eLink[sIndex] = SK_MaxS32; | 559 eLink[sIndex] = SK_MaxS32; |
| 673 } | 560 } |
| 674 SkASSERT(eIndex != SK_MaxS32); | 561 SkASSERT(eIndex != SK_MaxS32); |
| 675 #if DEBUG_ASSEMBLE | 562 #if DEBUG_ASSEMBLE |
| 676 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's'
: 'e', | 563 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's'
: 'e', |
| 677 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', | 564 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', |
| 678 eIndex < 0 ? ~eIndex : eIndex); | 565 eIndex < 0 ? ~eIndex : eIndex); |
| 679 #endif | 566 #endif |
| 680 do { | 567 do { |
| 681 outer = runs[rIndex]; | 568 const SkOpContour* contour = runs[rIndex]; |
| 682 const SkOpContour& contour = contours[outer]; | |
| 683 if (first) { | 569 if (first) { |
| 684 first = false; | 570 first = false; |
| 685 const SkPoint* startPtr = &contour.start(); | 571 const SkPoint* startPtr = &contour->start(); |
| 686 simple->deferredMove(startPtr[0]); | 572 simple->deferredMove(startPtr[0]); |
| 687 } | 573 } |
| 688 if (forward) { | 574 if (forward) { |
| 689 contour.toPartialForward(simple); | 575 contour->toPartialForward(simple); |
| 690 } else { | 576 } else { |
| 691 contour.toPartialBackward(simple); | 577 contour->toPartialBackward(simple); |
| 692 } | 578 } |
| 693 #if DEBUG_ASSEMBLE | 579 #if DEBUG_ASSEMBLE |
| 694 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex
, | 580 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex
, |
| 695 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, | 581 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, |
| 696 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); | 582 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); |
| 697 #endif | 583 #endif |
| 698 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { | 584 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { |
| 699 simple->close(); | 585 simple->close(); |
| 700 break; | 586 break; |
| 701 } | 587 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 } | 621 } |
| 736 } while (rIndex < count); | 622 } while (rIndex < count); |
| 737 #if DEBUG_ASSEMBLE | 623 #if DEBUG_ASSEMBLE |
| 738 for (rIndex = 0; rIndex < count; ++rIndex) { | 624 for (rIndex = 0; rIndex < count; ++rIndex) { |
| 739 SkASSERT(sLink[rIndex] == SK_MaxS32); | 625 SkASSERT(sLink[rIndex] == SK_MaxS32); |
| 740 SkASSERT(eLink[rIndex] == SK_MaxS32); | 626 SkASSERT(eLink[rIndex] == SK_MaxS32); |
| 741 } | 627 } |
| 742 #endif | 628 #endif |
| 743 } | 629 } |
| 744 | 630 |
| 745 bool HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) { | 631 static void align(SkTDArray<SkOpContour* >* contourList) { |
| 746 #if DEBUG_SHOW_WINDING | 632 int contourCount = (*contourList).count(); |
| 747 SkOpContour::debugShowWindingValues(contourList); | 633 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 748 #endif | 634 SkOpContour* contour = (*contourList)[cTest]; |
| 749 if (!CoincidenceCheck(contourList, total)) { | 635 contour->align(); |
| 636 } |
| 637 } |
| 638 |
| 639 static void calcAngles(SkTDArray<SkOpContour* >* contourList, SkChunkAlloc* allo
cator) { |
| 640 int contourCount = (*contourList).count(); |
| 641 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 642 SkOpContour* contour = (*contourList)[cTest]; |
| 643 contour->calcAngles(allocator); |
| 644 } |
| 645 } |
| 646 |
| 647 static void missingCoincidence(SkTDArray<SkOpContour* >* contourList, |
| 648 SkOpCoincidence* coincidence, SkChunkAlloc* allocator) { |
| 649 int contourCount = (*contourList).count(); |
| 650 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 651 SkOpContour* contour = (*contourList)[cTest]; |
| 652 contour->missingCoincidence(coincidence, allocator); |
| 653 } |
| 654 } |
| 655 |
| 656 static bool moveNearby(SkTDArray<SkOpContour* >* contourList) { |
| 657 int contourCount = (*contourList).count(); |
| 658 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 659 SkOpContour* contour = (*contourList)[cTest]; |
| 660 if (!contour->moveNearby()) { |
| 661 return false; |
| 662 } |
| 663 } |
| 664 return true; |
| 665 } |
| 666 |
| 667 static void sortAngles(SkTDArray<SkOpContour* >* contourList) { |
| 668 int contourCount = (*contourList).count(); |
| 669 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 670 SkOpContour* contour = (*contourList)[cTest]; |
| 671 contour->sortAngles(); |
| 672 } |
| 673 } |
| 674 |
| 675 static void sortSegments(SkTDArray<SkOpContour* >* contourList) { |
| 676 int contourCount = (*contourList).count(); |
| 677 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 678 SkOpContour* contour = (*contourList)[cTest]; |
| 679 contour->sortSegments(); |
| 680 } |
| 681 } |
| 682 |
| 683 bool HandleCoincidence(SkTDArray<SkOpContour* >* contourList, SkOpCoincidence* c
oincidence, |
| 684 SkChunkAlloc* allocator, SkOpGlobalState* globalState) { |
| 685 // move t values and points together to eliminate small/tiny gaps |
| 686 if (!moveNearby(contourList)) { |
| 750 return false; | 687 return false; |
| 751 } | 688 } |
| 752 #if DEBUG_SHOW_WINDING | 689 align(contourList); // give all span members common values |
| 753 SkOpContour::debugShowWindingValues(contourList); | 690 #if DEBUG_VALIDATE |
| 691 globalState->setPhase(SkOpGlobalState::kIntersecting); |
| 754 #endif | 692 #endif |
| 755 fixOtherTIndex(contourList); | 693 coincidence->addMissing(allocator); |
| 756 if (!checkEnds(contourList)) { // check if connecting curve intersected at
the same end | 694 #if DEBUG_VALIDATE |
| 695 globalState->setPhase(SkOpGlobalState::kWalking); |
| 696 #endif |
| 697 coincidence->expand(); // check to see if, loosely, coincident ranges may b
e expanded |
| 698 coincidence->mark(); // mark spans of coincident segments as coincident |
| 699 missingCoincidence(contourList, coincidence, allocator); // look for coinci
dence missed earlier |
| 700 if (!coincidence->apply()) { // adjust the winding value to account for coi
ncident edges |
| 757 return false; | 701 return false; |
| 758 } | 702 } |
| 759 bool hasM = checkMultiples(contourList); // check if intersections agree on
t and point values | 703 sortSegments(contourList); |
| 760 SkTDArray<SkOpSegment::AlignedSpan> aligned; | 704 calcAngles(contourList, allocator); |
| 761 if (hasM) { | 705 sortAngles(contourList); |
| 762 alignMultiples(contourList, &aligned); // align pairs of identical poin
ts | 706 if (globalState->angleCoincidence()) { |
| 763 alignCoincidence(contourList, aligned); | 707 missingCoincidence(contourList, coincidence, allocator); |
| 708 if (!coincidence->apply()) { |
| 709 return false; |
| 710 } |
| 764 } | 711 } |
| 765 checkDuplicates(contourList); // check if spans have the same number on the
other end | 712 #if DEBUG_ACTIVE_SPANS |
| 766 checkTiny(contourList); // if pair have the same end points, mark them as p
arallel | |
| 767 checkSmall(contourList); // a pair of curves with a small span may turn int
o coincident lines | |
| 768 joinCoincidence(contourList); // join curves that connect to a coincident p
air | |
| 769 sortSegments(contourList); | |
| 770 if (!calcAngles(contourList)) { | |
| 771 return false; | |
| 772 } | |
| 773 sortAngles(contourList); | |
| 774 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | |
| 775 DebugShowActiveSpans(*contourList); | 713 DebugShowActiveSpans(*contourList); |
| 776 #endif | 714 #endif |
| 777 return true; | 715 return true; |
| 778 } | 716 } |
| OLD | NEW |