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