| 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 "SkOpEdgeBuilder.h" | 8 #include "SkOpEdgeBuilder.h" |
| 9 #include "SkPathOpsCommon.h" | 9 #include "SkPathOpsCommon.h" |
| 10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 int angleCount = sorted.count(); | 42 int angleCount = sorted.count(); |
| 43 #if DEBUG_SORT | 43 #if DEBUG_SORT |
| 44 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, sortable); | 44 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, sortable); |
| 45 #endif | 45 #endif |
| 46 if (!sortable) { | 46 if (!sortable) { |
| 47 continue; | 47 continue; |
| 48 } | 48 } |
| 49 // find first angle, initialize winding to computed fWindSum | 49 // find first angle, initialize winding to computed fWindSum |
| 50 int firstIndex = -1; | 50 int firstIndex = -1; |
| 51 const SkOpAngle* angle; | 51 const SkOpAngle* angle; |
| 52 bool foundAngle = true; |
| 52 do { | 53 do { |
| 53 angle = sorted[++firstIndex]; | 54 ++firstIndex; |
| 55 if (firstIndex >= angleCount) { |
| 56 foundAngle = false; |
| 57 break; |
| 58 } |
| 59 angle = sorted[firstIndex]; |
| 54 segment = angle->segment(); | 60 segment = angle->segment(); |
| 55 } while (segment->windSum(angle) == SK_MinS32); | 61 } while (segment->windSum(angle) == SK_MinS32); |
| 62 if (!foundAngle) { |
| 63 continue; |
| 64 } |
| 56 #if DEBUG_SORT | 65 #if DEBUG_SORT |
| 57 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | 66 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); |
| 58 #endif | 67 #endif |
| 59 int sumMiWinding = segment->updateWindingReverse(angle); | 68 int sumMiWinding = segment->updateWindingReverse(angle); |
| 60 int sumSuWinding = segment->updateOppWindingReverse(angle); | 69 int sumSuWinding = segment->updateOppWindingReverse(angle); |
| 61 if (segment->operand()) { | 70 if (segment->operand()) { |
| 62 SkTSwap<int>(sumMiWinding, sumSuWinding); | 71 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 63 } | 72 } |
| 64 int nextIndex = firstIndex + 1; | 73 int nextIndex = firstIndex + 1; |
| 65 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | 74 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 | 137 |
| 129 static bool bridgeOp(SkTArray<SkOpContour*, true>& contourList, const SkPathOp o
p, | 138 static bool bridgeOp(SkTArray<SkOpContour*, true>& contourList, const SkPathOp o
p, |
| 130 const int xorMask, const int xorOpMask, SkPathWriter* simple) { | 139 const int xorMask, const int xorOpMask, SkPathWriter* simple) { |
| 131 bool firstContour = true; | 140 bool firstContour = true; |
| 132 bool unsortable = false; | 141 bool unsortable = false; |
| 133 bool topUnsortable = false; | 142 bool topUnsortable = false; |
| 134 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; | 143 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; |
| 135 do { | 144 do { |
| 136 int index, endIndex; | 145 int index, endIndex; |
| 137 bool done; | 146 bool done; |
| 138 SkOpSegment* current = FindSortableTop(contourList, &firstContour, &inde
x, &endIndex, | 147 SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kBinarySi
ngle, &firstContour, |
| 139 &topLeft, &topUnsortable, &done, true); | 148 &index, &endIndex, &topLeft, &topUnsortable, &done); |
| 140 if (!current) { | 149 if (!current) { |
| 141 if (topUnsortable || !done) { | 150 if (topUnsortable || !done) { |
| 142 topUnsortable = false; | 151 topUnsortable = false; |
| 143 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi
n); | 152 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi
n); |
| 144 topLeft.fX = topLeft.fY = SK_ScalarMin; | 153 topLeft.fX = topLeft.fY = SK_ScalarMin; |
| 145 continue; | 154 continue; |
| 146 } | 155 } |
| 147 break; | 156 break; |
| 148 } | 157 } |
| 149 SkTDArray<SkOpSpan*> chaseArray; | 158 SkTDArray<SkOpSpan*> chaseArray; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 178 current->debugID(), current->xyAtT(index).fX, current->xyAtT
(index).fY, | 187 current->debugID(), current->xyAtT(index).fX, current->xyAtT
(index).fY, |
| 179 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY); | 188 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY); |
| 180 #endif | 189 #endif |
| 181 current->addCurveTo(index, endIndex, simple, true); | 190 current->addCurveTo(index, endIndex, simple, true); |
| 182 current = next; | 191 current = next; |
| 183 index = nextStart; | 192 index = nextStart; |
| 184 endIndex = nextEnd; | 193 endIndex = nextEnd; |
| 185 } while (!simple->isClosed() && (!unsortable | 194 } while (!simple->isClosed() && (!unsortable |
| 186 || !current->done(SkMin32(index, endIndex)))); | 195 || !current->done(SkMin32(index, endIndex)))); |
| 187 if (current->activeWinding(index, endIndex) && !simple->isClosed
()) { | 196 if (current->activeWinding(index, endIndex) && !simple->isClosed
()) { |
| 197 // FIXME : add to simplify, xor cpaths |
| 198 int min = SkMin32(index, endIndex); |
| 199 if (!unsortable && !simple->isEmpty()) { |
| 200 unsortable = current->checkSmall(min); |
| 201 } |
| 188 SkASSERT(unsortable || simple->isEmpty()); | 202 SkASSERT(unsortable || simple->isEmpty()); |
| 189 int min = SkMin32(index, endIndex); | |
| 190 if (!current->done(min)) { | 203 if (!current->done(min)) { |
| 191 current->addCurveTo(index, endIndex, simple, true); | 204 current->addCurveTo(index, endIndex, simple, true); |
| 192 current->markDoneBinary(min); | 205 current->markDoneBinary(min); |
| 193 } | 206 } |
| 194 } | 207 } |
| 195 simple->close(); | 208 simple->close(); |
| 196 } else { | 209 } else { |
| 197 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex
); | 210 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex
); |
| 198 if (last && !last->fLoop) { | 211 if (last && !last->fLoop) { |
| 199 *chaseArray.append() = last; | 212 *chaseArray.append() = last; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 228 {{ false, false }, { false, true }}, // sect | 241 {{ false, false }, { false, true }}, // sect |
| 229 {{ false, true }, { true, true }}, // union | 242 {{ false, true }, { true, true }}, // union |
| 230 {{ false, true }, { true, false }}, // xor | 243 {{ false, true }, { true, false }}, // xor |
| 231 {{ false, true }, { false, false }}, // rev diff | 244 {{ false, true }, { false, false }}, // rev diff |
| 232 }; | 245 }; |
| 233 | 246 |
| 234 bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { | 247 bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { |
| 235 #if DEBUG_SHOW_TEST_NAME | 248 #if DEBUG_SHOW_TEST_NAME |
| 236 char* debugName = DEBUG_FILENAME_STRING; | 249 char* debugName = DEBUG_FILENAME_STRING; |
| 237 if (debugName && debugName[0]) { | 250 if (debugName && debugName[0]) { |
| 238 DebugBumpTestName(debugName); | 251 SkPathOpsDebug::BumpTestName(debugName); |
| 239 DebugShowPath(one, two, op, debugName); | 252 SkPathOpsDebug::ShowPath(one, two, op, debugName); |
| 240 } | 253 } |
| 241 #endif | 254 #endif |
| 242 op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; | 255 op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; |
| 243 SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isI
nverseFillType()] | 256 SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isI
nverseFillType()] |
| 244 ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType; | 257 ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType; |
| 245 const SkPath* minuend = &one; | 258 const SkPath* minuend = &one; |
| 246 const SkPath* subtrahend = &two; | 259 const SkPath* subtrahend = &two; |
| 247 if (op == kReverseDifference_PathOp) { | 260 if (op == kReverseDifference_PathOp) { |
| 248 minuend = &two; | 261 minuend = &two; |
| 249 subtrahend = &one; | 262 subtrahend = &one; |
| 250 op = kDifference_PathOp; | 263 op = kDifference_PathOp; |
| 251 } | 264 } |
| 252 #if DEBUG_SORT || DEBUG_SWAP_TOP | 265 #if DEBUG_SORT || DEBUG_SWAP_TOP |
| 253 gDebugSortCount = gDebugSortCountDefault; | 266 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; |
| 254 #endif | 267 #endif |
| 255 // turn path into list of segments | 268 // turn path into list of segments |
| 256 SkTArray<SkOpContour> contours; | 269 SkTArray<SkOpContour> contours; |
| 257 // FIXME: add self-intersecting cubics' T values to segment | 270 // FIXME: add self-intersecting cubics' T values to segment |
| 258 SkOpEdgeBuilder builder(*minuend, contours); | 271 SkOpEdgeBuilder builder(*minuend, contours); |
| 259 const int xorMask = builder.xorMask(); | 272 const int xorMask = builder.xorMask(); |
| 260 builder.addOperand(*subtrahend); | 273 builder.addOperand(*subtrahend); |
| 261 if (!builder.finish()) { | 274 if (!builder.finish()) { |
| 262 return false; | 275 return false; |
| 263 } | 276 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 293 } | 306 } |
| 294 #if DEBUG_SHOW_WINDING | 307 #if DEBUG_SHOW_WINDING |
| 295 SkOpContour::debugShowWindingValues(contourList); | 308 SkOpContour::debugShowWindingValues(contourList); |
| 296 #endif | 309 #endif |
| 297 CoincidenceCheck(&contourList, total); | 310 CoincidenceCheck(&contourList, total); |
| 298 #if DEBUG_SHOW_WINDING | 311 #if DEBUG_SHOW_WINDING |
| 299 SkOpContour::debugShowWindingValues(contourList); | 312 SkOpContour::debugShowWindingValues(contourList); |
| 300 #endif | 313 #endif |
| 301 FixOtherTIndex(&contourList); | 314 FixOtherTIndex(&contourList); |
| 302 CheckEnds(&contourList); | 315 CheckEnds(&contourList); |
| 316 CheckTiny(&contourList); |
| 303 SortSegments(&contourList); | 317 SortSegments(&contourList); |
| 304 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | 318 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
| 305 DebugShowActiveSpans(contourList); | 319 DebugShowActiveSpans(contourList); |
| 306 #endif | 320 #endif |
| 307 // construct closed contours | 321 // construct closed contours |
| 308 SkPathWriter wrapper(*result); | 322 SkPathWriter wrapper(*result); |
| 309 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); | 323 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); |
| 310 { // if some edges could not be resolved, assemble remaining fragments | 324 { // if some edges could not be resolved, assemble remaining fragments |
| 311 SkPath temp; | 325 SkPath temp; |
| 312 temp.setFillType(fillType); | 326 temp.setFillType(fillType); |
| 313 SkPathWriter assembled(temp); | 327 SkPathWriter assembled(temp); |
| 314 Assemble(wrapper, &assembled); | 328 Assemble(wrapper, &assembled); |
| 315 *result = *assembled.nativePath(); | 329 *result = *assembled.nativePath(); |
| 316 result->setFillType(fillType); | 330 result->setFillType(fillType); |
| 317 } | 331 } |
| 318 return true; | 332 return true; |
| 319 } | 333 } |
| OLD | NEW |