blob: 340b306d60fb84d48ee6faf74189b1ab37460537 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +00007#include "SkAddIntersections.h"
caryclark54359292015-03-26 07:52:43 -07008#include "SkOpCoincidence.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +00009#include "SkOpEdgeBuilder.h"
10#include "SkPathOpsCommon.h"
11#include "SkPathWriter.h"
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +000012#include "SkTSort.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000013
caryclarkbca19f72015-05-13 08:23:48 -070014const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windingPtr,
15 bool* sortablePtr) {
16 // find first angle, initialize winding to computed fWindSum
17 SkOpSegment* segment = start->segment();
18 const SkOpAngle* angle = segment->spanToAngle(start, end);
19 if (!angle) {
20 *windingPtr = SK_MinS32;
halcanary96fcdcc2015-08-27 07:41:13 -070021 return nullptr;
caryclarkbca19f72015-05-13 08:23:48 -070022 }
23 bool computeWinding = false;
24 const SkOpAngle* firstAngle = angle;
25 bool loop = false;
26 bool unorderable = false;
27 int winding = SK_MinS32;
28 do {
29 angle = angle->next();
30 unorderable |= angle->unorderable();
31 if ((computeWinding = unorderable || (angle == firstAngle && loop))) {
32 break; // if we get here, there's no winding, loop is unorderable
33 }
34 loop |= angle == firstAngle;
35 segment = angle->segment();
36 winding = segment->windSum(angle);
37 } while (winding == SK_MinS32);
38 // if the angle loop contains an unorderable span, the angle order may be useless
39 // directly compute the winding in this case for each span
40 if (computeWinding) {
41 firstAngle = angle;
42 winding = SK_MinS32;
43 do {
44 SkOpSpanBase* startSpan = angle->start();
45 SkOpSpanBase* endSpan = angle->end();
46 SkOpSpan* lesser = startSpan->starter(endSpan);
47 int testWinding = lesser->windSum();
48 if (testWinding == SK_MinS32) {
49 testWinding = lesser->computeWindSum();
50 }
51 if (testWinding != SK_MinS32) {
52 segment = angle->segment();
53 winding = testWinding;
54 }
55 angle = angle->next();
56 } while (angle != firstAngle);
57 }
58 *sortablePtr = !unorderable;
59 *windingPtr = winding;
60 return angle;
61}
62
caryclark624637c2015-05-11 07:21:27 -070063SkOpSegment* FindUndone(SkOpContourHead* contourList, SkOpSpanBase** startPtr,
caryclark54359292015-03-26 07:52:43 -070064 SkOpSpanBase** endPtr) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000065 SkOpSegment* result;
caryclark624637c2015-05-11 07:21:27 -070066 SkOpContour* contour = contourList;
67 do {
caryclark54359292015-03-26 07:52:43 -070068 result = contour->undoneSegment(startPtr, endPtr);
caryclark@google.com07393ca2013-04-08 11:47:37 +000069 if (result) {
70 return result;
71 }
caryclark624637c2015-05-11 07:21:27 -070072 } while ((contour = contour->next()));
halcanary96fcdcc2015-08-27 07:41:13 -070073 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +000074}
75
caryclark54359292015-03-26 07:52:43 -070076SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
77 SkOpSpanBase** endPtr) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000078 while (chase->count()) {
caryclark54359292015-03-26 07:52:43 -070079 SkOpSpanBase* span;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000080 chase->pop(&span);
caryclark54359292015-03-26 07:52:43 -070081 SkOpSegment* segment = span->segment();
82 *startPtr = span->ptT()->next()->span();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000083 bool done = true;
halcanary96fcdcc2015-08-27 07:41:13 -070084 *endPtr = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -070085 if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
caryclark54359292015-03-26 07:52:43 -070086 *startPtr = last->start();
87 *endPtr = last->end();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000088 #if TRY_ROTATE
89 *chase->insert(0) = span;
90 #else
91 *chase->append() = span;
92 #endif
caryclark@google.com07393ca2013-04-08 11:47:37 +000093 return last->segment();
94 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000095 if (done) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000096 continue;
97 }
caryclark65f55312014-11-13 06:58:52 -080098 // find first angle, initialize winding to computed wind sum
caryclarkbca19f72015-05-13 08:23:48 -070099 int winding;
100 bool sortable;
101 const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
caryclark54359292015-03-26 07:52:43 -0700102 if (winding == SK_MinS32) {
103 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000104 }
caryclarkbca19f72015-05-13 08:23:48 -0700105 int sumWinding SK_INIT_TO_AVOID_WARNING;
106 if (sortable) {
107 segment = angle->segment();
108 sumWinding = segment->updateWindingReverse(angle);
109 }
halcanary96fcdcc2015-08-27 07:41:13 -0700110 SkOpSegment* first = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -0700111 const SkOpAngle* firstAngle = angle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000112 while ((angle = angle->next()) != firstAngle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000113 segment = angle->segment();
caryclark54359292015-03-26 07:52:43 -0700114 SkOpSpanBase* start = angle->start();
115 SkOpSpanBase* end = angle->end();
djsollen2f124632016-04-29 13:53:05 -0700116 int maxWinding SK_INIT_TO_AVOID_WARNING;
caryclarkbca19f72015-05-13 08:23:48 -0700117 if (sortable) {
118 segment->setUpWinding(start, end, &maxWinding, &sumWinding);
119 }
caryclark54359292015-03-26 07:52:43 -0700120 if (!segment->done(angle)) {
caryclarkbca19f72015-05-13 08:23:48 -0700121 if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) {
caryclark54359292015-03-26 07:52:43 -0700122 first = segment;
123 *startPtr = start;
124 *endPtr = end;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000125 }
caryclark54359292015-03-26 07:52:43 -0700126 // OPTIMIZATION: should this also add to the chase?
caryclarkbca19f72015-05-13 08:23:48 -0700127 if (sortable) {
128 (void) segment->markAngle(maxWinding, sumWinding, angle);
129 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000130 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000131 }
caryclark54359292015-03-26 07:52:43 -0700132 if (first) {
133 #if TRY_ROTATE
134 *chase->insert(0) = span;
135 #else
136 *chase->append() = span;
137 #endif
138 return first;
139 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000140 }
halcanary96fcdcc2015-08-27 07:41:13 -0700141 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000142}
143
caryclark54359292015-03-26 07:52:43 -0700144#if DEBUG_ACTIVE_SPANS
caryclark624637c2015-05-11 07:21:27 -0700145void DebugShowActiveSpans(SkOpContourHead* contourList) {
146 SkOpContour* contour = contourList;
147 do {
148 contour->debugShowActiveSpans();
149 } while ((contour = contour->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000150}
151#endif
152
caryclark624637c2015-05-11 07:21:27 -0700153bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) {
154 SkTDArray<SkOpContour* > list;
155 SkOpContour* contour = *contourList;
caryclark54359292015-03-26 07:52:43 -0700156 do {
157 if (contour->count()) {
158 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
159 *list.append() = contour;
160 }
161 } while ((contour = contour->next()));
caryclark624637c2015-05-11 07:21:27 -0700162 int count = list.count();
163 if (!count) {
164 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000165 }
caryclark624637c2015-05-11 07:21:27 -0700166 if (count > 1) {
167 SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
168 }
169 contour = list[0];
170 SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour);
171 contour->globalState()->setContourHead(contourHead);
172 *contourList = contourHead;
173 for (int index = 1; index < count; ++index) {
174 SkOpContour* next = list[index];
175 contour->setNext(next);
176 contour = next;
177 }
halcanary96fcdcc2015-08-27 07:41:13 -0700178 contour->setNext(nullptr);
caryclark624637c2015-05-11 07:21:27 -0700179 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000180}
181
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +0000182class DistanceLessThan {
183public:
184 DistanceLessThan(double* distances) : fDistances(distances) { }
185 double* fDistances;
186 bool operator()(const int one, const int two) {
187 return fDistances[one] < fDistances[two];
188 }
189};
190
caryclark@google.com07393ca2013-04-08 11:47:37 +0000191 /*
192 check start and end of each contour
193 if not the same, record them
194 match them up
195 connect closest
196 reassemble contour pieces into new path
197 */
198void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
caryclark54359292015-03-26 07:52:43 -0700199 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
caryclark624637c2015-05-11 07:21:27 -0700200 SkOpContourHead contour;
caryclarkdae6b972016-06-08 04:28:19 -0700201 SkOpGlobalState globalState(nullptr, &contour SkDEBUGPARAMS(false)
202 SkDEBUGPARAMS(nullptr));
caryclark03b03ca2015-04-23 09:13:37 -0700203#if DEBUG_SHOW_TEST_NAME
204 SkDebugf("</div>\n");
205#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000206#if DEBUG_PATH_CONSTRUCTION
207 SkDebugf("%s\n", __FUNCTION__);
208#endif
caryclark54359292015-03-26 07:52:43 -0700209 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState);
210 builder.finish(&allocator);
211 SkTDArray<const SkOpContour* > runs; // indices of partial contours
212 const SkOpContour* eContour = builder.head();
213 do {
214 if (!eContour->count()) {
215 continue;
216 }
217 const SkPoint& eStart = eContour->start();
218 const SkPoint& eEnd = eContour->end();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000219#if DEBUG_ASSEMBLE
220 SkDebugf("%s contour", __FUNCTION__);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000221 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000222 SkDebugf("[%d]", runs.count());
223 } else {
224 SkDebugf(" ");
225 }
226 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
227 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
228#endif
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000229 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
caryclark54359292015-03-26 07:52:43 -0700230 eContour->toPath(simple);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000231 continue;
232 }
caryclark54359292015-03-26 07:52:43 -0700233 *runs.append() = eContour;
234 } while ((eContour = eContour->next()));
235 int count = runs.count();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000236 if (count == 0) {
237 return;
238 }
caryclark54359292015-03-26 07:52:43 -0700239 SkTDArray<int> sLink, eLink;
240 sLink.append(count);
241 eLink.append(count);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000242 int rIndex, iIndex;
243 for (rIndex = 0; rIndex < count; ++rIndex) {
244 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
245 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000246 const int ends = count * 2; // all starts and ends
247 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
caryclark54359292015-03-26 07:52:43 -0700248 SkTDArray<double> distances;
249 distances.append(entries);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000250 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
caryclark54359292015-03-26 07:52:43 -0700251 const SkOpContour* oContour = runs[rIndex >> 1];
252 const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000253 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
254 * ends - rIndex - 1;
255 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
caryclark54359292015-03-26 07:52:43 -0700256 const SkOpContour* iContour = runs[iIndex >> 1];
257 const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000258 double dx = iPt.fX - oPt.fX;
259 double dy = iPt.fY - oPt.fY;
260 double dist = dx * dx + dy * dy;
261 distances[row + iIndex] = dist; // oStart distance from iStart
262 }
263 }
caryclark54359292015-03-26 07:52:43 -0700264 SkTDArray<int> sortedDist;
265 sortedDist.append(entries);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000266 for (rIndex = 0; rIndex < entries; ++rIndex) {
267 sortedDist[rIndex] = rIndex;
268 }
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +0000269 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000270 int remaining = count; // number of start/end pairs
271 for (rIndex = 0; rIndex < entries; ++rIndex) {
272 int pair = sortedDist[rIndex];
273 int row = pair / ends;
274 int col = pair - row * ends;
275 int thingOne = row < col ? row : ends - row - 2;
276 int ndxOne = thingOne >> 1;
277 bool endOne = thingOne & 1;
278 int* linkOne = endOne ? eLink.begin() : sLink.begin();
279 if (linkOne[ndxOne] != SK_MaxS32) {
280 continue;
281 }
282 int thingTwo = row < col ? col : ends - row + col - 1;
283 int ndxTwo = thingTwo >> 1;
284 bool endTwo = thingTwo & 1;
285 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
286 if (linkTwo[ndxTwo] != SK_MaxS32) {
287 continue;
288 }
289 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
290 bool flip = endOne == endTwo;
291 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
292 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
293 if (!--remaining) {
294 break;
295 }
296 }
297 SkASSERT(!remaining);
298#if DEBUG_ASSEMBLE
299 for (rIndex = 0; rIndex < count; ++rIndex) {
300 int s = sLink[rIndex];
301 int e = eLink[rIndex];
302 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
303 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
304 }
305#endif
306 rIndex = 0;
307 do {
308 bool forward = true;
309 bool first = true;
310 int sIndex = sLink[rIndex];
311 SkASSERT(sIndex != SK_MaxS32);
312 sLink[rIndex] = SK_MaxS32;
313 int eIndex;
314 if (sIndex < 0) {
315 eIndex = sLink[~sIndex];
316 sLink[~sIndex] = SK_MaxS32;
317 } else {
318 eIndex = eLink[sIndex];
319 eLink[sIndex] = SK_MaxS32;
320 }
321 SkASSERT(eIndex != SK_MaxS32);
322#if DEBUG_ASSEMBLE
323 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
324 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
325 eIndex < 0 ? ~eIndex : eIndex);
326#endif
327 do {
caryclark54359292015-03-26 07:52:43 -0700328 const SkOpContour* contour = runs[rIndex];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000329 if (first) {
330 first = false;
caryclark54359292015-03-26 07:52:43 -0700331 const SkPoint* startPtr = &contour->start();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000332 simple->deferredMove(startPtr[0]);
333 }
334 if (forward) {
caryclark54359292015-03-26 07:52:43 -0700335 contour->toPartialForward(simple);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000336 } else {
caryclark54359292015-03-26 07:52:43 -0700337 contour->toPartialBackward(simple);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000338 }
339#if DEBUG_ASSEMBLE
340 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
341 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
342 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
343#endif
344 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
345 simple->close();
346 break;
347 }
348 if (forward) {
349 eIndex = eLink[rIndex];
350 SkASSERT(eIndex != SK_MaxS32);
351 eLink[rIndex] = SK_MaxS32;
352 if (eIndex >= 0) {
353 SkASSERT(sLink[eIndex] == rIndex);
354 sLink[eIndex] = SK_MaxS32;
355 } else {
356 SkASSERT(eLink[~eIndex] == ~rIndex);
357 eLink[~eIndex] = SK_MaxS32;
358 }
359 } else {
360 eIndex = sLink[rIndex];
361 SkASSERT(eIndex != SK_MaxS32);
362 sLink[rIndex] = SK_MaxS32;
363 if (eIndex >= 0) {
364 SkASSERT(eLink[eIndex] == rIndex);
365 eLink[eIndex] = SK_MaxS32;
366 } else {
367 SkASSERT(sLink[~eIndex] == ~rIndex);
368 sLink[~eIndex] = SK_MaxS32;
369 }
370 }
371 rIndex = eIndex;
372 if (rIndex < 0) {
373 forward ^= 1;
374 rIndex = ~rIndex;
375 }
376 } while (true);
377 for (rIndex = 0; rIndex < count; ++rIndex) {
378 if (sLink[rIndex] != SK_MaxS32) {
379 break;
380 }
381 }
382 } while (rIndex < count);
383#if DEBUG_ASSEMBLE
384 for (rIndex = 0; rIndex < count; ++rIndex) {
385 SkASSERT(sLink[rIndex] == SK_MaxS32);
386 SkASSERT(eLink[rIndex] == SK_MaxS32);
387 }
388#endif
389}
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000390
caryclark624637c2015-05-11 07:21:27 -0700391static void align(SkOpContourHead* contourList) {
392 SkOpContour* contour = contourList;
393 do {
caryclark54359292015-03-26 07:52:43 -0700394 contour->align();
caryclark624637c2015-05-11 07:21:27 -0700395 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700396}
397
caryclark27c8eb82015-07-06 11:38:33 -0700398static void addAlignIntersections(SkOpContourHead* contourList, SkChunkAlloc* allocator) {
399 SkOpContour* contour = contourList;
400 do {
401 contour->addAlignIntersections(contourList, allocator);
402 } while ((contour = contour->next()));
403}
404
caryclark624637c2015-05-11 07:21:27 -0700405static void calcAngles(SkOpContourHead* contourList, SkChunkAlloc* allocator) {
406 SkOpContour* contour = contourList;
407 do {
caryclark54359292015-03-26 07:52:43 -0700408 contour->calcAngles(allocator);
caryclark624637c2015-05-11 07:21:27 -0700409 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700410}
411
caryclarkd4349722015-07-23 12:40:22 -0700412static void findCollapsed(SkOpContourHead* contourList) {
413 SkOpContour* contour = contourList;
414 do {
415 contour->findCollapsed();
416 } while ((contour = contour->next()));
417}
418
caryclark27c8eb82015-07-06 11:38:33 -0700419static bool missingCoincidence(SkOpContourHead* contourList,
caryclark54359292015-03-26 07:52:43 -0700420 SkOpCoincidence* coincidence, SkChunkAlloc* allocator) {
caryclark624637c2015-05-11 07:21:27 -0700421 SkOpContour* contour = contourList;
caryclark27c8eb82015-07-06 11:38:33 -0700422 bool result = false;
caryclark624637c2015-05-11 07:21:27 -0700423 do {
caryclark27c8eb82015-07-06 11:38:33 -0700424 result |= contour->missingCoincidence(coincidence, allocator);
caryclark624637c2015-05-11 07:21:27 -0700425 } while ((contour = contour->next()));
caryclark27c8eb82015-07-06 11:38:33 -0700426 return result;
caryclark54359292015-03-26 07:52:43 -0700427}
428
caryclarkd78c0882016-02-24 09:03:07 -0800429static bool moveMultiples(SkOpContourHead* contourList) {
caryclark624637c2015-05-11 07:21:27 -0700430 SkOpContour* contour = contourList;
431 do {
caryclarkd78c0882016-02-24 09:03:07 -0800432 if (!contour->moveMultiples()) {
433 return false;
434 }
caryclark624637c2015-05-11 07:21:27 -0700435 } while ((contour = contour->next()));
caryclarkd78c0882016-02-24 09:03:07 -0800436 return true;
caryclark08bc8482015-04-24 09:08:57 -0700437}
438
caryclark624637c2015-05-11 07:21:27 -0700439static void moveNearby(SkOpContourHead* contourList) {
440 SkOpContour* contour = contourList;
441 do {
caryclark08bc8482015-04-24 09:08:57 -0700442 contour->moveNearby();
caryclark624637c2015-05-11 07:21:27 -0700443 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700444}
445
caryclark624637c2015-05-11 07:21:27 -0700446static void sortAngles(SkOpContourHead* contourList) {
447 SkOpContour* contour = contourList;
448 do {
caryclark54359292015-03-26 07:52:43 -0700449 contour->sortAngles();
caryclark624637c2015-05-11 07:21:27 -0700450 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700451}
452
caryclark624637c2015-05-11 07:21:27 -0700453bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence,
454 SkChunkAlloc* allocator) {
455 SkOpGlobalState* globalState = contourList->globalState();
caryclark08bc8482015-04-24 09:08:57 -0700456 // combine t values when multiple intersections occur on some segments but not others
caryclark26ad22a2015-10-16 09:03:38 -0700457 DEBUG_COINCIDENCE_HEALTH(contourList, "start");
caryclarkd78c0882016-02-24 09:03:07 -0800458 if (!moveMultiples(contourList)) {
459 return false;
460 }
caryclark26ad22a2015-10-16 09:03:38 -0700461 DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples");
caryclarkd4349722015-07-23 12:40:22 -0700462 findCollapsed(contourList);
caryclark26ad22a2015-10-16 09:03:38 -0700463 DEBUG_COINCIDENCE_HEALTH(contourList, "findCollapsed");
caryclark54359292015-03-26 07:52:43 -0700464 // move t values and points together to eliminate small/tiny gaps
caryclark08bc8482015-04-24 09:08:57 -0700465 moveNearby(contourList);
caryclark26ad22a2015-10-16 09:03:38 -0700466 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
caryclark54359292015-03-26 07:52:43 -0700467 align(contourList); // give all span members common values
caryclark26ad22a2015-10-16 09:03:38 -0700468 DEBUG_COINCIDENCE_HEALTH(contourList, "align");
caryclark27c8eb82015-07-06 11:38:33 -0700469 coincidence->fixAligned(); // aligning may have marked a coincidence pt-t deleted
caryclark26ad22a2015-10-16 09:03:38 -0700470 DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned");
caryclark54359292015-03-26 07:52:43 -0700471#if DEBUG_VALIDATE
472 globalState->setPhase(SkOpGlobalState::kIntersecting);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000473#endif
caryclark27c8eb82015-07-06 11:38:33 -0700474 // look for intersections on line segments formed by moving end points
475 addAlignIntersections(contourList, allocator);
caryclark26ad22a2015-10-16 09:03:38 -0700476 DEBUG_COINCIDENCE_HEALTH(contourList, "addAlignIntersections");
477 if (coincidence->addMissing(allocator)) {
478 DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing");
479 moveNearby(contourList);
480 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2");
481 align(contourList); // give all span members common values
482 DEBUG_COINCIDENCE_HEALTH(contourList, "align2");
483 coincidence->fixAligned(); // aligning may have marked a coincidence pt-t deleted
484 DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned2");
485 }
caryclark54359292015-03-26 07:52:43 -0700486#if DEBUG_VALIDATE
487 globalState->setPhase(SkOpGlobalState::kWalking);
488#endif
caryclark27c8eb82015-07-06 11:38:33 -0700489 // check to see if, loosely, coincident ranges may be expanded
490 if (coincidence->expand()) {
caryclark26ad22a2015-10-16 09:03:38 -0700491 DEBUG_COINCIDENCE_HEALTH(contourList, "expand1");
492 if (!coincidence->addExpanded(allocator PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState))) {
493 return false;
494 }
caryclark65f55312014-11-13 06:58:52 -0800495 }
caryclark26ad22a2015-10-16 09:03:38 -0700496 DEBUG_COINCIDENCE_HEALTH(contourList, "expand2");
caryclark27c8eb82015-07-06 11:38:33 -0700497 // the expanded ranges may not align -- add the missing spans
caryclark5c5cfe22016-04-05 07:28:48 -0700498 if (!coincidence->mark()) { // mark spans of coincident segments as coincident
499 return false;
500 }
caryclark26ad22a2015-10-16 09:03:38 -0700501 DEBUG_COINCIDENCE_HEALTH(contourList, "mark1");
caryclark27c8eb82015-07-06 11:38:33 -0700502 // look for coincidence missed earlier
503 if (missingCoincidence(contourList, coincidence, allocator)) {
caryclark26ad22a2015-10-16 09:03:38 -0700504 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence1");
caryclark27c8eb82015-07-06 11:38:33 -0700505 (void) coincidence->expand();
caryclark26ad22a2015-10-16 09:03:38 -0700506 DEBUG_COINCIDENCE_HEALTH(contourList, "expand3");
507 if (!coincidence->addExpanded(allocator PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState))) {
508 return false;
509 }
510 DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded2");
caryclark27c8eb82015-07-06 11:38:33 -0700511 coincidence->mark();
512 }
caryclark26ad22a2015-10-16 09:03:38 -0700513 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence2");
caryclark27c8eb82015-07-06 11:38:33 -0700514 SkOpCoincidence overlaps;
515 do {
516 SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
517 if (!pairs->apply()) { // adjust the winding value to account for coincident edges
518 return false;
519 }
caryclark26ad22a2015-10-16 09:03:38 -0700520 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply");
caryclark27c8eb82015-07-06 11:38:33 -0700521 // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
522 // are different, construct a new pair to resolve their mutual span
523 pairs->findOverlaps(&overlaps, allocator);
caryclark26ad22a2015-10-16 09:03:38 -0700524 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps");
caryclark27c8eb82015-07-06 11:38:33 -0700525 } while (!overlaps.isEmpty());
caryclark54359292015-03-26 07:52:43 -0700526 calcAngles(contourList, allocator);
reed0dc4dd62015-03-24 13:55:33 -0700527 sortAngles(contourList);
caryclark54359292015-03-26 07:52:43 -0700528 if (globalState->angleCoincidence()) {
caryclark27c8eb82015-07-06 11:38:33 -0700529 (void) missingCoincidence(contourList, coincidence, allocator);
caryclark54359292015-03-26 07:52:43 -0700530 if (!coincidence->apply()) {
531 return false;
532 }
533 }
534#if DEBUG_ACTIVE_SPANS
caryclark624637c2015-05-11 07:21:27 -0700535 coincidence->debugShowCoincidence();
536 DebugShowActiveSpans(contourList);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000537#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000538 return true;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000539}