Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: src/pathops/SkPathOpsCommon.cpp

Issue 1037573004: cumulative pathops patch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix pathopsinverse gm Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pathops/SkPathOpsCommon.h ('k') | src/pathops/SkPathOpsCubic.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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, &current, indexPtr, endIndexPtr); 349 SkASSERT(current == (*startPtr)->segment());
350 skipVertical(contourList, &current, 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, &current, indexPtr, endI ndexPtr, &tHit, 355 contourWinding = rightAngleWinding(contourList, &current, 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, &current, indexPtr, e ndIndexPtr, &tHit, 394 oppContourWinding = rightAngleWinding(contourList, &current, 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 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
444 SkOpContour contour;
445 SkOpGlobalState globalState(NULL PATH_OPS_DEBUG_PARAMS(&contour));
557 #if DEBUG_PATH_CONSTRUCTION 446 #if DEBUG_PATH_CONSTRUCTION
558 SkDebugf("%s\n", __FUNCTION__); 447 SkDebugf("%s\n", __FUNCTION__);
559 #endif 448 #endif
560 SkTArray<SkOpContour> contours; 449 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState);
561 SkOpEdgeBuilder builder(path, contours); 450 builder.finish(&allocator);
562 builder.finish(); 451 SkTDArray<const SkOpContour* > runs; // indices of partial contours
563 int count = contours.count(); 452 const SkOpContour* eContour = builder.head();
564 int outer; 453 do {
565 SkTArray<int, true> runs(count); // indices of partial contours 454 if (!eContour->count()) {
566 for (outer = 0; outer < count; ++outer) { 455 continue;
567 const SkOpContour& eContour = contours[outer]; 456 }
568 const SkPoint& eStart = eContour.start(); 457 const SkPoint& eStart = eContour->start();
569 const SkPoint& eEnd = eContour.end(); 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
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
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 }
OLDNEW
« no previous file with comments | « src/pathops/SkPathOpsCommon.h ('k') | src/pathops/SkPathOpsCubic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698