| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 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 |  */ | 
| skia.committer@gmail.com | b0a327e | 2012-11-21 02:02:25 +0000 | [diff] [blame^] | 7 |  | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 8 | #include "Simplify.h" | 
 | 9 |  | 
 | 10 | namespace Op { | 
 | 11 |  | 
| caryclark@google.com | 7ba591e | 2012-11-20 14:21:54 +0000 | [diff] [blame] | 12 | #define INCLUDED_BY_SHAPE_OPS 1 | 
 | 13 |  | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 14 | #include "Simplify.cpp" | 
 | 15 |  | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 16 | // FIXME: this and find chase should be merge together, along with | 
 | 17 | // other code that walks winding in angles | 
 | 18 | // OPTIMIZATION: Probably, the walked winding should be rolled into the angle structure | 
 | 19 | // so it isn't duplicated by walkers like this one | 
 | 20 | static Segment* findChaseOp(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) { | 
 | 21 |     while (chase.count()) { | 
 | 22 |         Span* span; | 
 | 23 |         chase.pop(&span); | 
 | 24 |         const Span& backPtr = span->fOther->span(span->fOtherIndex); | 
 | 25 |         Segment* segment = backPtr.fOther; | 
 | 26 |         tIndex = backPtr.fOtherIndex; | 
 | 27 |         SkTDArray<Angle> angles; | 
 | 28 |         int done = 0; | 
 | 29 |         if (segment->activeAngle(tIndex, done, angles)) { | 
 | 30 |             Angle* last = angles.end() - 1; | 
 | 31 |             tIndex = last->start(); | 
 | 32 |             endIndex = last->end(); | 
 | 33 |    #if TRY_ROTATE | 
 | 34 |             *chase.insert(0) = span; | 
 | 35 |    #else | 
 | 36 |             *chase.append() = span; | 
 | 37 |    #endif | 
 | 38 |             return last->segment(); | 
 | 39 |         } | 
 | 40 |         if (done == angles.count()) { | 
 | 41 |             continue; | 
 | 42 |         } | 
 | 43 |         SkTDArray<Angle*> sorted; | 
 | 44 |         bool sortable = Segment::SortAngles(angles, sorted); | 
 | 45 | #if DEBUG_SORT | 
 | 46 |         sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0); | 
 | 47 | #endif | 
 | 48 |         if (!sortable) { | 
 | 49 |             continue; | 
 | 50 |         } | 
 | 51 |         // find first angle, initialize winding to computed fWindSum | 
 | 52 |         int firstIndex = -1; | 
 | 53 |         const Angle* angle; | 
 | 54 |         int winding; | 
 | 55 |         do { | 
 | 56 |             angle = sorted[++firstIndex]; | 
 | 57 |             segment = angle->segment(); | 
 | 58 |             winding = segment->windSum(angle); | 
 | 59 |         } while (winding == SK_MinS32); | 
 | 60 |         int spanWinding = segment->spanSign(angle->start(), angle->end()); | 
 | 61 |     #if DEBUG_WINDING | 
 | 62 |         SkDebugf("%s winding=%d spanWinding=%d\n", | 
 | 63 |                 __FUNCTION__, winding, spanWinding); | 
 | 64 |     #endif | 
 | 65 |         // turn span winding into contour winding | 
 | 66 |         if (spanWinding * winding < 0) { | 
 | 67 |             winding += spanWinding; | 
 | 68 |         } | 
 | 69 |         // we care about first sign and whether wind sum indicates this | 
 | 70 |         // edge is inside or outside. Maybe need to pass span winding | 
 | 71 |         // or first winding or something into this function? | 
 | 72 |         // advance to first undone angle, then return it and winding | 
 | 73 |         // (to set whether edges are active or not) | 
 | 74 |         int nextIndex = firstIndex + 1; | 
 | 75 |         int angleCount = sorted.count(); | 
 | 76 |         int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | 
 | 77 |         angle = sorted[firstIndex]; | 
 | 78 |         segment = angle->segment(); | 
 | 79 |         int oWinding = segment->oppSum(angle); | 
 | 80 |     #if DEBUG_SORT | 
 | 81 |         segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding); | 
 | 82 |     #endif | 
 | 83 |         winding -= segment->spanSign(angle); | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 84 |         oWinding -= segment->oppSign(angle); | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 85 |         bool firstOperand = segment->operand(); | 
 | 86 |         do { | 
 | 87 |             SkASSERT(nextIndex != firstIndex); | 
 | 88 |             if (nextIndex == angleCount) { | 
 | 89 |                 nextIndex = 0; | 
 | 90 |             } | 
 | 91 |             angle = sorted[nextIndex]; | 
 | 92 |             segment = angle->segment(); | 
 | 93 |             int deltaSum = segment->spanSign(angle); | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 94 |             int deltaOppSum = segment->oppSign(angle); | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 95 |             bool angleIsOp = segment->operand() ^ firstOperand; | 
 | 96 |             int maxWinding; | 
 | 97 |             if (angleIsOp) { | 
 | 98 |                 maxWinding = oWinding; | 
 | 99 |                 oWinding -= deltaSum; | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 100 |                 winding -= deltaOppSum; | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 101 |             } else { | 
 | 102 |                 maxWinding = winding; | 
 | 103 |                 winding -= deltaSum; | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 104 |                 oWinding -= deltaOppSum; | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 105 |             } | 
 | 106 |     #if DEBUG_SORT | 
 | 107 |             SkDebugf("%s id=%d maxWinding=%d winding=%d oWinding=%d sign=%d\n", __FUNCTION__, | 
 | 108 |                     segment->debugID(), maxWinding, winding, oWinding, angle->sign()); | 
 | 109 |     #endif | 
 | 110 |             tIndex = angle->start(); | 
 | 111 |             endIndex = angle->end(); | 
 | 112 |             int lesser = SkMin32(tIndex, endIndex); | 
 | 113 |             const Span& nextSpan = segment->span(lesser); | 
 | 114 |             if (!nextSpan.fDone) { | 
 | 115 |                 if (angleIsOp) { | 
 | 116 |                     SkTSwap(winding, oWinding); | 
 | 117 |                 } | 
 | 118 |                 if (useInnerWinding(maxWinding, winding)) { | 
 | 119 |                     maxWinding = winding; | 
 | 120 |                 } | 
 | 121 |                 segment->markWinding(lesser, maxWinding, oWinding); | 
 | 122 |                 break; | 
 | 123 |             } | 
 | 124 |         } while (++nextIndex != lastIndex); | 
 | 125 |    #if TRY_ROTATE | 
 | 126 |         *chase.insert(0) = span; | 
 | 127 |    #else | 
 | 128 |         *chase.append() = span; | 
 | 129 |    #endif | 
 | 130 |         return segment; | 
 | 131 |     } | 
 | 132 |     return NULL; | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 133 | } | 
 | 134 |  | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 135 | static bool windingIsActive(int winding, int oppWinding, int spanWinding, int oppSpanWinding, | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 136 |         bool windingIsOp, ShapeOp op) { | 
 | 137 |     bool active = windingIsActive(winding, spanWinding); | 
 | 138 |     if (!active) { | 
 | 139 |         return false; | 
 | 140 |     } | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 141 |     if (oppSpanWinding && windingIsActive(oppWinding, oppSpanWinding)) { | 
 | 142 |         return op == kIntersect_Op || op == kUnion_Op; | 
 | 143 |     } | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 144 |     bool opActive = oppWinding != 0; | 
 | 145 |     return gOpLookup[op][opActive][windingIsOp]; | 
 | 146 | } | 
 | 147 |  | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 148 | static int updateWindings(const Segment* current, int index, int endIndex, | 
 | 149 |         int& spanWinding, int& oppWinding, int& oppSpanWinding) { | 
 | 150 |     int winding = updateWindings(current, index, endIndex, spanWinding); | 
 | 151 |     int lesser = SkMin32(index, endIndex); | 
 | 152 |     oppWinding = current->oppSum(lesser); | 
 | 153 |     oppSpanWinding = current->oppSign(index, endIndex); | 
 | 154 |     if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) { | 
 | 155 |         oppWinding -= oppSpanWinding; | 
 | 156 |     } | 
 | 157 |     return winding; | 
 | 158 | } | 
 | 159 |  | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 160 | static bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op, | 
