| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkAddIntersections.h" | 7 #include "SkAddIntersections.h" |
| 8 #include "SkOpCoincidence.h" |
| 8 #include "SkOpEdgeBuilder.h" | 9 #include "SkOpEdgeBuilder.h" |
| 9 #include "SkPathOpsCommon.h" | 10 #include "SkPathOpsCommon.h" |
| 10 #include "SkPathWriter.h" | 11 #include "SkPathWriter.h" |
| 11 | 12 |
| 12 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int* tIndex, int* e
ndIndex) { | 13 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase**
startPtr, |
| 14 SkOpSpanBase** endPtr) { |
| 13 while (chase.count()) { | 15 while (chase.count()) { |
| 14 SkOpSpan* span; | 16 SkOpSpanBase* span; |
| 15 chase.pop(&span); | 17 chase.pop(&span); |
| 16 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); | 18 // OPTIMIZE: prev makes this compatible with old code -- but is it neces
sary? |
| 17 SkOpSegment* segment = backPtr.fOther; | 19 *startPtr = span->ptT()->prev()->span(); |
| 18 *tIndex = backPtr.fOtherIndex; | 20 SkOpSegment* segment = (*startPtr)->segment(); |
| 19 bool sortable = true; | 21 bool sortable = true; |
| 20 bool done = true; | 22 bool done = true; |
| 21 *endIndex = -1; | 23 *endPtr = NULL; |
| 22 if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endInd
ex, &done, | 24 if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr,
&done, |
| 23 &sortable)) { | 25 &sortable)) { |
| 24 if (last->unorderable()) { | 26 if (last->unorderable()) { |
| 25 continue; | 27 continue; |
| 26 } | 28 } |
| 27 *tIndex = last->start(); | 29 *startPtr = last->start(); |
| 28 *endIndex = last->end(); | 30 *endPtr = last->end(); |
| 29 #if TRY_ROTATE | 31 #if TRY_ROTATE |
| 30 *chase.insert(0) = span; | 32 *chase.insert(0) = span; |
| 31 #else | 33 #else |
| 32 *chase.append() = span; | 34 *chase.append() = span; |
| 33 #endif | 35 #endif |
| 34 return last->segment(); | 36 return last->segment(); |
| 35 } | 37 } |
| 36 if (done) { | 38 if (done) { |
| 37 continue; | 39 continue; |
| 38 } | 40 } |
| 39 if (!sortable) { | 41 if (!sortable) { |
| 40 continue; | 42 continue; |
| 41 } | 43 } |
| 42 // find first angle, initialize winding to computed fWindSum | 44 // find first angle, initialize winding to computed fWindSum |
| 43 const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex); | 45 const SkOpAngle* angle = segment->spanToAngle(*startPtr, *endPtr); |
| 44 if (!angle) { | 46 if (!angle) { |
| 45 continue; | 47 continue; |
| 46 } | 48 } |
| 47 const SkOpAngle* firstAngle = angle; | 49 const SkOpAngle* firstAngle = angle; |
| 48 bool loop = false; | 50 bool loop = false; |
| 49 int winding = SK_MinS32; | 51 int winding = SK_MinS32; |
| 50 do { | 52 do { |
| 51 angle = angle->next(); | 53 angle = angle->next(); |
| 52 if (angle == firstAngle && loop) { | 54 if (angle == firstAngle && loop) { |
| 53 break; // if we get here, there's no winding, loop is unorder
able | 55 break; // if we get here, there's no winding, loop is unorder
able |
| 54 } | 56 } |
| 55 loop |= angle == firstAngle; | 57 loop |= angle == firstAngle; |
| 56 segment = angle->segment(); | 58 segment = angle->segment(); |
| 57 winding = segment->windSum(angle); | 59 winding = segment->windSum(angle); |
| 58 } while (winding == SK_MinS32); | 60 } while (winding == SK_MinS32); |
| 59 if (winding == SK_MinS32) { | 61 if (winding == SK_MinS32) { |
| 60 continue; | 62 continue; |
| 61 } | 63 } |
| 62 int sumMiWinding = segment->updateWindingReverse(angle); | 64 int sumMiWinding = segment->updateWindingReverse(angle); |
| 63 int sumSuWinding = segment->updateOppWindingReverse(angle); | 65 int sumSuWinding = segment->updateOppWindingReverse(angle); |
| 64 if (segment->operand()) { | 66 if (segment->operand()) { |
| 65 SkTSwap<int>(sumMiWinding, sumSuWinding); | 67 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 66 } | 68 } |
| 67 SkOpSegment* first = NULL; | 69 SkOpSegment* first = NULL; |
| 68 bool badData = false; | 70 firstAngle = angle; |
| 69 while ((angle = angle->next()) != firstAngle && !badData) { | 71 while ((angle = angle->next()) != firstAngle) { |
| 70 segment = angle->segment(); | 72 segment = angle->segment(); |
| 71 int start = angle->start(); | 73 SkOpSpanBase* start = angle->start(); |
| 72 int end = angle->end(); | 74 SkOpSpanBase* end = angle->end(); |
| 73 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; | 75 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; |
| 74 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding, | 76 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding, |
| 75 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | 77 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); |
| 76 if (!segment->done(angle)) { | 78 if (!segment->done(angle)) { |
| 77 if (!first) { | 79 if (!first) { |
| 78 first = segment; | 80 first = segment; |
| 79 *tIndex = start; | 81 *startPtr = start; |
| 80 *endIndex = end; | 82 *endPtr = end; |
| 81 } | |
| 82 if (segment->inconsistentAngle(maxWinding, sumWinding, oppMaxWin
ding, | |
| 83 oppSumWinding, angle)) { | |
| 84 badData = true; | |
| 85 break; | |
| 86 } | 83 } |
| 87 // OPTIMIZATION: should this also add to the chase? | 84 // OPTIMIZATION: should this also add to the chase? |
| 88 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, | 85 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, |
| 89 oppSumWinding, angle); | 86 oppSumWinding, angle); |
| 90 } | 87 } |
| 91 } | 88 } |
| 92 if (badData) { | |
| 93 continue; | |
| 94 } | |
| 95 if (first) { | 89 if (first) { |
| 96 #if TRY_ROTATE | 90 #if TRY_ROTATE |
| 97 *chase.insert(0) = span; | 91 *chase.insert(0) = span; |
| 98 #else | 92 #else |
| 99 *chase.append() = span; | 93 *chase.append() = span; |
| 100 #endif | 94 #endif |
| 101 return first; | 95 return first; |
| 102 } | 96 } |
| 103 } | 97 } |
| 104 return NULL; | 98 return NULL; |
| 105 } | 99 } |
| 106 | 100 |
| 107 /* | 101 static bool bridgeOp(SkTDArray<SkOpContour* >& contourList, const SkPathOp op, |
| 108 static bool windingIsActive(int winding, int oppWinding, int spanWinding, int op
pSpanWinding, | 102 const int xorMask, const int xorOpMask, SkPathWriter* simple, SkChunkAll
oc* allocator) { |
| 109 bool windingIsOp, PathOp op) { | |
| 110 bool active = windingIsActive(winding, spanWinding); | |
| 111 if (!active) { | |
| 112 return false; | |
| 113 } | |
| 114 if (oppSpanWinding && windingIsActive(oppWinding, oppSpanWinding)) { | |
| 115 switch (op) { | |
| 116 case kIntersect_Op: | |
| 117 case kUnion_Op: | |
| 118 return true; | |
| 119 case kDifference_Op: { | |
| 120 int absSpan = abs(spanWinding); | |
| 121 int absOpp = abs(oppSpanWinding); | |
| 122 return windingIsOp ? absSpan < absOpp : absSpan > absOpp; | |
| 123 } | |
| 124 case kXor_Op: | |
| 125 return spanWinding != oppSpanWinding; | |
| 126 default: | |
| 127 SkASSERT(0); | |
| 128 } | |
| 129 } | |
| 130 bool opActive = oppWinding != 0; | |
| 131 return gOpLookup[op][opActive][windingIsOp]; | |
| 132 } | |
| 133 */ | |
| 134 | |
| 135 static bool bridgeOp(SkTArray<SkOpContour*, true>& contourList, const SkPathOp o
p, | |
| 136 const int xorMask, const int xorOpMask, SkPathWriter* simple) { | |
| 137 bool firstContour = true; | 103 bool firstContour = true; |
| 138 bool unsortable = false; | 104 bool unsortable = false; |
| 139 bool topUnsortable = false; | 105 bool topUnsortable = false; |
| 140 bool firstPass = true; | 106 bool firstPass = true; |
| 141 SkPoint lastTopLeft; | 107 SkPoint lastTopLeft; |
| 142 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; | 108 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; |
| 143 do { | 109 do { |
| 144 int index, endIndex; | 110 SkOpSpanBase* start; |
| 111 SkOpSpanBase* end; |
| 145 bool topDone; | 112 bool topDone; |
| 146 bool onlyVertical = false; | 113 bool onlyVertical = false; |
| 147 lastTopLeft = topLeft; | 114 lastTopLeft = topLeft; |
| 148 SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kBinarySi
ngle, &firstContour, | 115 SkOpSegment* current = FindSortableTop(contourList, firstPass, SkOpAngle
::kBinarySingle, |
| 149 &index, &endIndex, &topLeft, &topUnsortable, &topDone, &onlyVert
ical, firstPass); | 116 &firstContour, &start, &end, &topLeft, &topUnsortable, &topDone,
&onlyVertical, |
| 117 allocator); |
| 150 if (!current) { | 118 if (!current) { |
| 151 if ((!topUnsortable || firstPass) && !topDone) { | 119 if ((!topUnsortable || firstPass) && !topDone) { |
| 152 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi
n); | 120 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi
n); |
| 153 if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_Scala
rMin) { | 121 if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_Scala
rMin) { |
| 154 if (firstPass) { | 122 if (firstPass) { |
| 155 firstPass = false; | 123 firstPass = false; |
| 156 } else { | 124 } else { |
| 157 break; | 125 break; |
| 158 } | 126 } |
| 159 } | 127 } |
| 160 topLeft.fX = topLeft.fY = SK_ScalarMin; | 128 topLeft.fX = topLeft.fY = SK_ScalarMin; |
| 161 continue; | 129 continue; |
| 162 } | 130 } |
| 163 break; | 131 break; |
| 164 } else if (onlyVertical) { | 132 } else if (onlyVertical) { |
| 165 break; | 133 break; |
| 166 } | 134 } |
| 167 firstPass = !topUnsortable || lastTopLeft != topLeft; | 135 firstPass = !topUnsortable || lastTopLeft != topLeft; |
| 168 SkTDArray<SkOpSpan*> chase; | 136 SkTDArray<SkOpSpanBase*> chase; |
| 169 do { | 137 do { |
| 170 if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) { | 138 if (current->activeOp(start, end, xorMask, xorOpMask, op)) { |
| 171 do { | 139 do { |
| 172 if (!unsortable && current->done()) { | 140 if (!unsortable && current->done()) { |
| 173 break; | 141 break; |
| 174 } | 142 } |
| 175 SkASSERT(unsortable || !current->done()); | 143 SkASSERT(unsortable || !current->done()); |
| 176 int nextStart = index; | 144 SkOpSpanBase* nextStart = start; |
| 177 int nextEnd = endIndex; | 145 SkOpSpanBase* nextEnd = end; |
| 178 SkOpSegment* next = current->findNextOp(&chase, &nextStart,
&nextEnd, | 146 SkOpSegment* next = current->findNextOp(&chase, &nextStart,
&nextEnd, |
| 179 &unsortable, op, xorMask, xorOpMask); | 147 &unsortable, op, xorMask, xorOpMask); |
| 180 if (!next) { | 148 if (!next) { |
| 181 if (!unsortable && simple->hasMove() | 149 if (!unsortable && simple->hasMove() |
| 182 && current->verb() != SkPath::kLine_Verb | 150 && current->verb() != SkPath::kLine_Verb |
| 183 && !simple->isClosed()) { | 151 && !simple->isClosed()) { |
| 184 current->addCurveTo(index, endIndex, simple, true); | 152 current->addCurveTo(start, end, simple, true); |
| 185 #if DEBUG_ACTIVE_SPANS | 153 #if DEBUG_ACTIVE_SPANS |
| 186 if (!simple->isClosed()) { | 154 if (!simple->isClosed()) { |
| 187 DebugShowActiveSpans(contourList); | 155 DebugShowActiveSpans(contourList); |
| 188 } | 156 } |
| 189 #endif | 157 #endif |
| 190 // SkASSERT(simple->isClosed()); | |
| 191 } | 158 } |
| 192 break; | 159 break; |
| 193 } | 160 } |
| 194 #if DEBUG_FLOW | 161 #if DEBUG_FLOW |
| 195 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _
_FUNCTION__, | 162 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9
g)\n", __FUNCTION__, |
| 196 current->debugID(), current->xyAtT(index).fX, current->xyAtT
(index).fY, | 163 current->debugID(), start->pt().fX, start->pt().fY, |
| 197 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY); | 164 end->pt().fX, end->pt().fY); |
| 198 #endif | 165 #endif |
| 199 current->addCurveTo(index, endIndex, simple, true); | 166 current->addCurveTo(start, end, simple, true); |
| 200 current = next; | 167 current = next; |
| 201 index = nextStart; | 168 start = nextStart; |
| 202 endIndex = nextEnd; | 169 end = nextEnd; |
| 203 } while (!simple->isClosed() && (!unsortable | 170 } while (!simple->isClosed() && (!unsortable || !start->starter(
end)->done())); |
| 204 || !current->done(SkMin32(index, endIndex)))); | 171 if (current->activeWinding(start, end) && !simple->isClosed()) { |
| 205 if (current->activeWinding(index, endIndex) && !simple->isClosed
()) { | 172 SkOpSpan* spanStart = start->starter(end); |
| 206 // FIXME : add to simplify, xor cpaths | 173 if (!spanStart->done()) { |
| 207 int min = SkMin32(index, endIndex); | 174 current->addCurveTo(start, end, simple, true); |
| 208 if (!unsortable && !simple->isEmpty()) { | 175 current->markDone(spanStart); |
| 209 unsortable = current->checkSmall(min); | |
| 210 } | |
| 211 if (!current->done(min)) { | |
| 212 current->addCurveTo(index, endIndex, simple, true); | |
| 213 current->markDoneBinary(min); | |
| 214 } | 176 } |
| 215 } | 177 } |
| 216 simple->close(); | 178 simple->close(); |
| 217 } else { | 179 } else { |
| 218 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex
); | 180 SkOpSpanBase* last = current->markAndChaseDone(start, end); |
| 219 if (last && !last->fChased && !last->fLoop) { | 181 if (last && !last->chased()) { |
| 220 last->fChased = true; | 182 last->setChased(true); |
| 221 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); | 183 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); |
| 222 *chase.append() = last; | 184 *chase.append() = last; |
| 223 #if DEBUG_WINDING | 185 #if DEBUG_WINDING |
| 224 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FU
NCTION__, | 186 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen
t()->debugID()); |
| 225 last->fOther->span(last->fOtherIndex).fOther->debugI
D(), last->fWindSum, | 187 if (!last->final()) { |
| 226 last->fSmall); | 188 SkDebugf(" windSum=%d", last->upCast()->windSum()); |
| 189 } |
| 190 SkDebugf("\n"); |
| 227 #endif | 191 #endif |
| 228 } | 192 } |
| 229 } | 193 } |
| 230 current = findChaseOp(chase, &index, &endIndex); | 194 current = findChaseOp(chase, &start, &end); |
| 231 #if DEBUG_ACTIVE_SPANS | 195 #if DEBUG_ACTIVE_SPANS |
| 232 DebugShowActiveSpans(contourList); | 196 DebugShowActiveSpans(contourList); |
| 233 #endif | 197 #endif |
| 234 if (!current) { | 198 if (!current) { |
| 235 break; | 199 break; |
| 236 } | 200 } |
| 237 } while (true); | 201 } while (true); |
| 238 } while (true); | 202 } while (true); |
| 239 return simple->someAssemblyRequired(); | 203 return simple->someAssemblyRequired(); |
| 240 } | 204 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 ++dumpID); | 248 ++dumpID); |
| 285 fprintf(file, " SkPath path;\n"); | 249 fprintf(file, " SkPath path;\n"); |
| 286 fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillT
ype()); | 250 fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillT
ype()); |
| 287 dump_path(file, one, false, true); | 251 dump_path(file, one, false, true); |
| 288 fprintf(file, " SkPath path1(path);\n"); | 252 fprintf(file, " SkPath path1(path);\n"); |
| 289 fprintf(file, " path.reset();\n"); | 253 fprintf(file, " path.reset();\n"); |
| 290 fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillT
ype()); | 254 fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillT
ype()); |
| 291 dump_path(file, two, false, true); | 255 dump_path(file, two, false, true); |
| 292 fprintf(file, " SkPath path2(path);\n"); | 256 fprintf(file, " SkPath path2(path);\n"); |
| 293 fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filenam
e);\n", op); | 257 fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filenam
e);\n", op); |
| 294 fprintf(file, "}\n");» | 258 fprintf(file, "}\n"); |
| 295 fclose(file); | 259 fclose(file); |
| 296 } | 260 } |
| 297 #endif | 261 #endif |
| 298 | 262 |
| 299 bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { | 263 bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { |
| 264 SkOpContour contour; |
| 265 SkOpCoincidence coincidence; |
| 266 SkOpGlobalState globalState(&coincidence PATH_OPS_DEBUG_PARAMS(&contour)); |
| 300 #if DEBUGGING_PATHOPS_FROM_HOST | 267 #if DEBUGGING_PATHOPS_FROM_HOST |
| 301 dump_op(one, two, op); | 268 dump_op(one, two, op); |
| 302 #endif» | 269 #endif |
| 303 #if DEBUG_SHOW_TEST_NAME | 270 #if 0 && DEBUG_SHOW_TEST_NAME |
| 304 char* debugName = DEBUG_FILENAME_STRING; | 271 char* debugName = DEBUG_FILENAME_STRING; |
| 305 if (debugName && debugName[0]) { | 272 if (debugName && debugName[0]) { |
| 306 SkPathOpsDebug::BumpTestName(debugName); | 273 SkPathOpsDebug::BumpTestName(debugName); |
| 307 SkPathOpsDebug::ShowPath(one, two, op, debugName); | 274 SkPathOpsDebug::ShowPath(one, two, op, debugName); |
| 308 } | 275 } |
| 309 #endif | 276 #endif |
| 310 op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; | 277 op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; |
| 311 SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isI
nverseFillType()] | 278 SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isI
nverseFillType()] |
| 312 ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType; | 279 ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType; |
| 313 const SkPath* minuend = &one; | 280 const SkPath* minuend = &one; |
| 314 const SkPath* subtrahend = &two; | 281 const SkPath* subtrahend = &two; |
| 315 if (op == kReverseDifference_PathOp) { | 282 if (op == kReverseDifference_PathOp) { |
| 316 minuend = &two; | 283 minuend = &two; |
| 317 subtrahend = &one; | 284 subtrahend = &one; |
| 318 op = kDifference_PathOp; | 285 op = kDifference_PathOp; |
| 319 } | 286 } |
| 320 #if DEBUG_SORT || DEBUG_SWAP_TOP | 287 #if DEBUG_SORT || DEBUG_SWAP_TOP |
| 321 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; | 288 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; |
| 322 #endif | 289 #endif |
| 323 // turn path into list of segments | 290 // turn path into list of segments |
| 324 SkTArray<SkOpContour> contours; | 291 SkChunkAlloc allocator(4096); // FIXME: add a constant expression here, tun
e |
| 325 // FIXME: add self-intersecting cubics' T values to segment | 292 SkOpEdgeBuilder builder(*minuend, &contour, &allocator, &globalState); |
| 326 SkOpEdgeBuilder builder(*minuend, contours); | |
| 327 if (builder.unparseable()) { | 293 if (builder.unparseable()) { |
| 328 return false; | 294 return false; |
| 329 } | 295 } |
| 330 const int xorMask = builder.xorMask(); | 296 const int xorMask = builder.xorMask(); |
| 331 builder.addOperand(*subtrahend); | 297 builder.addOperand(*subtrahend); |
| 332 if (!builder.finish()) { | 298 if (!builder.finish(&allocator)) { |
| 333 return false; | 299 return false; |
| 334 } | 300 } |
| 301 #if !FORCE_RELEASE |
| 302 contour.dumpSegments(op); |
| 303 #endif |
| 304 |
| 335 result->reset(); | 305 result->reset(); |
| 336 result->setFillType(fillType); | 306 result->setFillType(fillType); |
| 337 const int xorOpMask = builder.xorMask(); | 307 const int xorOpMask = builder.xorMask(); |
| 338 SkTArray<SkOpContour*, true> contourList; | 308 SkTDArray<SkOpContour* > contourList; |
| 339 MakeContourList(contours, contourList, xorMask == kEvenOdd_PathOpsMask, | 309 MakeContourList(&contour, contourList, xorMask == kEvenOdd_PathOpsMask, |
| 340 xorOpMask == kEvenOdd_PathOpsMask); | 310 xorOpMask == kEvenOdd_PathOpsMask); |
| 341 SkOpContour** currentPtr = contourList.begin(); | 311 SkOpContour** currentPtr = contourList.begin(); |
| 342 if (!currentPtr) { | 312 if (!currentPtr) { |
| 343 return true; | 313 return true; |
| 344 } | 314 } |
| 315 if ((*currentPtr)->count() == 0) { |
| 316 SkASSERT((*currentPtr)->next() == NULL); |
| 317 return true; |
| 318 } |
| 345 SkOpContour** listEnd = contourList.end(); | 319 SkOpContour** listEnd = contourList.end(); |
| 346 // find all intersections between segments | 320 // find all intersections between segments |
| 347 do { | 321 do { |
| 348 SkOpContour** nextPtr = currentPtr; | 322 SkOpContour** nextPtr = currentPtr; |
| 349 SkOpContour* current = *currentPtr++; | 323 SkOpContour* current = *currentPtr++; |
| 350 if (current->containsCubics()) { | |
| 351 AddSelfIntersectTs(current); | |
| 352 } | |
| 353 SkOpContour* next; | 324 SkOpContour* next; |
| 354 do { | 325 do { |
| 355 next = *nextPtr++; | 326 next = *nextPtr++; |
| 356 } while (AddIntersectTs(current, next) && nextPtr != listEnd); | 327 } while (AddIntersectTs(current, next, &coincidence, &allocator) && next
Ptr != listEnd); |
| 357 } while (currentPtr != listEnd); | 328 } while (currentPtr != listEnd); |
| 329 #if DEBUG_VALIDATE |
| 330 globalState.setPhase(SkOpGlobalState::kWalking); |
| 331 #endif |
| 358 // eat through coincident edges | 332 // eat through coincident edges |
| 359 | 333 if (!HandleCoincidence(&contourList, &coincidence, &allocator, &globalState)
) { |
| 360 int total = 0; | |
| 361 int index; | |
| 362 for (index = 0; index < contourList.count(); ++index) { | |
| 363 total += contourList[index]->segments().count(); | |
| 364 } | |
| 365 if (!HandleCoincidence(&contourList, total)) { | |
| 366 return false; | 334 return false; |
| 367 } | 335 } |
| 368 // construct closed contours | 336 // construct closed contours |
| 369 SkPathWriter wrapper(*result); | 337 SkPathWriter wrapper(*result); |
| 370 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); | 338 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper, &allocator); |
| 371 { // if some edges could not be resolved, assemble remaining fragments | 339 { // if some edges could not be resolved, assemble remaining fragments |
| 372 SkPath temp; | 340 SkPath temp; |
| 373 temp.setFillType(fillType); | 341 temp.setFillType(fillType); |
| 374 SkPathWriter assembled(temp); | 342 SkPathWriter assembled(temp); |
| 375 Assemble(wrapper, &assembled); | 343 Assemble(wrapper, &assembled); |
| 376 *result = *assembled.nativePath(); | 344 *result = *assembled.nativePath(); |
| 377 result->setFillType(fillType); | 345 result->setFillType(fillType); |
| 378 } | 346 } |
| 379 return true; | 347 return true; |
| 380 } | 348 } |
| OLD | NEW |