| 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" |
| 11 | 11 |
| 12 // FIXME: this and find chase should be merge together, along with | 12 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int* tIndex, int* e
ndIndex) { |
| 13 // other code that walks winding in angles | |
| 14 // OPTIMIZATION: Probably, the walked winding should be rolled into the angle st
ructure | |
| 15 // so it isn't duplicated by walkers like this one | |
| 16 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int& nextStart, int
& nextEnd) { | |
| 17 while (chase.count()) { | 13 while (chase.count()) { |
| 18 SkOpSpan* span; | 14 SkOpSpan* span; |
| 19 chase.pop(&span); | 15 chase.pop(&span); |
| 20 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); | 16 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex); |
| 21 SkOpSegment* segment = backPtr.fOther; | 17 SkOpSegment* segment = backPtr.fOther; |
| 22 nextStart = backPtr.fOtherIndex; | 18 *tIndex = backPtr.fOtherIndex; |
| 23 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 19 bool sortable = true; |
| 24 int done = 0; | 20 bool done = true; |
| 25 if (segment->activeAngle(nextStart, &done, &angles)) { | 21 *endIndex = -1; |
| 26 SkOpAngle* last = angles.end() - 1; | 22 if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endInd
ex, &done, |
| 27 nextStart = last->start(); | 23 &sortable)) { |
| 28 nextEnd = last->end(); | 24 *tIndex = last->start(); |
| 25 *endIndex = last->end(); |
| 29 #if TRY_ROTATE | 26 #if TRY_ROTATE |
| 30 *chase.insert(0) = span; | 27 *chase.insert(0) = span; |
| 31 #else | 28 #else |
| 32 *chase.append() = span; | 29 *chase.append() = span; |
| 33 #endif | 30 #endif |
| 34 return last->segment(); | 31 return last->segment(); |
| 35 } | 32 } |
| 36 if (done == angles.count()) { | 33 if (done) { |
| 37 continue; | 34 continue; |
| 38 } | 35 } |
| 39 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | |
| 40 bool sortable = SkOpSegment::SortAngles(angles, &sorted, | |
| 41 SkOpSegment::kMayBeUnordered_SortAngleKind); | |
| 42 int angleCount = sorted.count(); | |
| 43 #if DEBUG_SORT | |
| 44 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, sortable); | |
| 45 #endif | |
| 46 if (!sortable) { | 36 if (!sortable) { |
| 47 continue; | 37 continue; |
| 48 } | 38 } |
| 49 // find first angle, initialize winding to computed fWindSum | 39 // find first angle, initialize winding to computed fWindSum |
| 50 int firstIndex = -1; | 40 const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex); |
| 51 const SkOpAngle* angle; | 41 const SkOpAngle* firstAngle = angle; |
| 52 bool foundAngle = true; | 42 SkDEBUGCODE(bool loop = false); |
| 43 int winding; |
| 53 do { | 44 do { |
| 54 ++firstIndex; | 45 angle = angle->next(); |
| 55 if (firstIndex >= angleCount) { | 46 SkASSERT(angle != firstAngle || !loop); |
| 56 foundAngle = false; | 47 SkDEBUGCODE(loop |= angle == firstAngle); |
| 57 break; | |
| 58 } | |
| 59 angle = sorted[firstIndex]; | |
| 60 segment = angle->segment(); | 48 segment = angle->segment(); |
| 61 } while (segment->windSum(angle) == SK_MinS32); | 49 winding = segment->windSum(angle); |
| 62 if (!foundAngle) { | 50 } while (winding == SK_MinS32); |
| 63 continue; | |
| 64 } | |
| 65 #if DEBUG_SORT | |
| 66 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | |
| 67 #endif | |
| 68 int sumMiWinding = segment->updateWindingReverse(angle); | 51 int sumMiWinding = segment->updateWindingReverse(angle); |
| 69 int sumSuWinding = segment->updateOppWindingReverse(angle); | 52 int sumSuWinding = segment->updateOppWindingReverse(angle); |
| 70 if (segment->operand()) { | 53 if (segment->operand()) { |
| 71 SkTSwap<int>(sumMiWinding, sumSuWinding); | 54 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 72 } | 55 } |
| 73 int nextIndex = firstIndex + 1; | |
| 74 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | |
| 75 SkOpSegment* first = NULL; | 56 SkOpSegment* first = NULL; |
| 76 do { | 57 while ((angle = angle->next()) != firstAngle) { |
| 77 SkASSERT(nextIndex != firstIndex); | |
| 78 if (nextIndex == angleCount) { | |
| 79 nextIndex = 0; | |
| 80 } | |
| 81 angle = sorted[nextIndex]; | |
| 82 segment = angle->segment(); | 58 segment = angle->segment(); |
| 83 int start = angle->start(); | 59 int start = angle->start(); |
| 84 int end = angle->end(); | 60 int end = angle->end(); |
| 85 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; | 61 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; |
| 86 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding, | 62 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding, |
| 87 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | 63 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); |
| 88 if (!segment->done(angle)) { | 64 if (!segment->done(angle)) { |
| 89 if (!first) { | 65 if (!first) { |
| 90 first = segment; | 66 first = segment; |
| 91 nextStart = start; | 67 *tIndex = start; |
| 92 nextEnd = end; | 68 *endIndex = end; |
| 93 } | 69 } |
| 94 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, | 70 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, |
| 95 oppSumWinding, angle); | 71 oppSumWinding, angle); |
| 96 } | 72 } |
| 97 } while (++nextIndex != lastIndex); | 73 } |
| 98 if (first) { | 74 if (first) { |
| 99 #if TRY_ROTATE | 75 #if TRY_ROTATE |
| 100 *chase.insert(0) = span; | 76 *chase.insert(0) = span; |
| 101 #else | 77 #else |
| 102 *chase.append() = span; | 78 *chase.append() = span; |
| 103 #endif | 79 #endif |
| 104 return first; | 80 return first; |
| 105 } | 81 } |
| 106 } | 82 } |
| 107 return NULL; | 83 return NULL; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 topLeft.fX = topLeft.fY = SK_ScalarMin; | 129 topLeft.fX = topLeft.fY = SK_ScalarMin; |
| 154 continue; | 130 continue; |
| 155 } | 131 } |
| 156 break; | 132 break; |
| 157 } | 133 } |
| 158 SkTDArray<SkOpSpan*> chaseArray; | 134 SkTDArray<SkOpSpan*> chaseArray; |
| 159 do { | 135 do { |
| 160 if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) { | 136 if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) { |
| 161 do { | 137 do { |
| 162 if (!unsortable && current->done()) { | 138 if (!unsortable && current->done()) { |
| 163 #if DEBUG_ACTIVE_SPANS | |
| 164 DebugShowActiveSpans(contourList); | |
| 165 #endif | |
| 166 if (simple->isEmpty()) { | 139 if (simple->isEmpty()) { |
| 167 simple->init(); | 140 simple->init(); |
| 168 } | 141 } |
| 169 break; | 142 break; |
| 170 } | 143 } |
| 171 SkASSERT(unsortable || !current->done()); | 144 SkASSERT(unsortable || !current->done()); |
| 172 int nextStart = index; | 145 int nextStart = index; |
| 173 int nextEnd = endIndex; | 146 int nextEnd = endIndex; |
| 174 SkOpSegment* next = current->findNextOp(&chaseArray, &nextSt
art, &nextEnd, | 147 SkOpSegment* next = current->findNextOp(&chaseArray, &nextSt
art, &nextEnd, |
| 175 &unsortable, op, xorMask, xorOpMask); | 148 &unsortable, op, xorMask, xorOpMask); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 192 index = nextStart; | 165 index = nextStart; |
| 193 endIndex = nextEnd; | 166 endIndex = nextEnd; |
| 194 } while (!simple->isClosed() && (!unsortable | 167 } while (!simple->isClosed() && (!unsortable |
| 195 || !current->done(SkMin32(index, endIndex)))); | 168 || !current->done(SkMin32(index, endIndex)))); |
| 196 if (current->activeWinding(index, endIndex) && !simple->isClosed
()) { | 169 if (current->activeWinding(index, endIndex) && !simple->isClosed
()) { |
| 197 // FIXME : add to simplify, xor cpaths | 170 // FIXME : add to simplify, xor cpaths |
| 198 int min = SkMin32(index, endIndex); | 171 int min = SkMin32(index, endIndex); |
| 199 if (!unsortable && !simple->isEmpty()) { | 172 if (!unsortable && !simple->isEmpty()) { |
| 200 unsortable = current->checkSmall(min); | 173 unsortable = current->checkSmall(min); |
| 201 } | 174 } |
| 202 SkASSERT(unsortable || simple->isEmpty()); | |
| 203 if (!current->done(min)) { | 175 if (!current->done(min)) { |
| 204 current->addCurveTo(index, endIndex, simple, true); | 176 current->addCurveTo(index, endIndex, simple, true); |
| 205 current->markDoneBinary(min); | 177 current->markDoneBinary(min); |
| 206 } | 178 } |
| 207 } | 179 } |
| 208 simple->close(); | 180 simple->close(); |
| 209 } else { | 181 } else { |
| 210 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex
); | 182 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex
); |
| 211 if (last && !last->fLoop) { | 183 if (last && !last->fChased && !last->fLoop) { |
| 184 last->fChased = true; |
| 185 SkASSERT(!SkPathOpsDebug::ChaseContains(chaseArray, last)); |
| 212 *chaseArray.append() = last; | 186 *chaseArray.append() = last; |
| 213 } | 187 } |
| 214 } | 188 } |
| 215 current = findChaseOp(chaseArray, index, endIndex); | 189 current = findChaseOp(chaseArray, &index, &endIndex); |
| 216 #if DEBUG_ACTIVE_SPANS | 190 #if DEBUG_ACTIVE_SPANS |
| 217 DebugShowActiveSpans(contourList); | 191 DebugShowActiveSpans(contourList); |
| 218 #endif | 192 #endif |
| 219 if (!current) { | 193 if (!current) { |
| 220 break; | 194 break; |
| 221 } | 195 } |
| 222 } while (true); | 196 } while (true); |
| 223 } while (true); | 197 } while (true); |
| 224 return simple->someAssemblyRequired(); | 198 return simple->someAssemblyRequired(); |
| 225 } | 199 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 next = *nextPtr++; | 271 next = *nextPtr++; |
| 298 } while (AddIntersectTs(current, next) && nextPtr != listEnd); | 272 } while (AddIntersectTs(current, next) && nextPtr != listEnd); |
| 299 } while (currentPtr != listEnd); | 273 } while (currentPtr != listEnd); |
| 300 // eat through coincident edges | 274 // eat through coincident edges |
| 301 | 275 |
| 302 int total = 0; | 276 int total = 0; |
| 303 int index; | 277 int index; |
| 304 for (index = 0; index < contourList.count(); ++index) { | 278 for (index = 0; index < contourList.count(); ++index) { |
| 305 total += contourList[index]->segments().count(); | 279 total += contourList[index]->segments().count(); |
| 306 } | 280 } |
| 307 HandleCoincidence(&contourList, total); | 281 if (!HandleCoincidence(&contourList, total)) { |
| 282 return false; |
| 283 } |
| 308 // construct closed contours | 284 // construct closed contours |
| 309 SkPathWriter wrapper(*result); | 285 SkPathWriter wrapper(*result); |
| 310 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); | 286 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); |
| 311 { // if some edges could not be resolved, assemble remaining fragments | 287 { // if some edges could not be resolved, assemble remaining fragments |
| 312 SkPath temp; | 288 SkPath temp; |
| 313 temp.setFillType(fillType); | 289 temp.setFillType(fillType); |
| 314 SkPathWriter assembled(temp); | 290 SkPathWriter assembled(temp); |
| 315 Assemble(wrapper, &assembled); | 291 Assemble(wrapper, &assembled); |
| 316 *result = *assembled.nativePath(); | 292 *result = *assembled.nativePath(); |
| 317 result->setFillType(fillType); | 293 result->setFillType(fillType); |
| 318 } | 294 } |
| 319 return true; | 295 return true; |
| 320 } | 296 } |
| OLD | NEW |