| caryclark@google.com | f839c03 | 2012-10-26 21:03:50 +0000 | [diff] [blame] | 161 |         const int aXorMask, const int bXorMask, PathWrapper& simple) { | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 162 |     bool firstContour = true; | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 163 |     bool unsortable = false; | 
 | 164 |     bool closable = true; | 
| caryclark@google.com | f839c03 | 2012-10-26 21:03:50 +0000 | [diff] [blame] | 165 |     SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 166 |     do { | 
| caryclark@google.com | fb51afb | 2012-10-19 15:54:16 +0000 | [diff] [blame] | 167 |         int index, endIndex; | 
| caryclark@google.com | f839c03 | 2012-10-26 21:03:50 +0000 | [diff] [blame] | 168 |         Segment* current = findSortableTop(contourList, index, endIndex, topLeft); | 
| caryclark@google.com | fb51afb | 2012-10-19 15:54:16 +0000 | [diff] [blame] | 169 |         if (!current) { | 
 | 170 |             break; | 
 | 171 |         } | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 172 |         int contourWinding, oppContourWinding; | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 173 |         if (firstContour) { | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 174 |             contourWinding = oppContourWinding = 0; | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 175 |             firstContour = false; | 
 | 176 |         } else { | 
| caryclark@google.com | 6ec1526 | 2012-11-16 20:16:50 +0000 | [diff] [blame] | 177 |             int minIndex = SkMin32(index, endIndex); | 
 | 178 |             int sumWinding = current->windSum(minIndex); | 
 | 179 |             int oppSumWinding = current->oppSum(minIndex); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 180 |             // FIXME: don't I have to adjust windSum to get contourWinding? | 
 | 181 |             if (sumWinding == SK_MinS32) { | 
| caryclark@google.com | 6ec1526 | 2012-11-16 20:16:50 +0000 | [diff] [blame] | 182 |                 sumWinding = current->computeSum(index, endIndex, &oppSumWinding); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 183 |             } | 
 | 184 |             if (sumWinding == SK_MinS32) { | 
 | 185 |                 contourWinding = innerContourCheck(contourList, current, | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 186 |                         index, endIndex, false); | 
 | 187 |                 oppContourWinding = innerContourCheck(contourList, current, | 
 | 188 |                         index, endIndex, true); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 189 |             } else { | 
| caryclark@google.com | 6ec1526 | 2012-11-16 20:16:50 +0000 | [diff] [blame] | 190 |                 int spanWinding, oppWinding; | 
| caryclark@google.com | 7ba591e | 2012-11-20 14:21:54 +0000 | [diff] [blame] | 191 |                 contourWinding = updateWindings(current, index, endIndex, spanWinding, | 
 | 192 |                         oppContourWinding, oppWinding); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 193 | #if DEBUG_WINDING | 
| caryclark@google.com | 6ec1526 | 2012-11-16 20:16:50 +0000 | [diff] [blame] | 194 |                 SkDebugf("%s contourWinding=%d oppContourWinding=%d spanWinding=%d oppWinding=%d\n", | 
 | 195 |                         __FUNCTION__, contourWinding, oppContourWinding, spanWinding, oppWinding); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 196 | #endif | 
 | 197 |             } | 
 | 198 | #if DEBUG_WINDING | 
 | 199 |          //   SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding)); | 
 | 200 |             SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding); | 
 | 201 | #endif | 
 | 202 |         } | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 203 |         int winding = contourWinding; | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 204 |         int oppWinding = oppContourWinding; | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 205 |         int spanWinding = current->spanSign(index, endIndex); | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 206 |         int oppSpanWinding = current->oppSign(index, endIndex); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 207 |         SkTDArray<Span*> chaseArray; | 
 | 208 |         do { | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 209 |             bool active = windingIsActive(winding, oppWinding, spanWinding, oppSpanWinding, | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 210 |                     current->operand(), op); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 211 |         #if DEBUG_WINDING | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 212 |             SkDebugf("%s active=%s winding=%d oppWinding=%d spanWinding=%d oppSpanWinding=%d\n", | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 213 |                     __FUNCTION__, active ? "true" : "false", | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 214 |                     winding, oppWinding, spanWinding, oppSpanWinding); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 215 |         #endif | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 216 |             do { | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 217 |         #if DEBUG_ACTIVE_SPANS | 
 | 218 |                 if (!unsortable && current->done()) { | 
 | 219 |                     debugShowActiveSpans(contourList); | 
 | 220 |                 } | 
 | 221 |         #endif | 
 | 222 |                 SkASSERT(unsortable || !current->done()); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 223 |                 int nextStart = index; | 
 | 224 |                 int nextEnd = endIndex; | 
 | 225 |                 Segment* next = current->findNextOp(chaseArray, active, | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 226 |                         nextStart, nextEnd, winding, oppWinding, spanWinding, oppSpanWinding, | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 227 |                         unsortable, op, aXorMask, bXorMask); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 228 |                 if (!next) { | 
| caryclark@google.com | c91dfe4 | 2012-10-16 12:06:27 +0000 | [diff] [blame] | 229 |                     SkASSERT(!unsortable); | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 230 |                     if (active && !unsortable && simple.hasMove() | 
| caryclark@google.com | f839c03 | 2012-10-26 21:03:50 +0000 | [diff] [blame] | 231 |                             && current->verb() != SkPath::kLine_Verb | 
 | 232 |                             && !simple.isClosed()) { | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 233 |                         current->addCurveTo(index, endIndex, simple, true); | 
| caryclark@google.com | f839c03 | 2012-10-26 21:03:50 +0000 | [diff] [blame] | 234 |                         SkASSERT(simple.isClosed()); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 235 |                     } | 
 | 236 |                     break; | 
 | 237 |                 } | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 238 |                 current->addCurveTo(index, endIndex, simple, active); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 239 |                 current = next; | 
 | 240 |                 index = nextStart; | 
 | 241 |                 endIndex = nextEnd; | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 242 |             } while (!simple.isClosed() | 
 | 243 |                     && ((active && !unsortable) || !current->done())); | 
 | 244 |             if (active) { | 
 | 245 |                 if (!simple.isClosed()) { | 
 | 246 |                     SkASSERT(unsortable); | 
 | 247 |                     int min = SkMin32(index, endIndex); | 
 | 248 |                     if (!current->done(min)) { | 
 | 249 |                         current->addCurveTo(index, endIndex, simple, true); | 
 | 250 |                         current->markDone(SkMin32(index, endIndex), winding ? winding : spanWinding); | 
 | 251 |                     } | 
 | 252 |                     closable = false; | 
 | 253 |                 } | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 254 |                 simple.close(); | 
 | 255 |             } | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 256 |             current = findChaseOp(chaseArray, index, endIndex); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 257 |         #if DEBUG_ACTIVE_SPANS | 
 | 258 |             debugShowActiveSpans(contourList); | 
 | 259 |         #endif | 
 | 260 |             if (!current) { | 
 | 261 |                 break; | 
 | 262 |             } | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 263 |             winding = updateWindings(current, index, endIndex, spanWinding, oppWinding, | 
 | 264 |                     oppSpanWinding); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 265 |         } while (true); | 
 | 266 |     } while (true); | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 267 |     return closable; | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 268 | } | 
 | 269 |  | 
 | 270 | } // end of Op namespace | 
 | 271 |  | 
 | 272 |  | 
 | 273 | void operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) { | 
 | 274 |     result.reset(); | 
 | 275 |     result.setFillType(SkPath::kEvenOdd_FillType); | 
 | 276 |     // turn path into list of segments | 
 | 277 |     SkTArray<Op::Contour> contours; | 
 | 278 |     // FIXME: add self-intersecting cubics' T values to segment | 
 | 279 |     Op::EdgeBuilder builder(one, contours); | 
 | 280 |     const int aXorMask = builder.xorMask(); | 
 | 281 |     builder.addOperand(two); | 
 | 282 |     const int bXorMask = builder.xorMask(); | 
 | 283 |     builder.finish(); | 
 | 284 |     SkTDArray<Op::Contour*> contourList; | 
 | 285 |     makeContourList(contours, contourList); | 
 | 286 |     Op::Contour** currentPtr = contourList.begin(); | 
 | 287 |     if (!currentPtr) { | 
 | 288 |         return; | 
 | 289 |     } | 
 | 290 |     Op::Contour** listEnd = contourList.end(); | 
 | 291 |     // find all intersections between segments | 
 | 292 |     do { | 
 | 293 |         Op::Contour** nextPtr = currentPtr; | 
 | 294 |         Op::Contour* current = *currentPtr++; | 
 | 295 |         Op::Contour* next; | 
 | 296 |         do { | 
 | 297 |             next = *nextPtr++; | 
 | 298 |         } while (addIntersectTs(current, next) && nextPtr != listEnd); | 
 | 299 |     } while (currentPtr != listEnd); | 
 | 300 |     // eat through coincident edges | 
| skia.committer@gmail.com | b0a327e | 2012-11-21 02:02:25 +0000 | [diff] [blame^] | 301 |  | 
| caryclark@google.com | 7ba591e | 2012-11-20 14:21:54 +0000 | [diff] [blame] | 302 |     int total = 0; | 
 | 303 |     int index; | 
 | 304 |     for (index = 0; index < contourList.count(); ++index) { | 
 | 305 |         total += contourList[index]->segments().count(); | 
 | 306 |     } | 
 | 307 | #if DEBUG_WINDING | 
 | 308 |     Op::Contour::debugShowWindingValues(contourList); | 
 | 309 | #endif | 
| caryclark@google.com | 57cff8d | 2012-11-14 21:14:56 +0000 | [diff] [blame] | 310 |     coincidenceCheck(contourList, (aXorMask == kEvenOdd_Mask) | 
| caryclark@google.com | 7ba591e | 2012-11-20 14:21:54 +0000 | [diff] [blame] | 311 |             ^ (bXorMask == kEvenOdd_Mask), total); | 
 | 312 | #if DEBUG_WINDING | 
 | 313 |     Op::Contour::debugShowWindingValues(contourList); | 
 | 314 | #endif | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 315 |     fixOtherTIndex(contourList); | 
| caryclark@google.com | 31143cf | 2012-11-09 22:14:19 +0000 | [diff] [blame] | 316 |     sortSegments(contourList); | 
 | 317 | #if DEBUG_ACTIVE_SPANS | 
 | 318 |     debugShowActiveSpans(contourList); | 
 | 319 | #endif | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 320 |     // construct closed contours | 
| caryclark@google.com | f839c03 | 2012-10-26 21:03:50 +0000 | [diff] [blame] | 321 |     Op::PathWrapper wrapper(result); | 
 | 322 |     bridgeOp(contourList, op, aXorMask, bXorMask, wrapper); | 
| caryclark@google.com | 235f56a | 2012-09-14 14:19:30 +0000 | [diff] [blame] | 323 | } |