| 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 "SkOpCoincidence.h" |
| 9 #include "SkOpEdgeBuilder.h" | 9 #include "SkOpEdgeBuilder.h" |
| 10 #include "SkPathOpsCommon.h" | 10 #include "SkPathOpsCommon.h" |
| 11 #include "SkPathWriter.h" | 11 #include "SkPathWriter.h" |
| 12 | 12 |
| 13 static bool bridgeWinding(SkTDArray<SkOpContour* >& contourList, SkPathWriter* s
imple, | 13 static bool bridgeWinding(SkOpContourHead* contourList, SkPathWriter* simple, |
| 14 SkChunkAlloc* allocator) { | 14 SkChunkAlloc* allocator) { |
| 15 bool firstContour = true; | |
| 16 bool unsortable = false; | 15 bool unsortable = false; |
| 17 bool topUnsortable = false; | |
| 18 bool firstPass = true; | |
| 19 SkDPoint lastTopLeft; | |
| 20 SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; | |
| 21 do { | 16 do { |
| 22 SkOpSpanBase* start = NULL; | 17 SkOpSpan* span = FindSortableTop(contourList); |
| 23 SkOpSpanBase* end = NULL; | 18 if (!span) { |
| 24 bool topDone; | |
| 25 bool onlyVertical = false; | |
| 26 lastTopLeft = topLeft; | |
| 27 SkOpSegment* current = FindSortableTop(contourList, firstPass, SkOpAngle
::kUnaryWinding, | |
| 28 &firstContour, &start, &end, &topLeft, &topUnsortable, &topDone,
&onlyVertical, | |
| 29 allocator); | |
| 30 if (!current) { | |
| 31 if ((!topUnsortable || firstPass) && !topDone) { | |
| 32 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi
n); | |
| 33 if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_Scala
rMin) { | |
| 34 if (firstPass) { | |
| 35 firstPass = false; | |
| 36 } else { | |
| 37 break; | |
| 38 } | |
| 39 } | |
| 40 topLeft.fX = topLeft.fY = SK_ScalarMin; | |
| 41 continue; | |
| 42 } | |
| 43 break; | |
| 44 } else if (onlyVertical) { | |
| 45 break; | 19 break; |
| 46 } | 20 } |
| 47 firstPass = !topUnsortable || lastTopLeft != topLeft; | 21 SkOpSegment* current = span->segment(); |
| 22 SkOpSpanBase* start = span->next(); |
| 23 SkOpSpanBase* end = span; |
| 48 SkTDArray<SkOpSpanBase*> chase; | 24 SkTDArray<SkOpSpanBase*> chase; |
| 49 do { | 25 do { |
| 50 if (current->activeWinding(start, end)) { | 26 if (current->activeWinding(start, end)) { |
| 51 do { | 27 do { |
| 52 if (!unsortable && current->done()) { | 28 if (!unsortable && current->done()) { |
| 53 break; | 29 break; |
| 54 } | 30 } |
| 55 SkASSERT(unsortable || !current->done()); | 31 SkASSERT(unsortable || !current->done()); |
| 56 SkOpSpanBase* nextStart = start; | 32 SkOpSpanBase* nextStart = start; |
| 57 SkOpSpanBase* nextEnd = end; | 33 SkOpSpanBase* nextEnd = end; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 86 current->addCurveTo(start, end, simple, true); | 62 current->addCurveTo(start, end, simple, true); |
| 87 current->markDone(spanStart); | 63 current->markDone(spanStart); |
| 88 } | 64 } |
| 89 } | 65 } |
| 90 simple->close(); | 66 simple->close(); |
| 91 } else { | 67 } else { |
| 92 SkOpSpanBase* last = current->markAndChaseDone(start, end); | 68 SkOpSpanBase* last = current->markAndChaseDone(start, end); |
| 93 if (last && !last->chased()) { | 69 if (last && !last->chased()) { |
| 94 last->setChased(true); | 70 last->setChased(true); |
| 95 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); | 71 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); |
| 96 // assert that last isn't already in array | |
| 97 *chase.append() = last; | 72 *chase.append() = last; |
| 98 #if DEBUG_WINDING | 73 #if DEBUG_WINDING |
| 99 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen
t()->debugID()); | 74 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen
t()->debugID()); |
| 100 if (!last->final()) { | 75 if (!last->final()) { |
| 101 SkDebugf(" windSum=%d", last->upCast()->windSum()); | 76 SkDebugf(" windSum=%d", last->upCast()->windSum()); |
| 102 } | 77 } |
| 103 SkDebugf("\n"); | 78 SkDebugf("\n"); |
| 104 #endif | 79 #endif |
| 105 } | 80 } |
| 106 } | 81 } |
| 107 current = FindChase(&chase, &start, &end); | 82 current = FindChase(&chase, &start, &end); |
| 108 #if DEBUG_ACTIVE_SPANS | 83 #if DEBUG_ACTIVE_SPANS |
| 109 DebugShowActiveSpans(contourList); | 84 DebugShowActiveSpans(contourList); |
| 110 #endif | 85 #endif |
| 111 if (!current) { | 86 if (!current) { |
| 112 break; | 87 break; |
| 113 } | 88 } |
| 114 } while (true); | 89 } while (true); |
| 115 } while (true); | 90 } while (true); |
| 116 return simple->someAssemblyRequired(); | 91 return simple->someAssemblyRequired(); |
| 117 } | 92 } |
| 118 | 93 |
| 119 // returns true if all edges were processed | 94 // returns true if all edges were processed |
| 120 static bool bridgeXor(SkTDArray<SkOpContour* >& contourList, SkPathWriter* simpl
e, | 95 static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple, |
| 121 SkChunkAlloc* allocator) { | 96 SkChunkAlloc* allocator) { |
| 122 SkOpSegment* current; | 97 SkOpSegment* current; |
| 123 SkOpSpanBase* start; | 98 SkOpSpanBase* start; |
| 124 SkOpSpanBase* end; | 99 SkOpSpanBase* end; |
| 125 bool unsortable = false; | 100 bool unsortable = false; |
| 126 bool closable = true; | 101 bool closable = true; |
| 127 while ((current = FindUndone(contourList, &start, &end))) { | 102 while ((current = FindUndone(contourList, &start, &end))) { |
| 128 do { | 103 do { |
| 129 #if DEBUG_ACTIVE_SPANS | 104 #if DEBUG_ACTIVE_SPANS |
| 130 if (!unsortable && current->done()) { | 105 if (!unsortable && current->done()) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 if (path.isConvex()) { | 159 if (path.isConvex()) { |
| 185 if (result != &path) { | 160 if (result != &path) { |
| 186 *result = path; | 161 *result = path; |
| 187 } | 162 } |
| 188 result->setFillType(fillType); | 163 result->setFillType(fillType); |
| 189 return true; | 164 return true; |
| 190 } | 165 } |
| 191 // turn path into list of segments | 166 // turn path into list of segments |
| 192 SkOpCoincidence coincidence; | 167 SkOpCoincidence coincidence; |
| 193 SkOpContour contour; | 168 SkOpContour contour; |
| 194 SkOpGlobalState globalState(&coincidence SkDEBUGPARAMS(&contour)); | 169 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); |
| 195 #if DEBUG_SORT || DEBUG_SWAP_TOP | 170 SkOpGlobalState globalState(&coincidence, contourList); |
| 171 #if DEBUG_SORT |
| 196 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; | 172 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; |
| 197 #endif | 173 #endif |
| 198 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); | 174 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); |
| 199 if (!builder.finish(&allocator)) { | 175 if (!builder.finish(&allocator)) { |
| 200 return false; | 176 return false; |
| 201 } | 177 } |
| 202 #if DEBUG_DUMP_SEGMENTS | 178 #if DEBUG_DUMP_SEGMENTS |
| 203 contour.dumpSegments((SkPathOp) -1); | 179 contour.dumpSegments((SkPathOp) -1); |
| 204 #endif | 180 #endif |
| 205 SkTDArray<SkOpContour* > contourList; | 181 if (!SortContourList(&contourList, false, false)) { |
| 206 MakeContourList(&contour, contourList, false, false); | |
| 207 SkOpContour** currentPtr = contourList.begin(); | |
| 208 if (!currentPtr) { | |
| 209 result->reset(); | 182 result->reset(); |
| 210 result->setFillType(fillType); | 183 result->setFillType(fillType); |
| 211 return true; | 184 return true; |
| 212 } | 185 } |
| 213 if ((*currentPtr)->count() == 0) { | |
| 214 SkASSERT((*currentPtr)->next() == NULL); | |
| 215 result->reset(); | |
| 216 result->setFillType(fillType); | |
| 217 return true; | |
| 218 } | |
| 219 SkOpContour** listEnd2 = contourList.end(); | |
| 220 // find all intersections between segments | 186 // find all intersections between segments |
| 187 SkOpContour* current = contourList; |
| 221 do { | 188 do { |
| 222 SkOpContour** nextPtr = currentPtr; | 189 SkOpContour* next = current; |
| 223 SkOpContour* current = *currentPtr++; | 190 while (AddIntersectTs(current, next, &coincidence, &allocator) |
| 224 SkOpContour* next; | 191 && (next = next->next())); |
| 225 do { | 192 } while ((current = current->next())); |
| 226 next = *nextPtr++; | |
| 227 } while (AddIntersectTs(current, next, &coincidence, &allocator) && next
Ptr != listEnd2); | |
| 228 } while (currentPtr != listEnd2); | |
| 229 #if DEBUG_VALIDATE | 193 #if DEBUG_VALIDATE |
| 230 globalState.setPhase(SkOpGlobalState::kWalking); | 194 globalState.setPhase(SkOpGlobalState::kWalking); |
| 231 #endif | 195 #endif |
| 232 if (!HandleCoincidence(&contourList, &coincidence, &allocator, &globalState)
) { | 196 if (!HandleCoincidence(contourList, &coincidence, &allocator)) { |
| 233 return false; | 197 return false; |
| 234 } | 198 } |
| 235 // construct closed contours | 199 // construct closed contours |
| 236 result->reset(); | 200 result->reset(); |
| 237 result->setFillType(fillType); | 201 result->setFillType(fillType); |
| 238 SkPathWriter wrapper(*result); | 202 SkPathWriter wrapper(*result); |
| 239 if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &
wrapper, &allocator) | 203 if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &
wrapper, &allocator) |
| 240 : !bridgeXor(contourList, &wrapper, &allocator)) | 204 : !bridgeXor(contourList, &wrapper, &allocator)) |
| 241 { // if some edges could not be resolved, assemble remaining fragments | 205 { // if some edges could not be resolved, assemble remaining fragments |
| 242 SkPath temp; | 206 SkPath temp; |
| 243 temp.setFillType(fillType); | 207 temp.setFillType(fillType); |
| 244 SkPathWriter assembled(temp); | 208 SkPathWriter assembled(temp); |
| 245 Assemble(wrapper, &assembled); | 209 Assemble(wrapper, &assembled); |
| 246 *result = *assembled.nativePath(); | 210 *result = *assembled.nativePath(); |
| 247 result->setFillType(fillType); | 211 result->setFillType(fillType); |
| 248 } | 212 } |
| 249 return true; | 213 return true; |
| 250 } | 214 } |
| OLD | NEW |