1/*
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 */
7#include "src/pathops/SkAddIntersections.h"
8#include "src/pathops/SkOpCoincidence.h"
9#include "src/pathops/SkPathOpsBounds.h"
10
11#include <utility>
12
13#if DEBUG_ADD_INTERSECTING_TS
14
15static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt,
16                                      const SkIntersectionHelper& wn, const SkIntersections& i) {
17    SkASSERT(i.used() == pts);
18    if (!pts) {
19        SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
20                __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
21        return;
22    }
23    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
24            i[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
25    if (pts == 2) {
26        SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i[0][1], PT_DEBUG_DATA(i, 1));
27    }
28    SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
29    if (pts == 2) {
30        SkDebugf(" " T_DEBUG_STR(wnTs, 1), i[1][1]);
31    }
32    SkDebugf("\n");
33}
34
35static void debugShowQuadLineIntersection(int pts, const SkIntersectionHelper& wt,
36                                          const SkIntersectionHelper& wn,
37                                          const SkIntersections& i) {
38    SkASSERT(i.used() == pts);
39    if (!pts) {
40        SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
41                __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
42        return;
43    }
44    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
45            i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
46    for (int n = 1; n < pts; ++n) {
47        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
48    }
49    SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
50    for (int n = 1; n < pts; ++n) {
51        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
52    }
53    SkDebugf("\n");
54}
55
56static void debugShowQuadIntersection(int pts, const SkIntersectionHelper& wt,
57        const SkIntersectionHelper& wn, const SkIntersections& i) {
58    SkASSERT(i.used() == pts);
59    if (!pts) {
60        SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
61                __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
62        return;
63    }
64    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
65            i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
66    for (int n = 1; n < pts; ++n) {
67        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
68    }
69    SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts()));
70    for (int n = 1; n < pts; ++n) {
71        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
72    }
73    SkDebugf("\n");
74}
75
76static void debugShowConicLineIntersection(int pts, const SkIntersectionHelper& wt,
77        const SkIntersectionHelper& wn, const SkIntersections& i) {
78    SkASSERT(i.used() == pts);
79    if (!pts) {
80        SkDebugf("%s no intersect " CONIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
81                __FUNCTION__, CONIC_DEBUG_DATA(wt.pts(), wt.weight()), LINE_DEBUG_DATA(wn.pts()));
82        return;
83    }
84    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CONIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
85            i[0][0], CONIC_DEBUG_DATA(wt.pts(), wt.weight()), PT_DEBUG_DATA(i, 0));
86    for (int n = 1; n < pts; ++n) {
87        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
88    }
89    SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
90    for (int n = 1; n < pts; ++n) {
91        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
92    }
93    SkDebugf("\n");
94}
95
96static void debugShowConicQuadIntersection(int pts, const SkIntersectionHelper& wt,
97        const SkIntersectionHelper& wn, const SkIntersections& i) {
98    SkASSERT(i.used() == pts);
99    if (!pts) {
100        SkDebugf("%s no intersect " CONIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
101                __FUNCTION__, CONIC_DEBUG_DATA(wt.pts(), wt.weight()), QUAD_DEBUG_DATA(wn.pts()));
102        return;
103    }
104    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CONIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
105            i[0][0], CONIC_DEBUG_DATA(wt.pts(), wt.weight()), PT_DEBUG_DATA(i, 0));
106    for (int n = 1; n < pts; ++n) {
107        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
108    }
109    SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts()));
110    for (int n = 1; n < pts; ++n) {
111        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
112    }
113    SkDebugf("\n");
114}
115
116static void debugShowConicIntersection(int pts, const SkIntersectionHelper& wt,
117        const SkIntersectionHelper& wn, const SkIntersections& i) {
118    SkASSERT(i.used() == pts);
119    if (!pts) {
120        SkDebugf("%s no intersect " CONIC_DEBUG_STR " " CONIC_DEBUG_STR "\n",
121                __FUNCTION__, CONIC_DEBUG_DATA(wt.pts(), wt.weight()),
122                CONIC_DEBUG_DATA(wn.pts(), wn.weight()));
123        return;
124    }
125    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CONIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
126            i[0][0], CONIC_DEBUG_DATA(wt.pts(), wt.weight()), PT_DEBUG_DATA(i, 0));
127    for (int n = 1; n < pts; ++n) {
128        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
129    }
130    SkDebugf(" wnTs[0]=%g " CONIC_DEBUG_STR, i[1][0], CONIC_DEBUG_DATA(wn.pts(), wn.weight()));
131    for (int n = 1; n < pts; ++n) {
132        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
133    }
134    SkDebugf("\n");
135}
136
137static void debugShowCubicLineIntersection(int pts, const SkIntersectionHelper& wt,
138        const SkIntersectionHelper& wn, const SkIntersections& i) {
139    SkASSERT(i.used() == pts);
140    if (!pts) {
141        SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
142                __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
143        return;
144    }
145    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
146            i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
147    for (int n = 1; n < pts; ++n) {
148        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
149    }
150    SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
151    for (int n = 1; n < pts; ++n) {
152        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
153    }
154    SkDebugf("\n");
155}
156
157static void debugShowCubicQuadIntersection(int pts, const SkIntersectionHelper& wt,
158        const SkIntersectionHelper& wn, const SkIntersections& i) {
159    SkASSERT(i.used() == pts);
160    if (!pts) {
161        SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
162                __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
163        return;
164    }
165    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
166            i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
167    for (int n = 1; n < pts; ++n) {
168        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
169    }
170    SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts()));
171    for (int n = 1; n < pts; ++n) {
172        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
173    }
174    SkDebugf("\n");
175}
176
177static void debugShowCubicConicIntersection(int pts, const SkIntersectionHelper& wt,
178        const SkIntersectionHelper& wn, const SkIntersections& i) {
179    SkASSERT(i.used() == pts);
180    if (!pts) {
181        SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CONIC_DEBUG_STR "\n",
182                __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CONIC_DEBUG_DATA(wn.pts(), wn.weight()));
183        return;
184    }
185    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
186            i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
187    for (int n = 1; n < pts; ++n) {
188        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
189    }
190    SkDebugf(" wnTs[0]=%g " CONIC_DEBUG_STR, i[1][0], CONIC_DEBUG_DATA(wn.pts(), wn.weight()));
191    for (int n = 1; n < pts; ++n) {
192        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
193    }
194    SkDebugf("\n");
195}
196
197static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt,
198        const SkIntersectionHelper& wn, const SkIntersections& i) {
199    SkASSERT(i.used() == pts);
200    if (!pts) {
201        SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
202                __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
203        return;
204    }
205    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
206            i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
207    for (int n = 1; n < pts; ++n) {
208        SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
209    }
210    SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts()));
211    for (int n = 1; n < pts; ++n) {
212        SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
213    }
214    SkDebugf("\n");
215}
216
217#else
218static void debugShowLineIntersection(int , const SkIntersectionHelper& ,
219        const SkIntersectionHelper& , const SkIntersections& ) {
220}
221
222static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& ,
223        const SkIntersectionHelper& , const SkIntersections& ) {
224}
225
226static void debugShowQuadIntersection(int , const SkIntersectionHelper& ,
227        const SkIntersectionHelper& , const SkIntersections& ) {
228}
229
230static void debugShowConicLineIntersection(int , const SkIntersectionHelper& ,
231        const SkIntersectionHelper& , const SkIntersections& ) {
232}
233
234static void debugShowConicQuadIntersection(int , const SkIntersectionHelper& ,
235        const SkIntersectionHelper& , const SkIntersections& ) {
236}
237
238static void debugShowConicIntersection(int , const SkIntersectionHelper& ,
239        const SkIntersectionHelper& , const SkIntersections& ) {
240}
241
242static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& ,
243        const SkIntersectionHelper& , const SkIntersections& ) {
244}
245
246static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& ,
247        const SkIntersectionHelper& , const SkIntersections& ) {
248}
249
250static void debugShowCubicConicIntersection(int , const SkIntersectionHelper& ,
251        const SkIntersectionHelper& , const SkIntersections& ) {
252}
253
254static void debugShowCubicIntersection(int , const SkIntersectionHelper& ,
255        const SkIntersectionHelper& , const SkIntersections& ) {
256}
257#endif
258
259bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coincidence) {
260    if (test != next) {
261        if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) {
262            return false;
263        }
264        // OPTIMIZATION: outset contour bounds a smidgen instead?
265        if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) {
266            return true;
267        }
268    }
269    SkIntersectionHelper wt;
270    wt.init(test);
271    do {
272        SkIntersectionHelper wn;
273        wn.init(next);
274        test->debugValidate();
275        next->debugValidate();
276        if (test == next && !wn.startAfter(wt)) {
277            continue;
278        }
279        do {
280            if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) {
281                continue;
282            }
283            int pts = 0;
284            SkIntersections ts { SkDEBUGCODE(test->globalState()) };
285            bool swap = false;
286            SkDQuad quad1, quad2;
287            SkDConic conic1, conic2;
288            SkDCubic cubic1, cubic2;
289            switch (wt.segmentType()) {
290                case SkIntersectionHelper::kHorizontalLine_Segment:
291                    swap = true;
292                    switch (wn.segmentType()) {
293                        case SkIntersectionHelper::kHorizontalLine_Segment:
294                        case SkIntersectionHelper::kVerticalLine_Segment:
295                        case SkIntersectionHelper::kLine_Segment:
296                            pts = ts.lineHorizontal(wn.pts(), wt.left(),
297                                    wt.right(), wt.y(), wt.xFlipped());
298                            debugShowLineIntersection(pts, wn, wt, ts);
299                            break;
300                        case SkIntersectionHelper::kQuad_Segment:
301                            pts = ts.quadHorizontal(wn.pts(), wt.left(),
302                                    wt.right(), wt.y(), wt.xFlipped());
303                            debugShowQuadLineIntersection(pts, wn, wt, ts);
304                            break;
305                        case SkIntersectionHelper::kConic_Segment:
306                            pts = ts.conicHorizontal(wn.pts(), wn.weight(), wt.left(),
307                                    wt.right(), wt.y(), wt.xFlipped());
308                            debugShowConicLineIntersection(pts, wn, wt, ts);
309                            break;
310                        case SkIntersectionHelper::kCubic_Segment:
311                            pts = ts.cubicHorizontal(wn.pts(), wt.left(),
312                                    wt.right(), wt.y(), wt.xFlipped());
313                            debugShowCubicLineIntersection(pts, wn, wt, ts);
314                            break;
315                        default:
316                            SkASSERT(0);
317                    }
318                    break;
319                case SkIntersectionHelper::kVerticalLine_Segment:
320                    swap = true;
321                    switch (wn.segmentType()) {
322                        case SkIntersectionHelper::kHorizontalLine_Segment:
323                        case SkIntersectionHelper::kVerticalLine_Segment:
324                        case SkIntersectionHelper::kLine_Segment: {
325                            pts = ts.lineVertical(wn.pts(), wt.top(),
326                                    wt.bottom(), wt.x(), wt.yFlipped());
327                            debugShowLineIntersection(pts, wn, wt, ts);
328                            break;
329                        }
330                        case SkIntersectionHelper::kQuad_Segment: {
331                            pts = ts.quadVertical(wn.pts(), wt.top(),
332                                    wt.bottom(), wt.x(), wt.yFlipped());
333                            debugShowQuadLineIntersection(pts, wn, wt, ts);
334                            break;
335                        }
336                        case SkIntersectionHelper::kConic_Segment: {
337                            pts = ts.conicVertical(wn.pts(), wn.weight(), wt.top(),
338                                    wt.bottom(), wt.x(), wt.yFlipped());
339                            debugShowConicLineIntersection(pts, wn, wt, ts);
340                            break;
341                        }
342                        case SkIntersectionHelper::kCubic_Segment: {
343                            pts = ts.cubicVertical(wn.pts(), wt.top(),
344                                    wt.bottom(), wt.x(), wt.yFlipped());
345                            debugShowCubicLineIntersection(pts, wn, wt, ts);
346                            break;
347                        }
348                        default:
349                            SkASSERT(0);
350                    }
351                    break;
352                case SkIntersectionHelper::kLine_Segment:
353                    switch (wn.segmentType()) {
354                        case SkIntersectionHelper::kHorizontalLine_Segment:
355                            pts = ts.lineHorizontal(wt.pts(), wn.left(),
356                                    wn.right(), wn.y(), wn.xFlipped());
357                            debugShowLineIntersection(pts, wt, wn, ts);
358                            break;
359                        case SkIntersectionHelper::kVerticalLine_Segment:
360                            pts = ts.lineVertical(wt.pts(), wn.top(),
361                                    wn.bottom(), wn.x(), wn.yFlipped());
362                            debugShowLineIntersection(pts, wt, wn, ts);
363                            break;
364                        case SkIntersectionHelper::kLine_Segment:
365                            pts = ts.lineLine(wt.pts(), wn.pts());
366                            debugShowLineIntersection(pts, wt, wn, ts);
367                            break;
368                        case SkIntersectionHelper::kQuad_Segment:
369                            swap = true;
370                            pts = ts.quadLine(wn.pts(), wt.pts());
371                            debugShowQuadLineIntersection(pts, wn, wt, ts);
372                            break;
373                        case SkIntersectionHelper::kConic_Segment:
374                            swap = true;
375                            pts = ts.conicLine(wn.pts(), wn.weight(), wt.pts());
376                            debugShowConicLineIntersection(pts, wn, wt, ts);
377                            break;
378                        case SkIntersectionHelper::kCubic_Segment:
379                            swap = true;
380                            pts = ts.cubicLine(wn.pts(), wt.pts());
381                            debugShowCubicLineIntersection(pts, wn, wt, ts);
382                            break;
383                        default:
384                            SkASSERT(0);
385                    }
386                    break;
387                case SkIntersectionHelper::kQuad_Segment:
388                    switch (wn.segmentType()) {
389                        case SkIntersectionHelper::kHorizontalLine_Segment:
390                            pts = ts.quadHorizontal(wt.pts(), wn.left(),
391                                    wn.right(), wn.y(), wn.xFlipped());
392                            debugShowQuadLineIntersection(pts, wt, wn, ts);
393                            break;
394                        case SkIntersectionHelper::kVerticalLine_Segment:
395                            pts = ts.quadVertical(wt.pts(), wn.top(),
396                                    wn.bottom(), wn.x(), wn.yFlipped());
397                            debugShowQuadLineIntersection(pts, wt, wn, ts);
398                            break;
399                        case SkIntersectionHelper::kLine_Segment:
400                            pts = ts.quadLine(wt.pts(), wn.pts());
401                            debugShowQuadLineIntersection(pts, wt, wn, ts);
402                            break;
403                        case SkIntersectionHelper::kQuad_Segment: {
404                            pts = ts.intersect(quad1.set(wt.pts()), quad2.set(wn.pts()));
405                            debugShowQuadIntersection(pts, wt, wn, ts);
406                            break;
407                        }
408                        case SkIntersectionHelper::kConic_Segment: {
409                            swap = true;
410                            pts = ts.intersect(conic2.set(wn.pts(), wn.weight()),
411                                    quad1.set(wt.pts()));
412                            debugShowConicQuadIntersection(pts, wn, wt, ts);
413                            break;
414                        }
415                        case SkIntersectionHelper::kCubic_Segment: {
416                            swap = true;
417                            pts = ts.intersect(cubic2.set(wn.pts()), quad1.set(wt.pts()));
418                            debugShowCubicQuadIntersection(pts, wn, wt, ts);
419                            break;
420                        }
421                        default:
422                            SkASSERT(0);
423                    }
424                    break;
425                case SkIntersectionHelper::kConic_Segment:
426                    switch (wn.segmentType()) {
427                        case SkIntersectionHelper::kHorizontalLine_Segment:
428                            pts = ts.conicHorizontal(wt.pts(), wt.weight(), wn.left(),
429                                    wn.right(), wn.y(), wn.xFlipped());
430                            debugShowConicLineIntersection(pts, wt, wn, ts);
431                            break;
432                        case SkIntersectionHelper::kVerticalLine_Segment:
433                            pts = ts.conicVertical(wt.pts(), wt.weight(), wn.top(),
434                                    wn.bottom(), wn.x(), wn.yFlipped());
435                            debugShowConicLineIntersection(pts, wt, wn, ts);
436                            break;
437                        case SkIntersectionHelper::kLine_Segment:
438                            pts = ts.conicLine(wt.pts(), wt.weight(), wn.pts());
439                            debugShowConicLineIntersection(pts, wt, wn, ts);
440                            break;
441                        case SkIntersectionHelper::kQuad_Segment: {
442                            pts = ts.intersect(conic1.set(wt.pts(), wt.weight()),
443                                    quad2.set(wn.pts()));
444                            debugShowConicQuadIntersection(pts, wt, wn, ts);
445                            break;
446                        }
447                        case SkIntersectionHelper::kConic_Segment: {
448                            pts = ts.intersect(conic1.set(wt.pts(), wt.weight()),
449                                    conic2.set(wn.pts(), wn.weight()));
450                            debugShowConicIntersection(pts, wt, wn, ts);
451                            break;
452                        }
453                        case SkIntersectionHelper::kCubic_Segment: {
454                            swap = true;
455                            pts = ts.intersect(cubic2.set(wn.pts()
456                                    SkDEBUGPARAMS(ts.globalState())),
457                                    conic1.set(wt.pts(), wt.weight()
458                                    SkDEBUGPARAMS(ts.globalState())));
459                            debugShowCubicConicIntersection(pts, wn, wt, ts);
460                            break;
461                        }
462                    }
463                    break;
464                case SkIntersectionHelper::kCubic_Segment:
465                    switch (wn.segmentType()) {
466                        case SkIntersectionHelper::kHorizontalLine_Segment:
467                            pts = ts.cubicHorizontal(wt.pts(), wn.left(),
468                                    wn.right(), wn.y(), wn.xFlipped());
469                            debugShowCubicLineIntersection(pts, wt, wn, ts);
470                            break;
471                        case SkIntersectionHelper::kVerticalLine_Segment:
472                            pts = ts.cubicVertical(wt.pts(), wn.top(),
473                                    wn.bottom(), wn.x(), wn.yFlipped());
474                            debugShowCubicLineIntersection(pts, wt, wn, ts);
475                            break;
476                        case SkIntersectionHelper::kLine_Segment:
477                            pts = ts.cubicLine(wt.pts(), wn.pts());
478                            debugShowCubicLineIntersection(pts, wt, wn, ts);
479                            break;
480                        case SkIntersectionHelper::kQuad_Segment: {
481                            pts = ts.intersect(cubic1.set(wt.pts()), quad2.set(wn.pts()));
482                            debugShowCubicQuadIntersection(pts, wt, wn, ts);
483                            break;
484                        }
485                        case SkIntersectionHelper::kConic_Segment: {
486                            pts = ts.intersect(cubic1.set(wt.pts()
487                                    SkDEBUGPARAMS(ts.globalState())),
488                                    conic2.set(wn.pts(), wn.weight()
489                                    SkDEBUGPARAMS(ts.globalState())));
490                            debugShowCubicConicIntersection(pts, wt, wn, ts);
491                            break;
492                        }
493                        case SkIntersectionHelper::kCubic_Segment: {
494                            pts = ts.intersect(cubic1.set(wt.pts()), cubic2.set(wn.pts()));
495                            debugShowCubicIntersection(pts, wt, wn, ts);
496                            break;
497                        }
498                        default:
499                            SkASSERT(0);
500                    }
501                    break;
502                default:
503                    SkASSERT(0);
504            }
505#if DEBUG_T_SECT_LOOP_COUNT
506            test->globalState()->debugAddLoopCount(&ts, wt, wn);
507#endif
508            int coinIndex = -1;
509            SkOpPtT* coinPtT[2];
510            for (int pt = 0; pt < pts; ++pt) {
511                SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1);
512                SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1);
513                wt.segment()->debugValidate();
514                // if t value is used to compute pt in addT, error may creep in and
515                // rect intersections may result in non-rects. if pt value from intersection
516                // is passed in, current tests break. As a workaround, pass in pt
517                // value from intersection only if pt.x and pt.y is integral
518                SkPoint iPt = ts.pt(pt).asSkPoint();
519                bool iPtIsIntegral = iPt.fX == floor(iPt.fX) && iPt.fY == floor(iPt.fY);
520                SkOpPtT* testTAt = iPtIsIntegral ? wt.segment()->addT(ts[swap][pt], iPt)
521                        : wt.segment()->addT(ts[swap][pt]);
522                wn.segment()->debugValidate();
523                SkOpPtT* nextTAt = iPtIsIntegral ? wn.segment()->addT(ts[!swap][pt], iPt)
524                        : wn.segment()->addT(ts[!swap][pt]);
525                if (!testTAt->contains(nextTAt)) {
526                    SkOpPtT* oppPrev = testTAt->oppPrev(nextTAt);  //  Returns nullptr if pair
527                    if (oppPrev) {                                 //  already share a pt-t loop.
528                        testTAt->span()->mergeMatches(nextTAt->span());
529                        testTAt->addOpp(nextTAt, oppPrev);
530                    }
531                    if (testTAt->fPt != nextTAt->fPt) {
532                        testTAt->span()->unaligned();
533                        nextTAt->span()->unaligned();
534                    }
535                    wt.segment()->debugValidate();
536                    wn.segment()->debugValidate();
537                }
538                if (!ts.isCoincident(pt)) {
539                    continue;
540                }
541                if (coinIndex < 0) {
542                    coinPtT[0] = testTAt;
543                    coinPtT[1] = nextTAt;
544                    coinIndex = pt;
545                    continue;
546                }
547                if (coinPtT[0]->span() == testTAt->span()) {
548                    coinIndex = -1;
549                    continue;
550                }
551                if (coinPtT[1]->span() == nextTAt->span()) {
552                    coinIndex = -1;  // coincidence span collapsed
553                    continue;
554                }
555                if (swap) {
556                    using std::swap;
557                    swap(coinPtT[0], coinPtT[1]);
558                    swap(testTAt, nextTAt);
559                }
560                SkASSERT(coincidence->globalState()->debugSkipAssert()
561                        || coinPtT[0]->span()->t() < testTAt->span()->t());
562                if (coinPtT[0]->span()->deleted()) {
563                    coinIndex = -1;
564                    continue;
565                }
566                if (testTAt->span()->deleted()) {
567                    coinIndex = -1;
568                    continue;
569                }
570                coincidence->add(coinPtT[0], testTAt, coinPtT[1], nextTAt);
571                wt.segment()->debugValidate();
572                wn.segment()->debugValidate();
573                coinIndex = -1;
574            }
575            SkOPOBJASSERT(coincidence, coinIndex < 0);  // expect coincidence to be paired
576        } while (wn.advance());
577    } while (wt.advance());
578    return true;
579}
580